/* * cyg-profile.c - CygProfiler runtime functions. * * Michal Ludvig * http://www.logix.cz/michal/devel * * cyg-profile.c * - Compile your program with -finstrument-functions and link * together with this code. * - Logging is enabled as soon as your program calls * cygprofile_enable() and disabled with cygprofile_disable(). * - Before logging was enabled you can change the name * of a logfile by calling cygprofile_setfilename(). */ /* Hint: -finstrument-functions, no_instrument_function */ #include #include #include #include #include "cyg-profile.h" #define FN_SIZE 100 #define FN_DEFAULT "cyglog.%d" /* Private variables. */ static int level=0; static FILE *logfile=NULL; static int cyg_profile_enabled=0; static char cyg_profile_filename[FN_SIZE+1]; #ifdef __cplusplus extern "C" { #endif /* Static functions. */ static FILE *openlogfile (const char *filename) __attribute__ ((no_instrument_function)); static void closelogfile (void) __attribute__ ((no_instrument_function)); /* Note that these are linked internally by the compiler. * Don't call them directly! */ void __cyg_profile_func_enter (void *this_fn, void *call_site) __attribute__ ((no_instrument_function)); void __cyg_profile_func_exit (void *this_fn, void *call_site) __attribute__ ((no_instrument_function)); #ifdef __cplusplus }; #endif void __cyg_profile_func_enter (void *this_fn, void *call_site) { if(cyg_profile_enabled) if (logfile || openlogfile(cyg_profile_filename)) fprintf(logfile, "+ %d %p %p\n", level++, this_fn, call_site); } void __cyg_profile_func_exit (void *this_fn, void *call_site) { if(cyg_profile_enabled) if (logfile || openlogfile(cyg_profile_filename)) fprintf(logfile, "- %d %p %p\n", level--, this_fn, call_site); } void cygprofile_enable (void) { if (!cyg_profile_filename[0]) cygprofile_setfilename (FN_DEFAULT); if (!openlogfile (cyg_profile_filename)) return; cyg_profile_enabled = 1; } void cygprofile_disable (void) { cyg_profile_enabled = 0; } int cygprofile_isenabled (void) { return cyg_profile_enabled; } int cygprofile_setfilename (const char *filename) { char *ptr; if (cygprofile_isenabled ()) return -1; if (strlen (filename) > FN_SIZE) return -2; ptr = strstr (filename, "%d"); if (ptr) { size_t len; len = ptr - filename; snprintf (cyg_profile_filename, len+1, "%s", filename); snprintf (&cyg_profile_filename[len], FN_SIZE - len, "%d", getpid ()); len = strlen (cyg_profile_filename); snprintf (&cyg_profile_filename[len], FN_SIZE - len, "%s", ptr + 2); } else snprintf (cyg_profile_filename, FN_SIZE, "%s", filename); if (logfile) closelogfile (); return 0; } char * cygprofile_getfilename (void) { if (!cyg_profile_filename[0]) cygprofile_setfilename (FN_DEFAULT); return cyg_profile_filename; } static FILE * openlogfile (const char *filename) { static int complained = 0; FILE *file; if (complained) return NULL; if (logfile) return logfile; file = fopen(filename, "w"); if (!file) { fprintf (stderr, "WARNING: Can't open logfile '%s': %s\n", filename, strerror (errno)); complained = 1; return NULL; } setlinebuf (file); logfile = file; return file; } static void closelogfile (void) { if (logfile) fclose (logfile); }