#include <IgTools/IgProf/src/IgProf.h>
Static Public Member Functions | |
static IgProfTrace * | buffer (int moduleid) |
Return a profile buffer for a profiler in the current thread. | |
static void | debug (const char *format,...) |
Internal printf()-like debugging utility. | |
static bool | disable (bool globally) |
Disable the profiling system, either globally or just in this thread. | |
static void | dump (void) |
Dump out the profiler data: trace tree and live maps. | |
static bool | enable (bool globally) |
Enable the profiling system, either globally or just in this thread. | |
static bool | enabled (bool globally) |
Check if the profiler is currently enabled. | |
static void | exitThread (bool final) |
Finalise a thread. | |
static bool | initialize (int *moduleid, void(*threadinit)(void), bool perthread) |
Initialise the profiler core itself. | |
static void | initThread (void) |
Setup a thread so it can be used in profiling. | |
static bool | isMultiThreaded (void) |
Return true if the process was linked against threading package. | |
static const char * | options (void) |
Get user-provided profiling options. | |
static int | panic (const char *file, int line, const char *func, const char *expr) |
Internal assertion helper routine. |
Implements utilities needed to implement actual profiler modules as well as final dumps.
Definition at line 11 of file IgProf.h.
IgProfTrace * IgProf::buffer | ( | int | moduleid | ) | [static] |
Return a profile buffer for a profiler in the current thread.
It is safe to call this function from any thread and in asynchronous signal handlers at any time. Returns the buffer to use or a null to indicate no data should be gathered in the calling context, for example if the profile core itself has already been destroyed.
Definition at line 315 of file IgProf.cc.
References IgProfTraceAlloc::buf, s_activated, s_bufkey, s_bufs, s_mainthread, and thread.
Referenced by __attribute__(), profileSignalHandler(), and remove().
00316 { 00317 // Check which pool to return. We return the one from s_bufs in 00318 // non-threaded applications and always in the main thread. In 00319 // other threads we return the main thread buffer if a single buffer 00320 // was requested, otherwise a per-thread buffer. 00321 pthread_t thread = pthread_self(); 00322 IgProfTraceAlloc *bufs = s_bufs; 00323 if (! s_activated) 00324 bufs = 0; 00325 else if (thread != s_mainthread && s_bufs[moduleid].perthread) 00326 bufs = (IgProfTraceAlloc *) pthread_getspecific(s_bufkey); 00327 00328 return bufs ? bufs[moduleid].buf : 0; 00329 }
void IgProf::debug | ( | const char * | format, | |
... | ||||
) | [static] |
Internal printf()-like debugging utility.
Produces output if $IGPROF_DEBUGGING environment variable is set to any value.
Definition at line 423 of file IgProf.cc.
References e.
Referenced by IgProfTrace::acquireResource(), IgProfBuffer::allocateRaw(), doexit(), dokill(), dopthread_sigmask(), dosigaction(), dump(), initialize(), initialize(), threadWrapper(), and IgProfExitDump::~IgProfExitDump().
00424 { 00425 static const char *debugging = getenv("IGPROF_DEBUGGING"); 00426 if (debugging) 00427 { 00428 timeval tv; 00429 gettimeofday(&tv, 0); 00430 fprintf(stderr, "*** IgProf(%lu, %.3f): ", 00431 (unsigned long) getpid(), 00432 tv.tv_sec + 1e-6*tv.tv_usec); 00433 00434 va_list args; 00435 va_start(args, format); 00436 vfprintf(stderr, format, args); 00437 va_end(args); 00438 } 00439 }
Disable the profiling system, either globally or just in this thread.
This is safe to call from anywhere. Returns true
if the profiler was enabled before the call.
Definition at line 370 of file IgProf.cc.
References IgProfAtomicDec(), s_enabled, s_flagkey, and s_pthreads.
Referenced by doaccept(), doclose(), dodup(), dodup2(), doexit(), dokill(), doopen(), doopen64(), dopthread_create(), dosocket(), initialize(), initialize(), panic(), and IgProfExitDump::~IgProfExitDump().
00371 { 00372 if (! globally && s_pthreads) 00373 { 00374 IgProfAtomic *flag = (IgProfAtomic *) pthread_getspecific(s_flagkey); 00375 return flag ? (IgProfAtomicDec(flag) >= 0 && s_enabled > 0) : false; 00376 } 00377 else 00378 { 00379 IgProfAtomic newval = IgProfAtomicDec(&s_enabled); 00380 return newval >= 0; 00381 } 00382 }
Dump out the profiler data: trace tree and live maps.
Definition at line 502 of file IgProf.cc.
References debug(), dumpProfile(), info, output(), s_clockres, s_masterbuf, s_outname, and IgProfTrace::stackRoot().
Referenced by dokill(), and IgProfExitDump::~IgProfExitDump().
00503 { 00504 static bool dumping = false; 00505 if (dumping) return; 00506 dumping = true; 00507 00508 FILE *output = (s_outname[0] == '|' 00509 ? (unsetenv("LD_PRELOAD"), popen(s_outname+1, "w")) 00510 : fopen (s_outname, "w+")); 00511 if (! output) 00512 { 00513 IgProf::debug("can't write to output %s: %d\n", s_outname, errno); 00514 dumping = false; 00515 return; 00516 } 00517 00518 IgProfDumpInfo info = { 0, 0, 0, 0 }; 00519 IgProf::debug("dumping state to %s\n", s_outname); 00520 fprintf(output, "P=(ID=%lu N=(%s) T=%f)\n", 00521 (unsigned long) getpid(), program_invocation_name, s_clockres); 00522 dumpProfile(output, s_masterbuf->stackRoot(), info); 00523 fclose(output); 00524 dumping = false; 00525 }
Enable the profiling system, either globally or just in this thread.
This is safe to call from anywhere. Returns true
if the profiler is enabled after the call.
Definition at line 352 of file IgProf.cc.
References IgProfAtomicInc(), s_enabled, s_flagkey, and s_pthreads.
Referenced by doaccept(), doclose(), dodup(), dodup2(), doexit(), dokill(), doopen(), doopen64(), dopthread_create(), dosocket(), initialize(), and initialize().
00353 { 00354 if (! globally && s_pthreads) 00355 { 00356 IgProfAtomic *flag = (IgProfAtomic *) pthread_getspecific(s_flagkey); 00357 return flag ? (IgProfAtomicInc(flag) > 0 && s_enabled > 0) : false; 00358 } 00359 else 00360 { 00361 IgProfAtomic newval = IgProfAtomicInc(&s_enabled); 00362 return newval > 0; 00363 } 00364 }
Check if the profiler is currently enabled.
This function should be called by asynchronous signal handlers to check whether they should record profile data -- not for the actual running where the value of the flag has little useful value, but to make sure no data is gathered after the system has started to close down.
Definition at line 337 of file IgProf.cc.
References s_enabled, s_flagkey, and s_pthreads.
Referenced by dokill(), initThread(), and profileSignalHandler().
00338 { 00339 if (! globally && s_pthreads) 00340 { 00341 IgProfAtomic *flag = (IgProfAtomic *) pthread_getspecific(s_flagkey); 00342 return flag ? (*flag > 0 && s_enabled > 0) : false; 00343 } 00344 else 00345 return s_enabled > 0; 00346 }
Finalise a thread.
Definition at line 280 of file IgProf.cc.
References i, IgProfTrace::mergeFrom(), N_MODULES, p, s_bufkey, s_bufs, s_mainthread, s_masterbuf, s_pthreads, and thread.
Referenced by doexit(), threadWrapper(), and IgProfExitDump::~IgProfExitDump().
00281 { 00282 if (! s_pthreads && ! final) 00283 return; 00284 00285 pthread_t thread = pthread_self (); 00286 IgProfTraceAlloc *bufs 00287 = (thread == s_mainthread ? s_bufs 00288 : (IgProfTraceAlloc *) pthread_getspecific(s_bufkey)); 00289 00290 for (int i = 0; i < N_MODULES && bufs; ++i) 00291 { 00292 IgProfTrace *p = bufs[i].buf; 00293 if (p) 00294 { 00295 s_masterbuf->mergeFrom(*p); 00296 bufs[i].buf = 0; 00297 delete p; 00298 } 00299 } 00300 00301 if (thread == s_mainthread) 00302 s_bufs = 0; 00303 else 00304 pthread_setspecific(s_bufkey, 0); 00305 00306 delete [] bufs; 00307 }
Initialise the profiler core itself.
Prepares the the program for profiling. Captures various exit points so we generate a dump before the program goes "out". Automatically triggered to run on library load. All profiler modules should invoke this method before doing their own initialisation.
Returns true
if profiling is activated in this process.
Definition at line 115 of file IgProf.cc.
References debug(), disable(), e, enable(), IgHook::hook(), i, initBuf(), MAX_FNAME, N_MODULES, options(), IgProfTrace::OptResources, bookConverter::opts, s_activated, s_bufkey, s_bufs, s_clockres, s_dumpflag, s_enabled, s_flagkey, s_initialized, s_mainthread, s_masterbuf, s_masterbufdata, s_outname, s_pthreads, s_symcache, s_symcachedata, target, and threadinits().
Referenced by initialize().
00116 { 00117 if (! s_initialized) 00118 { 00119 s_initialized = true; 00120 00121 const char *options = IgProf::options(); 00122 if (! options || ! *options) 00123 { 00124 IgProf::debug("$IGPROF not set, not profiling this process\n"); 00125 return s_activated = false; 00126 } 00127 00128 for (const char *opts = options; *opts; ) 00129 { 00130 while (*opts == ' ' || *opts == ',') 00131 ++opts; 00132 00133 if (! strncmp(opts, "igprof:out='", 12)) 00134 { 00135 int i = 0; 00136 opts += 12; 00137 while (i < MAX_FNAME-1 && *opts && *opts != '\'') 00138 s_outname[i++] = *opts++; 00139 s_outname[i] = 0; 00140 } 00141 else if (! strncmp(opts, "igprof:dump='", 13)) 00142 { 00143 int i = 0; 00144 opts += 13; 00145 while (i < MAX_FNAME-1 && *opts && *opts != '\'') 00146 s_dumpflag[i++] = *opts++; 00147 s_dumpflag[i] = 0; 00148 } 00149 else 00150 opts++; 00151 00152 while (*opts && *opts != ',' && *opts != ' ') 00153 opts++; 00154 } 00155 00156 if (! s_outname[0]) 00157 sprintf(s_outname, "igprof.%ld", (long) getpid()); 00158 00159 s_bufs = new IgProfTraceAlloc[N_MODULES]; 00160 memset(s_bufs, 0, N_MODULES * sizeof(*s_bufs)); 00161 00162 void *program = dlopen(0, RTLD_NOW); 00163 if (program && dlsym(program, "pthread_create")) 00164 { 00165 s_pthreads = true; 00166 pthread_key_create(&s_bufkey, 0); 00167 pthread_key_create(&s_flagkey, 0); 00168 pthread_setspecific(s_flagkey, new IgProfAtomic(1)); 00169 } 00170 dlclose(program); 00171 00172 const char *target = getenv("IGPROF_TARGET"); 00173 s_mainthread = pthread_self(); 00174 if (target && ! strstr(program_invocation_name, target)) 00175 { 00176 IgProf::debug("Current process not selected for profiling:" 00177 " process '%s' does not match '%s'\n", 00178 program_invocation_name, target); 00179 return s_activated = false; 00180 } 00181 00182 itimerval precision; 00183 itimerval interval = { { 0, 10000 }, { 100, 0 } }; 00184 itimerval nullified = { { 0, 0 }, { 0, 0 } }; 00185 setitimer(ITIMER_PROF, &interval, 0); 00186 getitimer(ITIMER_PROF, &precision); 00187 setitimer(ITIMER_PROF, &nullified, 0); 00188 s_clockres = (precision.it_interval.tv_sec 00189 + 1e-6 * precision.it_interval.tv_usec); 00190 00191 IgProf::debug("Activated in %s, timing resolution %f, %s," 00192 " main thread id 0x%lx\n", 00193 program_invocation_name, s_clockres, 00194 s_pthreads ? "multi-threaded" : "no threads", 00195 s_mainthread); 00196 IgProf::debug("Options: %s\n", options); 00197 00198 IgHook::hook(doexit_hook_main.raw); 00199 IgHook::hook(doexit_hook_main2.raw); 00200 IgHook::hook(dokill_hook_main.raw); 00201 #if __linux 00202 if (doexit_hook_main.raw.chain) IgHook::hook(doexit_hook_libc.raw); 00203 if (doexit_hook_main2.raw.chain) IgHook::hook(doexit_hook_libc2.raw); 00204 if (dokill_hook_main.raw.chain) IgHook::hook(dokill_hook_libc.raw); 00205 #endif 00206 if (s_pthreads) 00207 { 00208 IgHook::hook(dopthread_create_hook_main.raw); 00209 #if __linux 00210 IgHook::hook(dopthread_create_hook_pthread20.raw); 00211 IgHook::hook(dopthread_create_hook_pthread21.raw); 00212 #endif 00213 } 00214 s_activated = true; 00215 s_enabled = 1; 00216 } 00217 00218 if (! s_activated) 00219 return false; 00220 00221 if (! moduleid) 00222 return true; 00223 00224 IgProf::disable(true); 00225 00226 if (! s_masterbuf) 00227 { 00228 s_masterbuf = new (s_masterbufdata) IgProfTrace(IgProfTrace::OptResources); 00229 s_symcache = new (s_symcachedata) IgProfSymCache; 00230 } 00231 00232 int modid; 00233 for (modid = 0; modid < N_MODULES; ++modid) 00234 if (! s_bufs[modid].buf) 00235 { 00236 initBuf(s_bufs[modid], perthread); 00237 *moduleid = modid; 00238 break; 00239 } 00240 00241 if (modid == N_MODULES) 00242 { 00243 IgProf::debug("Too many profilers enabled (%d), please" 00244 " rebuild IgProf with larger N_MODULES\n", 00245 N_MODULES); 00246 abort (); 00247 } 00248 00249 if (threadinit) 00250 threadinits().push_back(threadinit); 00251 00252 IgProf::enable(true); 00253 return true; 00254 }
Setup a thread so it can be used in profiling.
This should be called for every thread that will participate in profiling.
Definition at line 264 of file IgProf.cc.
References IgProfTraceAlloc::buf, enabled(), i, initBuf(), N_MODULES, s_bufkey, s_bufs, and s_flagkey.
Referenced by threadWrapper().
00265 { 00266 IgProfTraceAlloc *bufs = new IgProfTraceAlloc[N_MODULES]; 00267 memset(bufs, 0, N_MODULES * sizeof(*bufs)); 00268 pthread_setspecific(s_bufkey, bufs); 00269 00270 IgProfAtomic *enabled = new IgProfAtomic(1); 00271 pthread_setspecific(s_flagkey, enabled); 00272 00273 for (int i = 0; i < N_MODULES && s_bufs[i].buf; ++i) 00274 if (s_bufs[i].perthread) 00275 initBuf(bufs[i], true); 00276 }
Return true
if the process was linked against threading package.
Definition at line 258 of file IgProf.cc.
References s_pthreads.
Referenced by enableSignalHandler().
00259 { return s_pthreads; }
const char * IgProf::options | ( | void | ) | [static] |
Get user-provided profiling options.
Definition at line 386 of file IgProf.cc.
References s_options.
Referenced by initialize(), and initialize().
Internal assertion helper routine.
Definition at line 395 of file IgProf.cc.
References disable(), i, offset, IgHookTrace::stacktrace(), IgHookTrace::symbol(), and GsfMatrixTools::trace().
00396 { 00397 IgProf::disable(true); 00398 00399 fprintf (stderr, "%s: %s:%d: %s: assertion failure: %s\n", 00400 program_invocation_name, file, line, func, expr); 00401 00402 void *trace [128]; 00403 int levels = IgHookTrace::stacktrace(trace, 128); 00404 for (int i = 2; i < levels; ++i) 00405 { 00406 const char *sym = 0; 00407 const char *lib = 0; 00408 int offset = 0; 00409 int liboffset = 0; 00410 00411 IgHookTrace::symbol(trace[i], sym, lib, offset, liboffset); 00412 fprintf(stderr, " %p %s + %d [%s + %d]\n", 00413 trace[i], sym ? sym : "?", offset, lib ? lib : "?", liboffset); 00414 } 00415 00416 // abort(); 00417 return 1; 00418 }