CMS 3D CMS Logo

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