I have this C code that implements an algorithm in the context of computer science research. The mentioned code contains many printf
and other functions calls that output formatted information about the state of the algorithm and key values in particular points. This output is very useful/clear from a learning perspective.
I would like to somehow preserve and access this information if desired, but not hurting the performance if I don't want such information.
I thought about some DEBUG
macro definition, and injected a bunch of ifdef
s:
#define DEBUG
...
#ifdef DEBUG
printf("At this point...");
#endif
But this makes the code ugly and difficult to read.
I am using Git, so perhaps some sort of alternate version could be a better approach to access the "learning" or "clean" version of the code.
So my concrete questions are related with practicality and coding conventions:
First, performance isn't a problem until your application doesn't meet actual performance requirements. Then you profile your application, measure it, and find the hotspots.
Then you fix the problems you find.
If you have a global debug level, you can do something like this:
extern volatile atomic unsigned int globalLogLevel;
void logDebugFunc( unsigned int level, const char *function, int line,
const char *filename, const char *format, ... );
#define LOG_DEBUG( level, format, ... ) \
do \
{ \
if ( level >= globalLogLevel ) \
{ \
logDebugFunc( level, __func__, __LINE__,\
__FILE__, format, __VA_ARGS__ ); \
} \
} while ( 0 )
(note that this automatically captures function, file, and line number - that way you know exactly where every debug log entry came from)
You can vary the logging levels, in this example higher numbers for more detailed log entry, lower numbers for rarer, more important log entries such as important events, errors, or warnings.
Then it just becomes how to update/change the globalLogLevel
while the process is running. There are all kinds of options there - you can use a real-time signal to send a new value, or you can redefine globalLogLevel
to something else - a function for a more complex calculation, a pointer into a mmap()
'd file where you can change log level directly.
You can make something like this as complex as you'd like, and with judicious use the performance penalty won't be drastic. The hit from the if
statement might not even be measurable unless you embed it into some super-tight loop that runs a lot.
Even better, you not only don't have to recompile your process to enable logging, you can reset the log level while the process is running.
You'll need something like this to figure out why you get that intermittent bad result from data, but only on one system of eight, and only when the moon is full. Because just about the only way to reliably and quickly solve problems like that is to have the code tell you everything it does.