CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch12/src/FWCore/Services/src/SimpleProfiler.cc

Go to the documentation of this file.
00001 
00002 #ifndef _POSIX_C_SOURCE
00003 #define _POSIX_C_SOURCE 199309
00004 #endif
00005 
00006 #if __linux
00007 # include <execinfo.h>
00008 # include <ucontext.h>
00009 # include <sys/syscall.h>
00010 #endif
00011 #if __APPLE__
00012 #include <signal.h>
00013 //the following is needed to use the deprecated ucontext method on OS X
00014 #define _XOPEN_SOURCE
00015 #endif
00016 
00017 
00018 #include <pthread.h>
00019 #include <unistd.h>
00020 #include <dlfcn.h>
00021 
00022 #include <cassert>
00023 #include <cstdio>
00024 #include <cstring>
00025 #include <iostream>
00026 #include <sstream>
00027 #include <stdexcept>
00028 
00029 #include <sys/time.h>
00030 #include <sys/stat.h>
00031 #include <sys/resource.h>
00032 #include <fcntl.h>
00033 #include <ucontext.h>
00034 #include <execinfo.h>
00035 
00036 #include "SimpleProfiler.h"
00037 #include "ProfParse.h"
00038 
00039 #ifdef __linux
00040 #ifndef __USE_POSIX199309
00041 #error "SimpleProfile requires the definition of __USE_POSIX199309"
00042 #endif
00043 #endif
00044 
00045 
00046 namespace INSTR
00047 {
00048   typedef unsigned char byte;
00049   const byte RET = 0xc3;  
00050 }
00051 
00052 namespace
00053 {
00054 
00055   std::string makeFileName()
00056   {
00057     pid_t p = getpid();
00058     std::ostringstream ost;
00059     ost << "profdata_" << p;
00060     return ost.str();
00061   }
00062 }
00063 
00064 // ---------------------------------------------------------------------
00065 // Macros, for this compilation unit only
00066 // ---------------------------------------------------------------------
00067 
00068 #define MUST_BE_ZERO(fun) if((fun)!=0) { perror("function failed"); abort(); }
00069 #define getBP(X)  asm ( "movl %%ebp,%0" : "=m" (X) )
00070 #define getSP(X)  asm ( "movl %%esp,%0" : "=m" (X) )
00071 
00072 #if 0
00073 #define DODEBUG if(1) std::cerr
00074 #else
00075 #define DODEBUG if(0) std::cerr
00076 #endif
00077 
00078 
00079 
00080 #ifndef __USE_GNU
00081 const int REG_EIP = 14;
00082 const int REG_EBP = 6;
00083 const int REG_ESP = 7;
00084 #endif
00085 
00086 #include "unistd.h"
00087 #include <sstream>
00088 #include <fstream>
00089 
00090 
00091 namespace 
00092 {
00093 
00094   // Record the dynamic library mapping information from /proc/ for
00095   // later use in discovering the names of functions recorded as
00096   // 'unknown_*'.
00097   void write_maps()
00098   {
00099     pid_t pid = getpid();
00100     std::ostringstream strinput,stroutput;
00101     strinput << "/proc/" << pid << "/maps";
00102     stroutput << "profdata_" << pid << "_maps";
00103     std::ifstream input(strinput.str().c_str());
00104     std::ofstream output(stroutput.str().c_str());
00105     std::string line;
00106     while (getline(input, line)) output << line << '\n';
00107     input.close();
00108     output.close();
00109   }
00110 
00111   FILE* frame_cond = 0;
00112 
00113   void openCondFile()
00114   {
00115     std::string filename(makeFileName());
00116     filename += "_condfile";
00117     frame_cond = fopen(filename.c_str(),"w");
00118     if(frame_cond==0)
00119       {
00120         std::cerr << "bad open of profdata_condfile\n";
00121         throw std::runtime_error("bad open");
00122       }
00123   }
00124 
00125   void writeCond(int code)
00126   {
00127     fwrite(&code,sizeof(int),1,frame_cond);
00128   }
00129 
00130   void closeCondFile()
00131   {
00132     fclose(frame_cond);
00133   }
00134 
00135   void dumpStack(const char* msg,
00136                  unsigned int* esp, unsigned int* ebp, unsigned char* eip,
00137                  ucontext_t* ucp)
00138   {
00139 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
00140     throw std::logic_error("Cannot dumpStack on 64 bit build");
00141 #else
00142     fprintf(frame_cond, msg);
00143     fflush(frame_cond);
00144     return;
00145     fprintf(frame_cond, "dumpStack:\n i= %p\n eip[0]= %2.2x\nb= %p\n s= %p\n b[0]= %x\n b[1]= %x\n b[2]= %x\n",
00146             eip, eip[0], (void *)ebp, (void *)esp, ebp[0], ebp[1], ebp[2]);
00147     fflush(frame_cond);
00148 
00149 
00150 #if 0
00151     unsigned int* spp = esp;
00152     for(int i=15;i>-5;--i)
00153       {
00154         fprintf(frame_cond, "    %x esp[%d]= %x\n", (void*)(spp+i), i, (void*)*(spp+i));
00155         fflush(frame_cond);
00156       }
00157 #else
00158     while(ucp->uc_link)
00159       {
00160         fprintf(frame_cond, "   %p\n", (void *)ucp->uc_link);
00161         ucp = ucp->uc_link;
00162       }
00163 #endif
00164 #endif
00165   }
00166 }
00167 
00168 namespace 
00169 {
00170   // counters
00171   int samples_total=0;
00172   int samples_missing_framepointer=0;
00173 }
00174 
00175 // ---------------------------------------------------------------------
00176 // This is the stack trace discovery code from IgHookTrace.
00177 // ---------------------------------------------------------------------
00178 
00179 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
00180 # define HAVE_UNWIND_BACKTRACE 1
00181 #endif
00182 #if !defined MAP_ANONYMOUS && defined MAP_ANON
00183 # define MAP_ANONYMOUS MAP_ANON
00184 #endif
00185 
00186 #if HAVE_UNWIND_BACKTRACE
00187 struct IgHookTraceArgs { void **array; int count; int size; };
00188 extern "C" {
00189   typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
00190   struct _Unwind_Context;
00191   enum _Unwind_Reason_Code
00192     {
00193       _URC_NO_REASON = 0,
00194       _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
00195       _URC_FATAL_PHASE2_ERROR = 2,
00196       _URC_FATAL_PHASE1_ERROR = 3,
00197       _URC_NORMAL_STOP = 4,
00198       _URC_END_OF_STACK = 5,
00199       _URC_HANDLER_FOUND = 6,
00200       _URC_INSTALL_CONTEXT = 7,
00201       _URC_CONTINUE_UNWIND = 8
00202     };
00203 
00204   typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *);
00205   _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
00206   _Unwind_Ptr _Unwind_GetIP (_Unwind_Context *);
00207 }
00208 
00209 #ifndef __linux
00210 static _Unwind_Reason_Code
00211 GCCBackTrace (_Unwind_Context *context, void *arg)
00212 {
00213   IgHookTraceArgs *args = (IgHookTraceArgs *) arg;
00214   if (args->count >= 0 && args->count < args->size)
00215     args->array [args->count++] = (void *) _Unwind_GetIP (context);
00216   else
00217     return _URC_END_OF_STACK;
00218   return _URC_NO_REASON;
00219 }
00220 #endif
00221 #endif
00222 
00223 
00224 int stacktrace (void *addresses[], int nmax)
00225 {
00226   ++samples_total;
00227 #if __linux && __i386
00228 # if ! __x86_64__
00229 #  define PROBABLY_VSYSCALL_PAGE 0xffff0000
00230 # else
00231 #  define PROBABLY_VSYSCALL_PAGE 0xffffffff00000000
00232 # endif
00233   struct frame
00234   {
00235     // Normal frame.
00236     frame               *ebp;
00237     void                *eip;
00238     // Signal frame stuff, put in here by kernel.
00239     int         signo;
00240     siginfo_t   *info;
00241     ucontext_t  *ctx;
00242   };
00243   // register frame      *ebp __asm__ ("ebp");
00244   // register frame      *esp __asm__ ("esp");
00245   // use macros to avoid compiler warning.
00246 #define getBP(X)  asm ( "movl %%ebp,%0" : "=m" (X) )
00247 #define getSP(X)  asm ( "movl %%esp,%0" : "=m" (X) )
00248   register frame* ebp = 0;
00249   getBP(ebp);
00250   register frame* esp = 0;
00251   getSP(esp);
00252 
00253   frame               *fp = ebp;
00254   int                   depth = 0;
00255 
00256   // Add fake entry to be compatible with other methods
00257   if (depth < nmax) addresses[depth++] = reinterpret_cast<void *>(reinterpret_cast<unsigned long>(&stacktrace));
00258 
00259   // Top-most frame ends with null pointer; check the rest is reasonable
00260   while (depth < nmax && fp >= esp)
00261     {
00262       // Add this stack frame.  The return address is the
00263       // instruction immediately after the "call".  The call
00264       // instruction itself is 4 or 6 bytes; we guess 4.
00265       addresses[depth++] = (char *) fp->eip - 4;
00266 
00267       // Recognise signal frames.  We use two different methods
00268       // depending on the linux kernel version.
00269       //
00270       // For the "old" kernels / systems we check the instructions
00271       // at the caller's return address.  We take it to be a signal
00272       // frame if we find the signal return code sequence there
00273       // and the thread register context structure pointer:
00274       //
00275       //    mov $__NR_rt_sigreturn, %eax
00276       //    int 0x80
00277       //
00278       // For the "new" kernels / systems the operating system maps
00279       // a "vsyscall" page at a high address, and it may contain
00280       // either the above code, or use of the sysenter/sysexit
00281       // instructions.  We cannot poke at that page so we take the
00282       // the high address as an indication this is a signal frame.
00283       // (http://www.trilithium.com/johan/2005/08/linux-gate/)
00284       // (http://manugarg.googlepages.com/systemcallinlinux2_6.html)
00285       //
00286       // If we don't recognise the signal frame correctly here, we
00287       // lose one stack frame: signal delivery is not a call so
00288       // when the signal handler is entered, ebp still points to
00289       // what it was just before the signal.
00290       unsigned char *insn = (unsigned char *) fp->eip;
00291       if (insn
00292           && insn[0] == 0xb8 && insn[1] == __NR_rt_sigreturn
00293           && insn[5] == 0xcd && insn[6] == 0x80
00294           && fp->ctx)
00295         {   
00296           void *retip = (void *) fp->ctx->uc_mcontext.gregs [REG_EIP];
00297           if (depth < nmax) addresses[depth++] = retip;
00298 
00299           fp = (frame *) fp->ctx->uc_mcontext.gregs [REG_EBP];
00300           if (fp && (unsigned long) retip > PROBABLY_VSYSCALL_PAGE)
00301             {
00302               // __kernel_vsyscall stack on system call exit is
00303               // [0] %ebp, [1] %edx, [2] %ecx, [3] return address.
00304               if (depth < nmax) addresses[depth++] = ((void **) fp)[3];
00305               fp = fp->ebp;
00306 
00307               // It seems the frame _above_ __kernel_syscall (the
00308               // syscall implementation in libc, such as __mmap())
00309               // is essentially frame-pointer-less, so we should
00310               // find also the call above, but I don't know how
00311               // to determine how many arguments the system call
00312               // pushed on stack to call __kernel_syscall short
00313               // of interpreting the DWARF unwind information :-(
00314               // So we may lose one level of call stack here.
00315               ++samples_missing_framepointer;
00316             }
00317         }
00318 
00319       // Otherwise it's a normal frame, process through frame pointer.
00320       else
00321         fp = fp->ebp;
00322     }
00323 
00324   return depth;
00325 #elif __linux
00326   return backtrace (addresses, nmax);
00327 #elif HAVE_UNWIND_BACKTRACE
00328   if (nmax >= 1)
00329     {
00330       IgHookTraceArgs args = { addresses, 0, nmax };
00331       _Unwind_Backtrace (&GCCBackTrace, &args);
00332 
00333       if (args.count > 1 && args.array [args.count-1] == 0)
00334         args.count--;
00335 
00336       return args.count;
00337     }
00338   return 0;
00339 #else
00340   return 0;
00341 #endif
00342 }
00343 
00344 // ---------------------------------------------------------------------
00345 // The signal handler. We register this to handle the SIGPROF signal.
00346 // ---------------------------------------------------------------------
00347 
00348 extern "C" 
00349 {
00350   void sigFunc(int sig, siginfo_t* info, void* context)
00351   {
00352     SimpleProfiler* prof = SimpleProfiler::instance();
00353     void** arr = prof->tempStack();
00354     int nmax =   prof->tempStackSize();
00355     int stackdepth = stacktrace(arr, nmax);
00356 
00357     assert(stackdepth <= nmax);
00358 
00359     // We don't want the first three entries, because they always
00360     // contain information about the how the signal handler was
00361     // called, the signal handler, and the stacktrace function.
00362     prof->commitFrame(arr+3, arr + stackdepth);
00363   }
00364 }
00365 
00366 namespace
00367 {
00368   
00369 #if USE_SIGALTSTACK
00370   stack_t ss_area;
00371 #endif
00372 
00373   void setupTimer();
00374 
00375   void* setStacktop()
00376   {
00377 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
00378     throw std::logic_error("setStacktop not callable on 64 bit platform");
00379     return 0;
00380 #else
00381     const std::string target_name("__libc_start_main");
00382     unsigned int* ebp_reg;
00383     getBP(ebp_reg);
00384     unsigned int* ebp = (unsigned int*)(ebp_reg);
00385     unsigned int* top = (unsigned int*)(ebp);
00386 
00387     void* address_of_target = 0;
00388     const int max_stackdepth=30;
00389     void* sta[max_stackdepth];
00390 
00391     int depth = backtrace(sta, max_stackdepth);
00392     int cnt = depth;
00393     if (depth > 1) depth-=1;
00394 
00395     // find function one below main()
00396     Dl_info look;
00397     for (int i=0; i<cnt && !address_of_target; ++i)
00398       {
00399         if(dladdr(sta[i],&look)!=0)
00400           {
00401             if (look.dli_saddr && target_name==look.dli_sname)
00402               {
00403                 address_of_target = sta[i];
00404               }
00405           }
00406         else
00407           {
00408             // This isn't really an error; it just means the function
00409             // was not found by the dynamic loader. The function might
00410             // be one that is declared 'static', and is thus not
00411             // visible outside of its compilation unit.
00412             std::cerr << "setStacktop: no function information for " 
00413                       << sta[i] 
00414                       << "\n";
00415           }
00416       }
00417 
00418     if (address_of_target == 0)
00419       throw std::runtime_error("no main function found in stack");
00420 
00421     //fprintf(stderr,"depth=%d top=%8.8x\n",depth,top);
00422 
00423     // Now we walk toward the beginning of the stack until we find the
00424     // frame that is holding the return address of our target function.
00425 
00426     // depth is how many more frames there are to look at in the stack.
00427     // top is the frame we are currently looking at.
00428     // top+1 is the address to which the current frame will return.
00429     while (depth>0 && (void*)*(top+1) != address_of_target)
00430       {
00431         //fprintf(stderr,"depth=%d top=%8.8x func=%8.8x\n",depth,top,*(top+1));
00432         if (top<(unsigned int*)0x10) fprintf(stderr,"problem\n");
00433         top=(unsigned int*)(*top);
00434         --depth;
00435       };
00436 
00437     if (depth==0) 
00438       throw std::runtime_error("setStacktop: could not find stack bottom");
00439 
00440     // Now we have to move one frame more, to the frame of the target
00441     // function. We want the location in memory of this frame (not any
00442     // address stored in the frame, but the address of the frame
00443     // itself).
00444     top=(unsigned int*)(*top);
00445 
00446     return top;
00447 #endif
00448   }
00449 
00450   void setupTimer()
00451   {
00452 #if USE_SIGALTSTACK
00453     static vector<char> charbuffer(SIGSTKSZ);
00454     //ss_area.ss_sp = new char[SIGSTKSZ];
00455     ss_area.ss_sp = &charbuffer[0];
00456     ss_area.ss_flags = 0;
00457     ss_area.ss_size = SIGSTKSZ;
00458 #endif
00459     //static int is_set = 0;
00460     //if(is_set!=1) { ++is_set; return; }
00461     //else ++is_set;
00462 
00463     sigset_t myset,oldset;
00464     // all blocked for now
00465     MUST_BE_ZERO(sigfillset(&myset));
00466     MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK,&myset,&oldset));
00467 
00468 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64) 
00469 #if __linux
00470     // ignore all the RT signals
00471     struct sigaction tmpact;
00472     memset(&tmpact,0,sizeof(tmpact));
00473     tmpact.sa_handler = SIG_IGN;
00474 
00475     for(int num=SIGRTMIN;num<SIGRTMAX;++num)
00476       {
00477         MUST_BE_ZERO(sigaddset(&oldset,num));
00478         MUST_BE_ZERO(sigaction(num,&tmpact,NULL));
00479       }
00480 #endif
00481 #endif
00482 
00483 #if USE_SIGALTSTACK
00484     if(sigaltstack(&ss_area,0)!=0)
00485       {
00486         perror("sigaltstack failed for profile timer interrupt");
00487         abort();
00488       }
00489 #endif
00490 
00491     // set up my RT signal now
00492     struct sigaction act;
00493     memset(&act,0,sizeof(act));
00494     act.sa_sigaction = sigFunc;
00495     act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
00496 
00497     // get my signal number
00498     int mysig = SIGPROF;
00499 
00500     if(sigaction(mysig,&act,NULL)!=0)
00501       {
00502         perror("sigaction failed");
00503         abort();
00504       }
00505 
00506     // Turn off handling of SIGSEGV signal
00507     memset(&act,0,sizeof(act));
00508     act.sa_handler = SIG_DFL;
00509 
00510     if (sigaction(SIGSEGV, &act, NULL) != 0)
00511       {
00512         perror("sigaction failed");
00513         abort();
00514       }
00515 
00516     struct rlimit limits;
00517     if (getrlimit(RLIMIT_CORE, &limits) != 0)
00518       {
00519         perror("getrlimit failed");
00520         abort();
00521       }
00522     std::cerr << "core size limit (soft): " << limits.rlim_cur << '\n';
00523     std::cerr << "core size limit (hard): " << limits.rlim_max << '\n';
00524 
00525     struct itimerval newval;
00526     struct itimerval oldval;
00527 
00528     newval.it_interval.tv_sec  = 0;
00529     newval.it_interval.tv_usec = 10000;
00530     newval.it_value.tv_sec  = 0;
00531     newval.it_value.tv_usec = 10000;
00532 
00533     if(setitimer(ITIMER_PROF,&newval,&oldval)!=0)
00534       {
00535         perror("setitimer failed");
00536         abort();
00537       }
00538 
00539     // reenable the signals, including my interval timer
00540     MUST_BE_ZERO(sigdelset(&oldset,mysig));
00541     MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK,&oldset,0));
00542   }
00543 
00544 
00545   struct AdjustSigs
00546   {
00547     AdjustSigs()
00548     {
00549       sigset_t myset,oldset;
00550       // all blocked for now
00551       MUST_BE_ZERO(sigfillset(&myset));
00552       MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK,&myset,&oldset));
00553     
00554       // ignore all the RT signals
00555       struct sigaction tmpact;
00556       memset(&tmpact,0,sizeof(tmpact));
00557       tmpact.sa_handler = SIG_IGN;
00558     
00559 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64) 
00560 #if __linux
00561       for(int num=SIGRTMIN;num<SIGRTMAX;++num)
00562         {
00563           MUST_BE_ZERO(sigaddset(&oldset,num));
00564           MUST_BE_ZERO(sigaction(num,&tmpact,NULL));
00565         }
00566 #endif
00567 #endif
00568     
00569       MUST_BE_ZERO(sigaddset(&oldset,SIGPROF));
00570       MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK,&oldset,0));
00571     }
00572   };
00573 
00574   static AdjustSigs global_adjust;
00575 
00576 
00577 }
00578 
00579 SimpleProfiler* SimpleProfiler::inst_ = 0;
00580 boost::mutex SimpleProfiler::lock_;
00581 
00582 
00583 SimpleProfiler* SimpleProfiler::instance()
00584 {
00585   if(SimpleProfiler::inst_ == 0)
00586     {
00587       boost::mutex::scoped_lock sl(lock_);
00588       if(SimpleProfiler::inst_ == 0)
00589         {
00590           static SimpleProfiler p;
00591           SimpleProfiler::inst_ = &p;
00592         }
00593     }
00594   return SimpleProfiler::inst_;
00595 }
00596 
00597 SimpleProfiler::SimpleProfiler():
00598   frame_data_(10*1000*1000),
00599   tmp_stack_(1000),
00600   high_water_(&frame_data_[10*1000*1000-10*1000]),
00601   curr_(&frame_data_[0]),
00602   filename_(makeFileName()),
00603   fd_(open(filename_.c_str(), 
00604            O_RDWR|O_CREAT,
00605            S_IRWXU|S_IRGRP|S_IROTH|S_IWGRP|S_IWOTH)),
00606   installed_(false),
00607   running_(false),
00608   owner_(),
00609   stacktop_(setStacktop())
00610 {
00611   if (fd_ < 0) {
00612     std::ostringstream ost;
00613     ost << "failed to open profiler output file " << filename_;
00614     throw std::runtime_error(ost.str().c_str());
00615   }
00616   
00617   openCondFile();
00618 }
00619 
00620 SimpleProfiler::~SimpleProfiler()
00621 {
00622   if (running_)
00623     std::cerr << "Warning: the profile timer was not stopped,\n"
00624               << "profiling data in " << filename_
00625               << " is probably incomplete and will not be processed\n";
00626 
00627   closeCondFile();
00628 }
00629 
00630 void SimpleProfiler::commitFrame(void** first, void** last)
00631 {
00632   void** cnt_ptr = curr_; 
00633   *cnt_ptr = reinterpret_cast<void*>(std::distance(first,last));
00634   ++curr_;
00635   curr_ = std::copy(first,last,curr_);
00636   if(curr_ > high_water_) doWrite();
00637 }
00638 
00639 void SimpleProfiler::doWrite()
00640 {
00641   void** start = &frame_data_[0];
00642   if(curr_ == start) return;
00643   unsigned int cnt = std::distance(start,curr_) * sizeof(void*);
00644   unsigned int totwr=0;
00645 
00646   while (cnt>0 && (totwr=write(fd_,start,cnt)) != cnt) {
00647     if(totwr==0) 
00648       throw std::runtime_error("SimpleProfiler::doWrite wrote zero bytes");
00649     start+=(totwr/sizeof(void*));
00650     cnt-=totwr;
00651   }
00652 
00653   curr_ = &frame_data_[0];
00654 }
00655 
00656 void SimpleProfiler::start()
00657 {
00658 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
00659   throw std::logic_error("SimpleProfiler not available on 64 bit platform");
00660 #endif
00661   {
00662     boost::mutex::scoped_lock sl(lock_);
00663 
00664     if (installed_) {
00665       std::cerr << "Warning: second thread " << pthread_self()
00666                 << " requested the profiler timer and another thread\n"
00667                 << owner_ << "has already started it.\n"
00668                 << "Only one thread can do profiling at a time.\n"
00669                 << "This second thread will not be profiled.\n";
00670       return;
00671     }
00672     
00673     installed_ = true;
00674   }
00675 
00676   owner_ = pthread_self();
00677   setupTimer();
00678   running_ = true;
00679 }
00680 
00681 void SimpleProfiler::stop()
00682 {
00683   if(!installed_)
00684     {
00685       std::cerr << "SimpleProfiler::stop - no timer installed to stop\n";
00686       return;
00687     }
00688 
00689   if(owner_ != pthread_self())
00690     {
00691       std::cerr << "SimpleProfiler::stop - only owning thread can stop the timer\n";
00692       return;
00693     }
00694 
00695   if(!running_)
00696     {
00697       std::cerr << "SimpleProfiler::stop - no timer is running\n";
00698       return;
00699     }
00700 
00701   struct itimerval newval;
00702 
00703   newval.it_interval.tv_sec  = 0;
00704   newval.it_interval.tv_usec = 0;
00705   newval.it_value.tv_sec  = 0;
00706   newval.it_value.tv_usec = 0;
00707 
00708   if(setitimer(ITIMER_PROF,&newval,0)!=0)
00709     {
00710       perror("setitimer call failed - could not stop the timer");
00711     }
00712 
00713   running_=false;
00714   complete();
00715 }
00716 
00717 
00718 
00719 void SimpleProfiler::complete()
00720 {
00721   doWrite();
00722 
00723   if(lseek(fd_,0,SEEK_SET)<0)
00724     {
00725       std::cerr << "SimpleProfiler: could not seek to the start of the profile\n"
00726                 << " data file during completion.  Data will be lost.\n";
00727       return;
00728     }
00729 
00730   writeProfileData(fd_,filename_);
00731   write_maps();
00732 
00733   std::string totsname = makeFileName();
00734   totsname += "_sample_info";
00735   std::ofstream ost(totsname.c_str());
00736   
00737   ost << "samples_total " << samples_total << "\n"
00738       << "samples_missing_framepointer " << samples_missing_framepointer << "\n" ;
00739 }