CMS 3D CMS Logo

SimpleProfiler.cc File Reference

#include <pthread.h>
#include <unistd.h>
#include <dlfcn.h>
#include <cassert>
#include <cstdio>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <ucontext.h>
#include <execinfo.h>
#include "SimpleProfiler.h"
#include "ProfParse.h"
#include <fstream>

Go to the source code of this file.

Namespaces

namespace  INSTR

Defines

#define _POSIX_C_SOURCE   199309
#define DODEBUG   if(0) std::cerr
#define getBP(X)   asm ( "movl %%ebp,%0" : "=m" (X) )
#define getSP(X)   asm ( "movl %%esp,%0" : "=m" (X) )
#define MUST_BE_ZERO(fun)   if((fun)!=0) { perror("function failed"); abort(); }

Typedefs

typedef unsigned char INSTR::byte

Functions

void closeCondFile ()
void dumpStack (const char *msg, unsigned int *esp, unsigned int *ebp, unsigned char *eip, ucontext_t *ucp)
std::string makeFileName ()
void openCondFile ()
voidsetStacktop ()
void setupTimer ()
void setupTimer ()
void sigFunc (int sig, siginfo_t *info, void *context)
int stacktrace (void *addresses[], int nmax)
void write_maps ()
void writeCond (int code)

Variables

FILE * frame_cond = 0
static AdjustSigs global_adjust
const int REG_EBP = 6
const int REG_EIP = 14
const int REG_ESP = 7
const byte INSTR::RET = 0xc3
int samples_missing_framepointer = 0
int samples_total = 0
stack_t ss_area


Define Documentation

#define _POSIX_C_SOURCE   199309

Definition at line 3 of file SimpleProfiler.cc.

#define DODEBUG   if(0) std::cerr

Definition at line 68 of file SimpleProfiler.cc.

#define getBP (  )     asm ( "movl %%ebp,%0" : "=m" (X) )

Definition at line 62 of file SimpleProfiler.cc.

Referenced by setStacktop().

#define getSP (  )     asm ( "movl %%esp,%0" : "=m" (X) )

Definition at line 63 of file SimpleProfiler.cc.

#define MUST_BE_ZERO ( fun   )     if((fun)!=0) { perror("function failed"); abort(); }

Definition at line 61 of file SimpleProfiler.cc.

Referenced by edm::disableAllSigs(), edm::disableRTSigs(), edm::disableSignal(), edm::enableSignal(), edm::installSig(), edm::reenableSigs(), setupTimer(), and edm::sigInventory().


Function Documentation

void @7703::closeCondFile (  )  [static]

Definition at line 123 of file SimpleProfiler.cc.

Referenced by SimpleProfiler::~SimpleProfiler().

00124   {
00125     fclose(frame_cond);
00126   }

void @7703::dumpStack ( const char *  msg,
unsigned int esp,
unsigned int ebp,
unsigned char *  eip,
ucontext_t *  ucp 
) [static]

Definition at line 128 of file SimpleProfiler.cc.

References i.

00131   {
00132 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
00133     throw std::logic_error("Cannot dumpStack on 64 bit build");
00134 #else
00135     fprintf(frame_cond, msg);
00136     fflush(frame_cond);
00137     return;
00138     fprintf(frame_cond, "dumpStack:\n i= %x\n eip[0]= %2.2x\nb= %x\n s= %x\n b[0]= %x\n b[1]= %x\n b[2]= %x\n",
00139             (void*)eip, eip[0], (void*)ebp, (void*)esp, (void*)(ebp[0]), (void*)(ebp[1]), (void*)(ebp[2]));
00140     fflush(frame_cond);
00141 
00142 
00143 #if 0
00144     unsigned int* spp = esp;
00145     for(int i=15;i>-5;--i)
00146       {
00147         fprintf(frame_cond, "    %x esp[%d]= %x\n", (void*)(spp+i), i, (void*)*(spp+i));
00148         fflush(frame_cond);
00149       }
00150 #else
00151     while(ucp->uc_link)
00152       {
00153         fprintf(frame_cond, "   %8.8x\n",ucp->uc_link);
00154         ucp = ucp->uc_link;
00155       }
00156 #endif
00157 #endif
00158   }

std::string @7703::makeFileName (  )  [static]

Definition at line 48 of file SimpleProfiler.cc.

References p.

Referenced by SimpleProfiler::complete(), and openCondFile().

00049   {
00050     pid_t p = getpid();
00051     std::ostringstream ost;
00052     ost << "profdata_" << p;
00053     return ost.str();
00054   }

void @7703::openCondFile (  )  [static]

Definition at line 106 of file SimpleProfiler.cc.

References TestMuL1L2Filter_cff::cerr, EgammaValidation_cff::filename, and makeFileName().

Referenced by SimpleProfiler::SimpleProfiler().

