Now, this is obviously only a humble start, so I would like to ask the community (yes, you!) to pitch in and help grow (and correct) this list of useful principles, so that, in time, it may actually become something used by folks around the web to better their coding practices. C'mon, this will be fun, fun, fun! :D
I. System operations on data, memory or file descriptors
- Use variable-length-arrays or alloca() as much as possible instead of malloc() and friends. This kind of allocation is much faster and is allocated on the current function's stack instead of the heap, so the allocated memory is automatically released when the containing function returns
.
[see http://en.wikipedia.org/wiki/Variable-length_array]
[see http://www.gnu.org/s/libc/manual/html_node/Advantages-of-Alloca.html] - Limit kernel syscalls to an absolute minimum. All operations on file handles (including stdin, stdout and stderr) are translated (at some point) into kernel syscalls! The same goes for malloc()/free() and many others. To this end you may consider reading the following points...
- Use mmap()/munmap() and friends whenever possible to dramatically reduce the costs of highly fragmented file i/o operations and/or memory allocations
;
[see http://en.wikipedia.org/wiki/Memory-mapped_file] - Use readv()/writev() and friends whenever possible instead of multiple read()/write() calls to make use of scatter/gather file operations, enabling you to combine multiple read or write operations in a single kernel syscall;
[see http://en.wikipedia.org/wiki/Vectored_I/O] - Use splice()/sendfile() to replace malloc()/read()/write() when copying data between file descriptors. The splice()/sendfile() calls are able to copy a segment of a given input file to an output file or internet socket just like a read()/write() instruction pair would (using a memory buffer pre-allocated with malloc()). However, splice()/sendfile() operate entirely inside the kernel, thus many syscalls are saved and no pre-allocated buffer is needed the whole copy yielding much higher performance.
II. Source generation, preprocessing, compilation
- Avoid passing expressions or function calls as parameters to macros. The macros will simply get expanded and the expression or function call that was given as a parameter will be executed at runtime in all places where they were expanded by the macro definition; this creates a lot of useless work and opens the possibility for undefined behaviour since an expression or function will be executed multiple times rather than only once as intended.
[cc_c]// Example
#define MAX(a, b) ((a) > (b) ? (a) : (b)) // the macro
int level = MAX(get_level(), 10); // bad usage
int current_level = get_level(); // good usage
int level = MAX(current_level, 10); // ...
[/cc_c] - Surround macro parameters with parantheses. This prevents syntax errors when expanding expression parameters.
- Analyze the preprocessed code. Many times your macros can expand to unexpectedly large pieces of code making the final executable much larger; analyzing the preprocessed code cand enable you to translate such macros into function calls that get executed at run-time instead of expanded at compile-time.
[cc_bash]
# GCC: preprocess only
$ gcc -E source.c > source.txt
[/cc_bash] This optimization can make the final executable much smaller and faster to load (and sometimes even execute) into the system memory (ergo inlining code is *not* always a better choice)!
III. Miscellaneous
- Use environment variables or program parameters instead of configuration files whenever possible. Having configuration files, while attractive, is costly in many cases. Your program must have additional code to load and parse the configurations in memory and it also has to access the disk to read the file(s) on every run. Using parameters or environment variables avoids all these problems elegantly while still allowing you to pass various settings to the program. If you are writing a performance-critical program, that has to be small and quick to load in memory, this may save you a lot of unneeded bloat.
That's it for now!
And, don't be a scrooge! Tell me what you think.
Enjoy! :D
Niciun comentariu:
Trimiteți un comentariu