|
As demosceners know, creating a 64kb demo is a triky thing, that requieres some special settings for compiling the code, but most importantly clever designing of the code. Some people thinkg a 64 kb is a small project. Ideed, it's not a big project, but it's not necessarily just 50 files code. Good design requieres good modularity. For 195/95/256 intro we used a workspace of 9 projects, not taking the experimental .net tool into account. Complete project is made of arrounf 600 source code files made of 724 thousand lines (5% of comments). Obviously, not all that code is finally going into the final executable. The final executable is compiled from 137 source files, 30 thousand code lines, 120 thousand data lines, 2% comments. The depth of the file structure is about 3 to 4 (only the first level is opened in the picture below).
| ||||||||||||||||||||
| ||||||||||||||||||||
|
Many people doesn't use the first optimization, /QIfist, mainly because it's not documented very well. If not used, the C compiler will insert a function call to _ftol() each time the C code makes a conversion from floating point to integer. That function is responsible for ensuring the correct conversion as defined by the IEEE floating point standard. That is not only a slow process, but also makes your code dependant on the libc. So many people creates his own _ftol() function. Actually, Paradise was using that approach. But later we discovered that with this compiling option, the function call is not generated at all. Thus, code is saved, and more importantly, speed is gained. This is a very nice trick, specially for those 4k intros made in C/C++. Second non obvious optimization, is to change the default call convention (__cdecl) so that parameters are not passed to the functions thru the stack, but thru registers when possible. This, again, makes the code faster, and more importantly, smaller. In 195/95/256, we saved up to 2 kilobytes with this trick. Third optimization. If a programm is well design, there is no need exception handling. Yes. Exception handling is just a workarround for people that incorrecly uses C++ and allocates resources in class constructors (allocations should be done in create() methods, and leave the constructors for their original purpose - initialize class members). So, we discard the exception handling, and let's use correctly defined interfaces to track the possible execution errors. The fourth option, use of instrincts, allows the compiler to insert a cpu instruction in the code when possible. If not used, a call to sqrtf() in the C code will generate a call, while with this option the assembly instruction is generated instead. This way, we save writing ourselfs (in assembler) all these functsions: sinf(), cosf(), fabsf(), memset(), memcpy() and many others. Still, a few functions -as fmodf()- will have to be done by hand. Again, if the code is deterministic and well design, no stack checks are needed. So use the /Gs option to skip innecesary code. The rest are normal compiler optimizations. But, there is something you can still do in the C code to reduce the code size: use allways the f subscript for the floaring point constants, otherwise a double will be stored in the executable, and a innecesary conversion will occur. As the size of a double is two times the size of a float, lot of space can be wasted if not carrefully adding the f to all the constants. Normally, if you follow the rule, you should be able to parse all the assembly listing code and find zero QWORDs in the code. The remaining tricks to keep the executable small are just related to the way programming is done, algorithms are design, code is reutilzed and data-layout. But please, never discard checking for errors as a way to reduce the size of your code, at least not in a 64 kb unless you are really in the limit (say, 200 bytes away from the 64kb limit, and dead-line in ten minutes). |