00107   {
00108     std::string filename(makeFileName());
00109     filename += "_condfile";
00110     frame_cond = fopen(filename.c_str(),"w");
00111     if(frame_cond==0)
00112       {
00113         std::cerr << "bad open of profdata_condfile\n";
00114         throw std::runtime_error("bad open");
00115       }
00116   }

void* @7703::setStacktop (  )  [static]

Definition at line 358 of file SimpleProfiler.cc.

References TestMuL1L2Filter_cff::cerr, getBP, and i.

00359   {
00360 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
00361     throw std::logic_error("setStacktop not callable on 64 bit platform");
00362     return 0;
00363 #else
00364     const std::string target_name("__libc_start_main");
00365     unsigned int* ebp_reg;
00366     getBP(ebp_reg);
00367     unsigned int* ebp = (unsigned int*)(ebp_reg);
00368     unsigned int* top = (unsigned int*)(ebp);
00369 
00370     void* address_of_target = 0;
00371     const int max_stackdepth=30;
00372     void* sta[max_stackdepth];
00373 
00374     int depth = backtrace(sta, max_stackdepth);
00375     int cnt = depth;
00376     if (depth > 1) depth-=1;
00377 
00378     // find function one below main()
00379     Dl_info look;
00380     for (int i=0; i<cnt && !address_of_target; ++i)
00381       {
00382         if(dladdr(sta[i],&look)!=0)
00383           {
00384             if (look.dli_saddr && target_name==look.dli_sname)
00385               {
00386                 address_of_target = sta[i];
00387               }
00388           }
00389         else
00390           {
00391             // This isn't really an error; it just means the function
00392             // was not found by the dynamic loader. The function might
00393             // be one that is declared 'static', and is thus not
00394             // visible outside of its compilation unit.
00395             std::cerr << "setStacktop: no function information for " 
00396                       << sta[i] 
00397                       << "\n";
00398           }
00399       }
00400 
00401     if (address_of_target == 0)
00402       throw std::runtime_error("no main function found in stack");
00403 
00404     //fprintf(stderr,"depth=%d top=%8.8x\n",depth,top);
00405 
00406     // Now we walk toward the beginning of the stack until we find the
00407     // frame that is holding the return address of our target function.
00408 
00409     // depth is how many more frames there are to look at in the stack.
00410     // top is the frame we are currently looking at.
00411     // top+1 is the address to which the current frame will return.
00412     while (depth>0 && (void*)*(top+1) != address_of_target)
00413       {
00414         //fprintf(stderr,"depth=%d top=%8.8x func=%8.8x\n",depth,top,*(top+1));
00415         if (top<(unsigned int*)0x10) fprintf(stderr,"problem\n");
00416         top=(unsigned int*)(*top);
00417         --depth;
00418       };
00419 
00420     if (depth==0) 
00421       throw std::runtime_error("setStacktop: could not find stack bottom");
00422 
00423     // Now we have to move one frame more, to the frame of the target
00424     // function. We want the location in memory of this frame (not any
00425     // address stored in the frame, but the address of the frame
00426     // itself).
00427     top=(unsigned int*)(*top);
00428 
00429     return top;
00430 #endif
00431   }

void @7703::setupTimer (  )  [static]

Definition at line 433 of file SimpleProfiler.cc.

References TestMuL1L2Filter_cff::cerr, MUST_BE_ZERO, NULL, funct::num(), SA_SIGINFO, sigaction, sigaddset, sigdelset, sigfillset, and sigFunc().

