From 8870040156910ebc470e9b15bb1bb6eebdc8e386 Mon Sep 17 00:00:00 2001 From: Cody Boone Ferguson <53008573+xexyl@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:00:06 -0700 Subject: [PATCH] 1996 fixes and updates Update the README.md files - at least with those not in a previous commit. The updates mostly include formatting (make them markdown) but probably also typos here and there. More probably has to be done with these files. The 1996/august/.gitignore was updated as well with a file that is generated by one of the suggested commands. --- 1996/august/.gitignore | 1 + 1996/august/README.md | 173 ++++++++++++++++---------------- 1996/dalbec/README.md | 2 +- 1996/eldby/README.md | 4 + 1996/huffman/README.md | 3 + 1996/jonth/README.md | 12 +-- 1996/rcm/README.md | 58 +++++------ 1996/schweikh2/README.md | 184 ++++++++++++++++++---------------- 1996/schweikh3/README.md | 210 +++++++++++++++++++-------------------- 9 files changed, 333 insertions(+), 314 deletions(-) diff --git a/1996/august/.gitignore b/1996/august/.gitignore index 4ebc5174f..9ea775773 100644 --- a/1996/august/.gitignore +++ b/1996/august/.gitignore @@ -1,2 +1,3 @@ august august.oc +test.oo diff --git a/1996/august/README.md b/1996/august/README.md index 9e8347049..74ddcf5e1 100644 --- a/1996/august/README.md +++ b/1996/august/README.md @@ -10,7 +10,7 @@ make all -### To run +## To run: cat august.c test.oc | ./august > test.oo ./august < test.oo @@ -19,158 +19,159 @@ If the above cat line does not execute in a very short amount of time, then you may need to fix your compiler or use gcc. -## Judges' comments +## Try: - Try: cat august.c fac.oc | ./august > fac.oo ./august < fac.oo - Or try: cat august.c fac.oc | ./august | ./august - And try: cat august.c parse.oc | ./august > parse.oo cat parse.oo fac.oc | ./august | ./august - This entry can feed on itself. If you C preprocess the source, - you compile the interpreter: + +## Judges' comments: + +This entry can feed on itself. If you C preprocess the source, +you compile the interpreter: make august.oc - We can now compile the interpreter as follows: +We can now compile the interpreter as follows: cat august.c august.oc | ./august > august.oo - and use the compiled interpreter to execute some previously - compiled code: +and use the compiled interpreter to execute some previously +compiled code: cat august.oo test.oo | ./august - And we can have the compiled interpreter interpret itself which - inturn compiles the test program: +And we can have the compiled interpreter interpret itself which +in turn compiles the test program: cat august.oo august.oo fac.oo | ./august - And if you have lots of spare time, you can recurse one level deeper: +And if you have lots of spare time, you can recurse one level deeper: cat august.oo august.oo august.oo fac.oo | ./august - We (the judges) recommend that you spend some time studying this - entry as it surely will make the 'best of the IOCCC' list. It was - very well received by those who attended the IOCCC BOF. +We (the judges) recommend that you spend some time studying this +entry as it surely will make the 'best of the IOCCC' list. It was +very well received by those who attended the IOCCC BOF. ## Author's comments - This program is a bytecode interpreter. This fact is not - particularly obfuscated; any experienced C programmer can see that - in about a minute. +This program is a bytecode interpreter. This fact is not +particularly obfuscated; any experienced C programmer can see that +in about a minute. - The interpreter reads the bytecode from the standard input. What - remains of the standard input after this is left as standard input for - the interpreted program. +The interpreter reads the bytecode from the standard input. What +remains of the standard input after this is left as standard input for +the interpreted program. - Having an interpreter but no code isn't any fun. But within a comment - in the beginning of the interpreter is a sequence of bytes that is - code that the interpreter understands. It is in fact the code for a - compiler that compiles from OC (Obfuscated C, a subset of C) into the - byte code that the interpreter understands. +Having an interpreter but no code isn't any fun. But within a comment +in the beginning of the interpreter is a sequence of bytes that is +code that the interpreter understands. It is in fact the code for a +compiler that compiles from OC (Obfuscated C, a subset of C) into the +byte code that the interpreter understands. - The language the compiler understands is a subset of C (the grammar - is in grammar.small) with the functions getchar() and putchar() - available. The subset has the types `int', `char', and pointers to - those (it has function pointers too, but not with the proper - syntax). Arrays can only be global. There is a rather limited set - of operators, and control constructs. +The language the compiler understands is a subset of C (the grammar +is in grammar.small) with the functions getchar() and putchar() +available. The subset has the types `int', `char', and pointers to +those (it has function pointers too, but not with the proper +syntax). Arrays can only be global. There is a rather limited set +of operators, and control constructs. - The compiler has absolutely no error checking, so things - can go wrong. But this is what seasoned C progammers are used to. +The compiler has absolutely no error checking, so things +can go wrong. But this is what seasoned C programmers are used to. - Assume that the interpreter has been compiled (source in prog.c and - binary in prog) and that we have this in a file named test.oc: +Assume that the interpreter has been compiled (source in prog.c and +binary in prog) and that we have this in a file named test.oc: main() { putchar('!'); putchar('\n'); exit(0); } - We can then compile by +We can then compile by cat august.c test.oc | ./august > test.oo - And run the compiled program by +And run the compiled program by ./august < test.oo - Or even simpler: +Or even simpler: cat august.c test.oc | ./august | ./august - A larger example is included fac.oc. +A larger example is included fac.oc. - The compiler for OC is naturally written in OC (where did you think - the byte code came from?). It is in the file parse.oc. +The compiler for OC is naturally written in OC (where did you think +the byte code came from?). It is in the file parse.oc. - Hmm... So now we have an interpreter written in OC and a compiler - for OC, can we compile the interpreter? Yes, we can! The OC - compiler does not have a preprocessor (hey, what do you expect from - a program that is this small), so we need to use an external one. - To preprocess august.c use the command from the build file, but add - the -E flag and change 60000 to 40000, i.e.: +Hmm... So now we have an interpreter written in OC and a compiler +for OC, can we compile the interpreter? Yes, we can! The OC +compiler does not have a preprocessor (hey, what do you expect from +a program that is this small), so we need to use an external one. +To preprocess august.c use the command from the build file, but add +the -E flag and change 60000 to 40000, i.e.: cc -E -DZ=40000 .... august.c > prog.oc - If prog.oc contain some junk line starting with a `#' (most likely - it does) then remove it. +If prog.oc contain some junk line starting with a `#' (most likely +it does) then remove it. - OK, we can now compile the interpreter: +OK, we can now compile the interpreter: cat august.c prog.oc | ./august > prog.oo - And we can run it: +And we can run it: cat prog.oo test.oo | ./august - Here we have the interpreter interpreting another interpreter that runs - the program. Did you think that was too fast? Just throw in another - level of interpretation: +Here we have the interpreter interpreting another interpreter that runs +the program. Did you think that was too fast? Just throw in another +level of interpretation: cat prog.oo prog.oo test.oo | ./august - And another... +And another... cat prog.oo prog.oo prog.oo test.oo | ./august - ***** +***** - Fitting the byte code for the compiler into the initial comment - was a challenge. I had to strip the compiler/interpreter of - a lot of functionality to bring down their sizes. The initial - version had a full set of binary operators as well as prefix &. - Given a handful more bytes it would be easy to put them back. +Fitting the byte code for the compiler into the initial comment +was a challenge. I had to strip the compiler/interpreter of +a lot of functionality to bring down their sizes. The initial +version had a full set of binary operators as well as prefix &. +Given a handful more bytes it would be easy to put them back. - Anyway, the bytecode from the compiler is first optimized in - an external optimizer (not supplied here); this brings down the - size of it by about 30%. The remaining code is then LZ-compressed - (roughly) with a sliding window of 255 bytes. The most common - occuring bytes are then encoded using " \n\t;{}" to avoid having - them counted as significant. About 200 bytes of the interpreter - handles the unpacking of the byte code (this is a lot, but it pays - off). +Anyway, the bytecode from the compiler is first optimized in +an external optimizer (not supplied here); this brings down the +size of it by about 30%. The remaining code is then LZ-compressed +(roughly) with a sliding window of 255 bytes. The most common +occuring bytes are then encoded using " \n\t;{}" to avoid having +them counted as significant. About 200 bytes of the interpreter +handles the unpacking of the byte code (this is a lot, but it pays +off). - Despite all this work I still had to put a lot of code in the - compilation command. This disturbs me. It is possible to compress - the code further with a better entropy coder (e.g. an arithmetic - coder), but decompression then takes up too much code. Maybe this - would be a way to fit it all into the 1536 bytes, but I'm don't have - time to try it. +Despite all this work I still had to put a lot of code in the +compilation command. This disturbs me. It is possible to compress +the code further with a better entropy coder (e.g. an arithmetic +coder), but decompression then takes up too much code. Maybe this +would be a way to fit it all into the 1536 bytes, but I'm don't have +time to try it. - ***** +***** - Execution starts at main(). Nothing can be used before it is - defined. getchar() and putchar() are predefined functions. +Execution starts at main(). Nothing can be used before it is +defined. getchar() and putchar() are predefined functions. - The following is a description of the OC grammar: +The following is a description of the OC grammar: - OC grammar - ========== - Terminals are in quotes, () is used for bracketing. +OC grammar +========== + +Terminals are in quotes, () is used for bracketing. program: decl* @@ -228,6 +229,6 @@ stars: "*"* - ***** +***** - Well, that is enough ranting for now. +Well, that is enough ranting for now. diff --git a/1996/dalbec/README.md b/1996/dalbec/README.md index ccae4e54d..7807b0b9c 100644 --- a/1996/dalbec/README.md +++ b/1996/dalbec/README.md @@ -51,7 +51,7 @@ We (the judges) recommend that you take the time needed to understand how this program works. The source is small enough to make the effort reasonable, and complex enough to make it interesting. -## Author's comments +## Author's comments: This program assumes that your terminal wraps lines automatically. If this is not the case, you may need to change the space in the diff --git a/1996/eldby/README.md b/1996/eldby/README.md index 92f339424..57c666a29 100644 --- a/1996/eldby/README.md +++ b/1996/eldby/README.md @@ -14,6 +14,10 @@ ./eldby +WARNING: on modern systems this is very fast and could be a problem for those +susceptible to photosensitivity. Please try this one with caution if this +applies to you! The same goes for people who can be overstimulated. + ## Judges' comments We were impressed by the author's ability to render spheres in 3D diff --git a/1996/huffman/README.md b/1996/huffman/README.md index fac0a0a82..ff05873b8 100644 --- a/1996/huffman/README.md +++ b/1996/huffman/README.md @@ -17,6 +17,9 @@ echo 'Huffman Decoding' | ./huffman +NOTE: this program uses `gets()` so you will likely get a warning when compiling +and/or running on modern systems. + ## Try: echo 'seeing or feeling is believing' | ./huffman diff --git a/1996/jonth/README.md b/1996/jonth/README.md index 2e9592ec9..78a9f60b6 100644 --- a/1996/jonth/README.md +++ b/1996/jonth/README.md @@ -12,7 +12,7 @@ make all -### To run +### To run: ./jonth @@ -20,18 +20,18 @@ ./jonth host1:0 host2:0 -## Judges' comments +## Judges' comments: - For extra credit, figure out how you can cheat by taking over - a square already occupied by an opponent. +For extra credit, figure out how you can cheat by taking over +a square already occupied by an opponent. -## Author's comments +## Author's comments: This is multi-user tic-tac-toe for X Windows. You may give one or two X displays as arguments to this game. -Known bugs: +### Known bugs: Sometimes on Solaris X gets confused and this program core dumps, solution: give two display arguments (prog host:0 host:0) diff --git a/1996/rcm/README.md b/1996/rcm/README.md index 8551e1504..f98aa32c1 100644 --- a/1996/rcm/README.md +++ b/1996/rcm/README.md @@ -20,50 +20,50 @@ For more information try: ./rcm < rfc1952.gz -## Judges' comments +## Judges' comments: For a good noop try: gzip -c < rcm.c | ./rcm -## Author's comments +## Author's comments: - Except for some silly requirements regarding input validation, CRC - checking, and similar unimportant fluff, this program is a fully - compliant RFC1951/RFC1952 (GNU Gzip) file uncompressor. Feed it a - "gzip" compressed file on standard input, and it will write the fully - uncompressed original file to standard output. +Except for some silly requirements regarding input validation, CRC +checking, and similar unimportant fluff, this program is a fully +compliant RFC1951/RFC1952 (GNU Gzip) file uncompressor. Feed it a +"gzip" compressed file on standard input, and it will write the fully +uncompressed original file to standard output. - ObJustifications for this entry: +### ObJustifications for this entry: - The Design Trade-off Argument +#### The Design Trade-off Argument: - "The 184 characters worth of defines in the build file have been - carefully offset by 184 redundant and unecessary '{', '}', and ';' - characters in the source file." +"The 184 characters worth of defines in the build file have been +carefully offset by 184 redundant and unnecessary '{', '}', and ';' +characters in the source file." - The Design Review Argument +#### The Design Review Argument: - "Using only 216 characters out of a maximum of 256, the build file - meets and actually exceeds specification." +"Using only 216 characters out of a maximum of 256, the build file +meets and actually exceeds specification." - The Program Metrics Argument +#### The Program Metrics Argument: - "The program source is less than 3,100 characters in length and - uncompresses file `emacs-19.34b.tar.gz' in about 130 seconds on - my HP 9000/735. The now obsolete source file `inflate.c' from - the GNU gzip source tree is 31,613 characters in length and - uncompresses the emacs distribution file in slightly under 25 - seconds. Thus: +"The program source is less than 3,100 characters in length and +uncompresses file `emacs-19.34b.tar.gz' in about 130 seconds on +my HP 9000/735. The now obsolete source file `inflate.c' from +the GNU gzip source tree is 31,613 characters in length and +uncompresses the emacs distribution file in slightly under 25 +seconds. Thus: 3100 / 130 = 23.85 -vs- 31613 / 25 = 1264.52 - which represents a better than 530% improvement in the ratio of - source file size to execution time." +which represents a better than 530% improvement in the ratio of +source file size to execution time." - The Whining Programmer's Argument +#### The Whining Programmer's Argument: - "The inflate algorithm requires that over 400 characters worth - of constants and tables be defined. Which means the program - itself had to be squeezed down to about 1,100 IOCCC countable - bytes." +"The inflate algorithm requires that over 400 characters worth +of constants and tables be defined. Which means the program +itself had to be squeezed down to about 1,100 IOCCC countable +bytes." diff --git a/1996/schweikh2/README.md b/1996/schweikh2/README.md index a318bfc6c..5bfef34f5 100644 --- a/1996/schweikh2/README.md +++ b/1996/schweikh2/README.md @@ -12,119 +12,131 @@ make all -### To run +## To run: ./schweikh2 -## Judges' comments +The program accepts up to 4 parameters: - Also try: +0. The number of operators in the expression [default: 9] + +1. The value of the first operand [default: 1] + +2. The (possibly negative) increment to the next operand [default: 1] + +3. The goal value or 0/0 [default: 42] + + +## Try: ./schweikh2 15 1 0 0/0 - The program accepts up to 4 parameters: +What happens if you pass only three parameters like the below? - 1) The number of operators in the expression [default: 9] + ./schweikh2 15 1 0 - 2) The value of the first operand [default: 1] +## Judges' comments: - 3) The (possibly negative) increment to the next operand [default: 1] - 4) The goal value or 0/0 [default: 42] - - The original program, with only slight obfuscations, may be found - in hunni.c. The perl script, obfuscates it appropriately: +The original program, with only slight obfuscations, may be found +in `hunni.c`. The perl script, obfuscates it appropriately: perl ./hunni.pl < hunni.c - This entry was another crowd pleaser at the IOCCC BOF. +This entry was another crowd pleaser at the IOCCC BOF. -## Author's comments +## Author's comments: - Note: the source must be viewed with tabstop 8. To appreciate the - beauty have your eyes half closed. +Note: the source must be viewed with tabstop 8. To appreciate the +beauty have your eyes half closed. - Why I think this program is obfuscated: +### Why I think this program is obfuscated: - C is a free format language. It is therefore a question of style how - variables, operators, declarations, functions and syntactic elements - like braces and parentheses are grouped together. As a rule of thumb, - I put spaces around operators, after opening braces and before closing - braces. I have generalized this rule by putting whitespace after *any* - non-white space character (with the exception of preprocessor directives). - There are no recognizable keywords anymore. There are no recognizable - string literals any more. The main function is invisible. All operators - longer than one character have gone. They have been replaced by macro - calls with quite a number of arguments. The keys are the token pasting - and stringizing macros e and O. The "arcane rules of token pasting" - [K&R2] are used up to three levels, H(O,r)R(O,r)! which is needed to make - one 8-character token from 8 characters ('unsigned'). BTW, C has no 9 or - more character reserved words, so a fourth level is only required if - you intend to generate object names from 9 or more components. The final - round even swaps the tokens, so all keywords must be spelled backwards - (sort of, can you spot printf in the P macro?). +C is a free format language. It is therefore a question of style how +variables, operators, declarations, functions and syntactic elements +like braces and parentheses are grouped together. As a rule of thumb, +I put spaces around operators, after opening braces and before closing +braces. I have generalized this rule by putting whitespace after *any* +non-white space character (with the exception of preprocessor directives). +There are no recognizable keywords anymore. There are no recognizable +string literals any more. The main function is invisible. All operators +longer than one character have gone. They have been replaced by macro +calls with quite a number of arguments. The keys are the token pasting +and stringizing macros e and O. The "arcane rules of token pasting" +[K&R2] are used up to three levels, `H(O,r)R(O,r)` (!) which is needed to make +one 8-character token from 8 characters ('unsigned'). BTW, C has no 9 or +more character reserved words, so a fourth level is only required if +you intend to generate object names from 9 or more components. The final +round even swaps the tokens, so all keywords must be spelled backwards +(sort of, can you spot printf in the P macro?). - Try to indent the source. The unbalanced parentheses confuse Solaris' - indent to the max (although the result does compile): +Try to indent the source. The unbalanced parentheses confuse Solaris' +indent to the max (although the result does compile): - Looking at the indented source is even *less* fun, because the nice - diamond pattern has been replaced by something that looks like, uhm, - modem noise. +Looking at the indented source is even *less* fun, because the nice +diamond pattern has been replaced by something that looks like, uhm, +modem noise. - Lint the source. It's clean. How obfuscated... +Lint the source. It's clean. How obfuscated... - What's the exit status? The program exits with J - 1 where J is the - return value from several non-void functions (needed to shut up - lint). The last assignment is J = printf ("%c", 10); so the exit - status is 0 unless the last printf failed, which is even a *useful* - status. A further obfuscation is the use of 10 instead of '\n'. - '\n' can not be constructed by token pasting, AFAIK. That's why schweikh2 - is likely to produce occasional garbage on non-ASCII execution character - set systems. +What's the exit status? The program exits with J - 1 where J is the +return value from several non-void functions (needed to shut up +lint). The last assignment is J = printf ("%c", 10); so the exit +status is 0 unless the last printf failed, which is even a *useful* +status. A further obfuscation is the use of 10 instead of '\n'. +'\n' can not be constructed by token pasting, AFAIK. That's why `schweikh2` +is likely to produce occasional garbage on non-ASCII execution character +set systems. - What this program does: - ----------------------- - The program is an expression evaluator for a limited class of - expressions. Known operators are + - * /, operands are real numbers - (integers or fractions). The operands are restricted in that they must - differ by a constant value, for example 1 + 2 * 3 / 4 - 5. For any - combination of operators the expression is evaluated and compared to a - goal value. If they compare equal the expression is printed. If the goal - value is specified as 0/0 all expressions and results are printed. For - any fraction, the numerator and denominator are divided by their - greatest common divisor. +What this program does: +----------------------- - The program accepts up to 4 parameters: - 1) The number of operators in the expression [default: 9] - 2) The value of the first operand [1] - 3) The (possibly negative) increment to the next operand [1] - 4) The goal value or 0/0 [42] +The program is an expression evaluator for a limited class of +expressions. Known operators are + - * /, operands are real numbers +(integers or fractions). The operands are restricted in that they must +differ by a constant value, for example 1 + 2 * 3 / 4 - 5. For any +combination of operators the expression is evaluated and compared to a +goal value. If they compare equal the expression is printed. If the goal +value is specified as 0/0 all expressions and results are printed. For +any fraction, the numerator and denominator are divided by their +greatest common divisor. - On ANSI/ISO C conformant systems (where long is at least 32 bits) - overflow will occur in the default case (first operand 1, increment 1) - only for more than 11 operators. Because a bit mask is used that needs - twice the number of operands in bits (plus a sentinel value) on those - systems the first parameter must not exceed 15. +The program accepts up to 4 parameters: + 1) The number of operators in the expression [default: 9] + 2) The value of the first operand [1] + 3) The (possibly negative) increment to the next operand [1] + 4) The goal value or 0/0 [42] - If long is at least 64 bits overflow will occur for more than 19 - operators but you will probably wait quite some time for every of the - 4^19 = 274,877,906,944 combinations to be evaluated... While I'm at it, - on a 50 MHz sparc, 4^11 expressions are evaluated in about 3 cpu - minutes (gcc -O3). +On ANSI/ISO C conformant systems (where long is at least 32 bits) +overflow will occur in the default case (first operand 1, increment 1) +only for more than 11 operators. Because a bit mask is used that needs +twice the number of operands in bits (plus a sentinel value) on those +systems the first parameter must not exceed 15. - Sample arguments: - ----------------- - $ schweikh2 6 - $ schweikh2 7 0 - $ schweikh2 7 7 0 - $ schweikh2 8 9 -1 -67/21 - $ schweikh2 8 2 2/5 -98/25 - $ schweikh2 2 1/0 1 1/0 +If long is at least 64 bits overflow will occur for more than 19 +operators but you will probably wait quite some time for every of the +4^19 = 274,877,906,944 combinations to be evaluated... While I'm at it, +on a 50 MHz sparc, 4^11 expressions are evaluated in about 3 cpu +minutes (gcc -O3). + +Sample arguments: +----------------- + + $ ./schweikh2 6 + $ ./schweikh2 7 0 + $ ./schweikh2 7 7 0 + $ ./schweikh2 8 9 -1 -67/21 + $ ./schweikh2 8 2 2/5 -98/25 + $ ./schweikh2 2 1/0 1 1/0 + +Miscellaneous +------------- + +The diamond pattern can be continued without a break. +For a nice printout try this on your Bourne compatible shell: + + + % while :; do grep -v '#' schweikh2.c; done - Miscellaneous - ------------- - The diamond pattern can be continued without a break. - For a nice printout try this on your Bourne compatible shell - % while :; do grep -v '#' schweikh2.c; done diff --git a/1996/schweikh3/README.md b/1996/schweikh3/README.md index 401b01be1..634c564bd 100644 --- a/1996/schweikh3/README.md +++ b/1996/schweikh3/README.md @@ -12,57 +12,58 @@ make all -### To run +## To run: - WARNING: Do not run this program without reading this text down to the end. - It may render your system unusable for a limited amount of time - or force you to reboot using the Big Red Button! This is not a joke. - You have been warned. - - ./schweikh3 - -## Judges' comments - - The source fails to compile on compilers that recognize the inline - keyword by default. For gcc, you may need to use -ansi. - - See the file, schweikh3.info for example output from various systems. - - But still it is a useful utility. To use try: +**WARNING**: Do not run this program without reading this text down to the end! +It may render your system unusable for a limited amount of time +or force you to reboot using the Big Red Button! This is **NOT** a joke. +You have been warned. ./schweikh3 - and thanks for the virtual memories! :-) - NOTE: On some systems such as SunOS, one may need to compile with: +## Judges' comments: - ${CC} ${CFLAGS} \ - -I. -D_POSIX_SOURCE '-Ddifftime(a,b)=(double)(b-a)' \ - schweikh3.c -o schweikh3 +The source fails to compile on compilers that recognize the inline +keyword by default. For gcc, you may need to use -ansi. -## Author's comments +See the file, `schweikh3.info` for example output from various systems. - Why I think my entry is obfuscated - ---------------------------------- +But still it is a useful utility. To use try: - There are some layout obfuscations that hinder readability, like - some (but not all) one character tokens in column 1. Includes, - defines and declarations of data and functions appear intermixed. - iso646.h is even included in the middle of an expression, how - disgusting. Besides, requiring iso646.h will render the program - uncompilable on many systems that have not yet incorporated - Amendment One to The Standard. If you, dear reader, suffer from - this disease, just read iso646.h. + ./schweikh3 - There are no `if' statements. They have been replaced by - "switch () case 1:" or "switch () case 0:" etc. At least one - switch has a declaration after the opening brace, booh! - Identifiers are named after random programming languages, Basic, - Cobol, F77, awk etc. +and thanks for the virtual memories! :-) - You have to select maximum ANSI C conformance of your - compiler. The source fails to compile under a C++ compiler due to - the `new' identifier which is a C++ reserved word: +NOTE: On some systems such as SunOS, one may need to compile with: + + ${CC} ${CFLAGS} \ + -I. -D_POSIX_SOURCE '-Ddifftime(a,b)=(double)(b-a)' \ + schweikh3.c -o schweikh3 + +## Author's comments: + +Why I think my entry is obfuscated +---------------------------------- + +There are some layout obfuscations that hinder readability, like +some (but not all) one character tokens in column 1. Includes, +defines and declarations of data and functions appear intermixed. +iso646.h is even included in the middle of an expression, how +disgusting. Besides, requiring iso646.h will render the program +uncompilable on many systems that have not yet incorporated +Amendment One to The Standard. If you, dear reader, suffer from +this disease, just read iso646.h. + +There are no `if' statements. They have been replaced by +"switch () case 1:" or "switch () case 0:" etc. At least one +switch has a declaration after the opening brace, booh! +Identifiers are named after random programming languages, Basic, +Cobol, F77, awk etc. + +You have to select maximum ANSI C conformance of your +compiler. The source fails to compile under a C++ compiler due to +the `new' identifier which is a C++ reserved word: $ g++ prog.c prog.c:9: parse error before `new' @@ -73,8 +74,8 @@ [...] prog.c:91: confused by earlier errors, bailing out - The source fails to compile on compilers that recognize the inline - keyword by default, e.g. gcc: +The source fails to compile on compilers that recognize the inline +keyword by default, e.g. gcc: $ gcc prog.c prog.c:46: parse error before `void' @@ -83,84 +84,81 @@ prog.c: At top level: prog.c:97: parse error before `void' - The -ansi option to gcc fixes this. +The `-ansi` option to gcc fixes this. - The source fails to compile on obsolete systems with obsolete - memory models due to the identifier `far' (to be honest: this is - untested :-). +The source fails to compile on obsolete systems with obsolete +memory models due to the identifier `far' (to be honest: this is +untested :-). - Does your indent cope with backslash/newline pairs inbetween - keywords like in "re\turn"? Solaris' indent inserts spaces - and thereby renders the source uncompilable... +Does your indent cope with backslash/newline pairs inbetween +keywords like in "re\turn"? Solaris' indent inserts spaces +and thereby renders the source uncompilable... - The indented source will exhibit different semantics when indenting - changes the number of lines (due to using the __LINE__ macro in an - expression). +The indented source will exhibit different semantics when indenting +changes the number of lines (due to using the __LINE__ macro in an +expression). - And what about sizeof __TIME__? This one's for the philosophers - and physicists among us programmers. What is it? sizeof (char *) -- no. - Strlen ("hh:mm:ss")? -- no. It's the same as sizeof __DATE__ - - sizeof "no" :-) +And what about sizeof __TIME__? This one's for the philosophers +and physicists among us programmers. What is it? sizeof (char *)? -- no. +strlen ("hh:mm:ss")? -- no. It's the same as sizeof __DATE__ - +sizeof "no" :-) - The program is POSIX conformant and lints without warning under - Solaris' Sunpro lint. Allocated memory is correctly freed on all - possible execution paths. +The program is POSIX conformant and lints without warning under +Solaris' Sunpro lint. Allocated memory is correctly freed on all +possible execution paths. - What this program does - ---------------------- +What this program does: +---------------------- - This program tests your operating system's allocation honesty. It - forks a child that will allocate as much as possible with byte - granularity and then write to every 1024th byte, at the same time - writing a status report on stdout. This way each page of the - allocated virtual memory will eventually be referenced. Without - any arguments, malloc() will be used to allocate memory. If the - first arg starts with c, calloc() will be used instead. +This program tests your operating system's allocation honesty. It +forks a child that will allocate as much as possible with byte +granularity and then write to every 1024th byte, at the same time +writing a status report on stdout. This way each page of the +allocated virtual memory will eventually be referenced. Without +any arguments, malloc() will be used to allocate memory. If the +first arg starts with c, calloc() will be used instead. - I distinguish three different behaviours: +I distinguish three different behaviours: - 1) OS without memory overcommit: - malloc does not lie -- you can use all memory the OS granted to you. +1. OS without memory overcommit: malloc does not lie -- you can use all memory +the OS granted to you. - 2) OS with memory overcommit: - malloc lies -- any program may get killed at random when the - OS can not acquire a free page. +2. OS with memory overcommit: malloc lies -- any program may get killed at +random when the OS can not acquire a free page. - 3) OS with pseudo memory overcommit: - malloc lies -- The OS puts processes to sleep for which it can - not acquire a free page. Because other processes are also - affected this way, the system slows down and quickly becomes - totally unusable (also known as "thrashing"). Because more and - more processes wait for memory returned by other exiting processes - the system eventually enters a deadlock situation and effectively - halts. +3. OS with pseudo memory overcommit: malloc lies -- The OS puts processes to +sleep for which it can not acquire a free page. Because other processes are also +affected this way, the system slows down and quickly becomes totally unusable +(also known as "thrashing"). Because more and more processes wait for memory +returned by other exiting processes the system eventually enters a deadlock +situation and effectively halts. - I had the pleasure and pain to find all three behaviours on the - platforms I use regularly. What follows are the outputs for - Solaris, FreeBSD and Linux. The Linux case is interesting in that - the behaviour changes when calloc is used instead of malloc. - For FreeBSD, the last two lines are not messages stemming from - my program but issued by the syslog daemon. +I had the pleasure and pain to find all three behaviours on the +platforms I use regularly. What follows are the outputs for +Solaris, FreeBSD and Linux. The Linux case is interesting in that +the behaviour changes when calloc is used instead of malloc. +For FreeBSD, the last two lines are not messages stemming from +my program but issued by the syslog daemon. - Implementation remarks - ---------------------- +Implementation remarks +---------------------- - How can we distinguish the three different OS types from the - table above? +How can we distinguish the three different OS types from the +table above? - Obviously, type 1), no overcommit, is easy. +Obviously, type 1), no overcommit, is easy. - For type 2), random kill, we need to fork a child that can be killed - and whose exit status the parent collects and decodes. Here's - where POSIX enters the scene. +For type 2), random kill, we need to fork a child that can be killed +and whose exit status the parent collects and decodes. Here's +where POSIX enters the scene. - Type 3), thrashing, was the hardest part. The first attempt was to - measure the elapsed processor time it takes to write a single byte - (using clock()). If a certain threshold is reached I assume the - system is thrashing. When thrashing, however, the process does not - consume processor time in a noticeable amount any longer and I lose. - So I switched to measuring wall clock time using time(). On the one - system that I observe thrashing (Linux) this works (although the - value returned by time seems to 'hang' sometimes when the OS thrashes. - Exceeding a threshold of 5 seconds may be detected only after half a - minute or so. +Type 3), thrashing, was the hardest part. The first attempt was to +measure the elapsed processor time it takes to write a single byte +(using clock()). If a certain threshold is reached I assume the +system is thrashing. When thrashing, however, the process does not +consume processor time in a noticeable amount any longer and I lose. +So I switched to measuring wall clock time using time(). On the one +system that I observe thrashing (Linux) this works (although the +value returned by time seems to 'hang' sometimes when the OS thrashes. +Exceeding a threshold of 5 seconds may be detected only after half a +minute or so.