00001 #include "IgTools/IgProf/src/IgProf.h"
00002 #include "IgTools/IgProf/src/IgProfTrace.h"
00003 #include "IgTools/IgHook/interface/IgHook.h"
00004 #include "IgTools/IgHook/interface/IgHookTrace.h"
00005 #include <cstdlib>
00006 #include <cstring>
00007 #include <signal.h>
00008 #include <sys/time.h>
00009
00010 #ifdef __APPLE__
00011 typedef sig_t sighandler_t;
00012 #endif
00013
00014
00015
00016 IGPROF_LIBHOOK(3, int, dopthread_sigmask, _main,
00017 (int how, sigset_t *newmask, sigset_t *oldmask),
00018 (how, newmask, oldmask),
00019 "pthread_sigmask", 0, 0)
00020 IGPROF_LIBHOOK(3, int, dosigaction, _main,
00021 (int signum, const struct sigaction *act, struct sigaction *oact),
00022 (signum, act, oact),
00023 "sigaction", 0, 0)
00024
00025
00026 static IgProfTrace::CounterDef s_ct_ticks = { "PERF_TICKS", IgProfTrace::TICK, -1 };
00027 static bool s_initialized = false;
00028 static int s_signal = SIGPROF;
00029 static int s_itimer = ITIMER_PROF;
00030 static int s_moduleid = -1;
00031
00037 static void
00038 profileSignalHandler(int , siginfo_t * , void * )
00039 {
00040 if (! IgProf::enabled(false))
00041 return;
00042
00043 IgProfTrace *buf = IgProf::buffer(s_moduleid);
00044 if (! buf)
00045 return;
00046
00047 void *addresses [IgProfTrace::MAX_DEPTH];
00048 int depth = IgHookTrace::stacktrace(addresses, IgProfTrace::MAX_DEPTH);
00049 IgProfTrace::Record entry = { IgProfTrace::COUNT, &s_ct_ticks, 1, 1, 0 };
00050
00051
00052 buf->push(addresses+3, depth-4, &entry, 1);
00053 }
00054
00058 static void
00059 enableTimer(void)
00060 {
00061 itimerval interval = { { 0, 10000 }, { 0, 10000 } };
00062 setitimer(s_itimer, &interval, 0);
00063 }
00064
00066 static void
00067 enableSignalHandler(void)
00068 {
00069 sigset_t profset;
00070 sigemptyset(&profset);
00071 sigaddset(&profset, s_signal);
00072 if (IgProf::isMultiThreaded())
00073 pthread_sigmask(SIG_UNBLOCK, &profset, 0);
00074 else
00075 sigprocmask(SIG_UNBLOCK, &profset, 0);
00076
00077 struct sigaction sa;
00078 sigemptyset(&sa.sa_mask);
00079 sa.sa_handler = (sighandler_t) &profileSignalHandler;
00080 sa.sa_flags = SA_RESTART | SA_SIGINFO;
00081 sigaction(s_signal, &sa, 0);
00082 }
00083
00085 static void
00086 threadInit(void)
00087 {
00088
00089 enableSignalHandler();
00090 enableTimer();
00091 }
00092
00093
00095 static void
00096 initialize(void)
00097 {
00098 if (s_initialized) return;
00099 s_initialized = true;
00100
00101 const char *options = IgProf::options();
00102 bool enable = false;
00103
00104 while (options && *options)
00105 {
00106 while (*options == ' ' || *options == ',')
00107 ++options;
00108
00109 if (! strncmp(options, "perf", 4))
00110 {
00111 enable = true;
00112 options += 4;
00113 while (*options)
00114 {
00115 if (! strncmp(options, ":real", 5))
00116 {
00117 s_signal = SIGALRM;
00118 s_itimer = ITIMER_REAL;
00119 options += 5;
00120 }
00121 else if (! strncmp(options, ":user", 5))
00122 {
00123 s_signal = SIGVTALRM;
00124 s_itimer = ITIMER_VIRTUAL;
00125 options += 5;
00126 }
00127 else if (! strncmp(options, ":process", 7))
00128 {
00129 s_signal = SIGPROF;
00130 s_itimer = ITIMER_PROF;
00131 options += 7;
00132 }
00133 else
00134 break;
00135 }
00136 }
00137 else
00138 options++;
00139
00140 while (*options && *options != ',' && *options != ' ')
00141 options++;
00142 }
00143
00144 if (! enable)
00145 return;
00146
00147 if (! IgProf::initialize(&s_moduleid, &threadInit, true))
00148 return;
00149
00150 IgProf::disable(true);
00151 if (s_itimer == ITIMER_REAL)
00152 IgProf::debug("Perf: measuring real time\n");
00153 else if (s_itimer == ITIMER_VIRTUAL)
00154 IgProf::debug("Perf: profiling user time\n");
00155 else if (s_itimer == ITIMER_PROF)
00156 IgProf::debug("Perf: profiling process time\n");
00157
00158
00159 IgHook::hook(dopthread_sigmask_hook_main.raw);
00160 IgHook::hook(dosigaction_hook_main.raw);
00161 IgProf::debug("Performance profiler enabled\n");
00162
00163 enableSignalHandler();
00164 enableTimer();
00165 IgProf::enable(true);
00166 }
00167
00168
00169
00170 static int
00171 dopthread_sigmask(IgHook::SafeData<igprof_dopthread_sigmask_t> &hook,
00172 int how, sigset_t *newmask, sigset_t *oldmask)
00173 {
00174 if (newmask
00175 && (how == SIG_BLOCK || how == SIG_SETMASK)
00176 && sigismember(newmask, s_signal))
00177 {
00178 IgProf::debug("pthread_sigmask(): prevented profiling signal"
00179 " %d from being blocked in thread 0x%lx\n",
00180 s_signal, (unsigned long) pthread_self());
00181 sigdelset(newmask, s_signal);
00182 }
00183
00184 return hook.chain(how, newmask, oldmask);
00185 }
00186
00187
00188 static int
00189 dosigaction(IgHook::SafeData<igprof_dosigaction_t> &hook,
00190 int signum, const struct sigaction *act, struct sigaction *oact)
00191 {
00192 struct sigaction sa;
00193 if (signum == s_signal
00194 && act
00195 && act->sa_handler != (sighandler_t) &profileSignalHandler)
00196 {
00197 IgProf::debug("sigaction(): prevented profiling signal"
00198 " %d from being overridden in thread 0x%lx\n",
00199 s_signal, (unsigned long) pthread_self());
00200 sigemptyset(&sa.sa_mask);
00201 sa.sa_handler = (sighandler_t) &profileSignalHandler;
00202 sa.sa_flags = SA_RESTART | SA_SIGINFO;
00203 act = &sa;
00204 }
00205
00206 return hook.chain(signum, act, oact);
00207 }
00208
00209
00210 static bool autoboot = (initialize(), true);