00434   {
00435 #if USE_SIGALTSTACK
00436     static vector<char> charbuffer(SIGSTKSZ);
00437     //ss_area.ss_sp = new char[SIGSTKSZ];
00438     ss_area.ss_sp = &charbuffer[0];
00439     ss_area.ss_flags = 0;
00440     ss_area.ss_size = SIGSTKSZ;
00441 #endif
00442     //static int is_set = 0;
00443     //if(is_set!=1) { ++is_set; return; }
00444     //else ++is_set;
00445 
00446     sigset_t myset,oldset;
00447     // all blocked for now
00448     MUST_BE_ZERO(sigfillset(&myset));
00449     MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK,&myset,&oldset));
00450 
00451 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
00452     // ignore all the RT signals
00453     struct sigaction tmpact;
00454     memset(&tmpact,0,sizeof(tmpact));
00455     tmpact.sa_handler = SIG_IGN;
00456 
00457     for(int num=SIGRTMIN;num<SIGRTMAX;++num)
00458       {
00459         MUST_BE_ZERO(sigaddset(&oldset,num));
00460         MUST_BE_ZERO(sigaction(num,&tmpact,NULL));
00461       }
00462 #endif
00463 
00464 #if USE_SIGALTSTACK
00465     if(sigaltstack(&ss_area,0)!=0)
00466       {
00467         perror("sigaltstack failed for profile timer interrupt");
00468         abort();
00469       }
00470 #endif
00471 
00472     // set up my RT signal now
00473     struct sigaction act;
00474     memset(&act,0,sizeof(act));
00475     act.sa_sigaction = sigFunc;
00476     act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
00477 
00478     // get my signal number
00479     int mysig = SIGPROF;
00480 
00481     if(sigaction(mysig,&act,NULL)!=0)
00482       {
00483         perror("sigaction failed");
00484         abort();
00485       }
00486 
00487     // Turn off handling of SIGSEGV signal
00488     memset(&act,0,sizeof(act));
00489     act.sa_handler = SIG_DFL;
00490 
00491     if (sigaction(SIGSEGV, &act, NULL) != 0)
00492       {
00493         perror("sigaction failed");
00494         abort();
00495       }
00496 
00497     struct rlimit limits;
00498     if (getrlimit(RLIMIT_CORE, &limits) != 0)
00499       {
00500         perror("getrlimit failed");
00501         abort();
00502       }
00503     std::cerr << "core size limit (soft): " << limits.rlim_cur << '\n';
00504     std::cerr << "core size limit (hard): " << limits.rlim_max << '\n';
00505 
00506     struct itimerval newval;
00507     struct itimerval oldval;
00508 
00509     newval.it_interval.tv_sec  = 0;
00510     newval.it_interval.tv_usec = 10000;
00511     newval.it_value.tv_sec  = 0;
00512     newval.it_value.tv_usec = 10000;
00513 
00514     if(setitimer(ITIMER_PROF,&newval,&oldval)!=0)
00515       {
00516         perror("setitimer failed");
00517         abort();
00518       }
00519 
00520     // reenable the signals, including my interval timer
00521     MUST_BE_ZERO(sigdelset(&oldset,mysig));
00522     MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK,&oldset,0));
00523   }

void @7703::setupTimer (  )  [static]

Referenced by SimpleProfiler::start().

void sigFunc ( int  sig,
siginfo_t info,
void context 
)

Definition at line 335 of file SimpleProfiler.cc.

References SimpleProfiler::commitFrame(), SimpleProfiler::instance(), stacktrace(), SimpleProfiler::tempStack(), and SimpleProfiler::tempStackSize().

Referenced by setupTimer().

00336   {
00337     SimpleProfiler* prof = SimpleProfiler::instance();
00338     void** arr = prof->tempStack();
00339     int nmax =   prof->tempStackSize();
00340     int stackdepth = stacktrace(arr, nmax);
00341 
00342     assert(stackdepth <= nmax);
00343 
00344     // We don't want the first three entries, because they always
00345     // contain information about the how the signal handler was
00346     // called, the signal handler, and the stacktrace function.
00347     prof->commitFrame(arr+3, arr + stackdepth);
00348   }

int stacktrace ( void addresses[],
int  nmax 
)

Definition at line 217 of file SimpleProfiler.cc.

References if(), info, REG_EBP, REG_EIP, samples_missing_framepointer, and samples_total.

Referenced by sigFunc().

00218 {
00219   ++samples_total;
00220 #if __linux && __i386
00221 # if ! __x86_64__
00222 #  define PROBABLY_VSYSCALL_PAGE 0xffff0000
00223 # else
00224 #  define PROBABLY_VSYSCALL_PAGE 0xffffffff00000000
00225 # endif
00226   struct frame
00227   {
00228     // Normal frame.
00229     frame               *ebp;
00230     void                *eip;
00231     // Signal frame stuff, put in here by kernel.
00232     int         signo;
00233     siginfo_t   *info;
00234     ucontext_t  *ctx;
00235   };
00236   register frame      *ebp __asm__ ("ebp");
00237   register frame      *esp __asm__ ("esp");
00238   frame               *fp = ebp;
00239   int                   depth = 0;
00240 
00241   // Add fake entry to be compatible with other methods
00242   if (depth < nmax) addresses[depth++] = (void *) &stacktrace;
00243 
00244   // Top-most frame ends with null pointer; check the rest is reasonable
00245   while (depth < nmax && fp >= esp)
00246     {
00247       // Add this stack frame.  The return address is the
00248       // instruction immediately after the "call".  The call
00249       // instruction itself is 4 or 6 bytes; we guess 4.
00250       addresses[depth++] = (char *) fp->eip - 4;
00251 
00252       // Recognise signal frames.  We use two different methods
00253       // depending on the linux kernel version.
00254       //
00255       // For the "old" kernels / systems we check the instructions
00256       // at the caller's return address.  We take it to be a signal
00257       // frame if we find the signal return code sequence there
00258       // and the thread register context structure pointer:
00259       //
00260       //    mov $__NR_rt_sigreturn, %eax
00261       //    int 0x80
00262       //
00263       // For the "new" kernels / systems the operating system maps
00264       // a "vsyscall" page at a high address, and it may contain
00265       // either the above code, or use of the sysenter/sysexit
00266       // instructions.  We cannot poke at that page so we take the
00267       // the high address as an indication this is a signal frame.
00268       // (https://www.trilithium.com/johan/2005/08/linux-gate/)
00269       // (https://manugarg.googlepages.com/systemcallinlinux2_6.html)
00270       //
00271       // If we don't recognise the signal frame correctly here, we
00272       // lose one stack frame: signal delivery is not a call so
00273       // when the signal handler is entered, ebp still points to
00274       // what it was just before the signal.
00275       unsigned char *insn = (unsigned char *) fp->eip;
00276       if (insn
00277           && insn[0] == 0xb8 && insn[1] == __NR_rt_sigreturn
00278           && insn[5] == 0xcd && insn[6] == 0x80
00279           && fp->ctx)
00280         {   
00281           void *retip = (void *) fp->ctx->uc_mcontext.gregs [REG_EIP];
00282           if (depth < nmax) addresses[depth++] = retip;
00283 
00284           fp = (frame *) fp->ctx->uc_mcontext.gregs [REG_EBP];
00285           if (fp && (unsigned long) retip > PROBABLY_VSYSCALL_PAGE)
00286             {
00287               // __kernel_vsyscall stack on system call exit is
00288               // [0] %ebp, [1] %edx, [2] %ecx, [3] return address.
00289               if (depth < nmax) addresses[depth++] = ((void **) fp)[3];
00290               fp = fp->ebp;
00291 
00292               // It seems the frame _above_ __kernel_syscall (the
00293               // syscall implementation in libc, such as __mmap())
00294               // is essentially frame-pointer-less, so we should
00295               // find also the call above, but I don't know how
00296               // to determine how many arguments the system call
00297               // pushed on stack to call __kernel_syscall short
00298               // of interpreting the DWARF unwind information :-(
00299               // So we may lose one level of call stack here.
00300               ++samples_missing_framepointer;
00301             }
00302         }
00303 
00304       // Otherwise it's a normal frame, process through frame pointer.
00305       else
00306         fp = fp->ebp;
00307     }
00308 
00309   return depth;
00310 #elif __linux
00311   return backtrace (addresses, nmax);
00312 #elif HAVE_UNWIND_BACKTRACE
00313   if (nmax >= 1)
00314     {
00315       IgHookTraceArgs args = { addresses, 0, nmax };
00316       _Unwind_Backtrace (&GCCBackTrace, &args);
00317 
00318       if (args.count > 1 && args.array [args.count-1] == 0)
00319         args.count--;
00320 
00321       return args.count;
00322     }
00323   return 0;
00324 #else
00325   return 0;
00326 #endif
00327 }

void @7703::write_maps (  )  [static]

Definition at line 90 of file SimpleProfiler.cc.

References iggi_31X_cfg::input, parsecf::pyparsing::line(), and output().

Referenced by SimpleProfiler::complete().

00091   {
00092     pid_t pid = getpid();
00093     std::ostringstream strinput,stroutput;
00094     strinput << "/proc/" << pid << "/maps";
00095     stroutput << "profdata_" << pid << "_maps";
00096     std::ifstream input(strinput.str().c_str());
00097     std::ofstream output(stroutput.str().c_str());
00098     std::string line;
00099     while (getline(input, line)) output << line << '\n';
00100     input.close();
00101     output.close();
00102   }

void @7703::writeCond ( int  code  )  [static]

Definition at line 118 of file SimpleProfiler.cc.

00119   {
00120     fwrite(&code,sizeof(int),1,frame_cond);
00121   }


Variable Documentation

FILE* frame_cond = 0 [static]

Definition at line 104 of file SimpleProfiler.cc.

AdjustSigs global_adjust [static]

Definition at line 553 of file SimpleProfiler.cc.

const int REG_EBP = 6

Definition at line 75 of file SimpleProfiler.cc.

Referenced by stacktrace(), and IgHookTrace::stacktrace().

const int REG_EIP = 14

Definition at line 74 of file SimpleProfiler.cc.

Referenced by stacktrace(), and IgHookTrace::stacktrace().

const int REG_ESP = 7

Definition at line 76 of file SimpleProfiler.cc.

int samples_missing_framepointer = 0 [static]

Definition at line 165 of file SimpleProfiler.cc.

Referenced by SimpleProfiler::complete(), and stacktrace().

int samples_total = 0 [static]

Definition at line 164 of file SimpleProfiler.cc.

Referenced by SimpleProfiler::complete(), and stacktrace().

stack_t ss_area [static]

Definition at line 354 of file SimpleProfiler.cc.


Generated on Tue Jun 9 17:53:33 2009 for CMSSW by  doxygen 1.5.4