CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
Namespaces | Macros | Typedefs | Functions | Variables
SimpleProfiler.cc File Reference
#include <pthread.h>
#include <unistd.h>
#include <dlfcn.h>
#include <cassert>
#include <cstdio>
#include <cstring>
#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

 INSTR
 

Macros

#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 sigFunc (int, siginfo_t *, void *)
 
int stacktrace (void *addresses[], int nmax)
 

Variables

int const REG_EBP = 6
 
int const REG_EIP = 14
 
int const REG_ESP = 7
 
byte const INSTR::RET = 0xc3
 

Macro Definition Documentation

#define _POSIX_C_SOURCE   199309

Definition at line 3 of file SimpleProfiler.cc.

#define DODEBUG   if(0) std::cerr

Definition at line 71 of file SimpleProfiler.cc.

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

Definition at line 65 of file SimpleProfiler.cc.

Referenced by stacktrace().

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

Definition at line 66 of file SimpleProfiler.cc.

Referenced by stacktrace().

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

Definition at line 64 of file SimpleProfiler.cc.

Function Documentation

void sigFunc ( int  ,
siginfo_t *  ,
void *   
)

Definition at line 326 of file SimpleProfiler.cc.

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

326  {
328  void** arr = prof->tempStack();
329  int nmax = prof->tempStackSize();
330  int stackdepth = stacktrace(arr, nmax);
331 
332  assert(stackdepth <= nmax);
333 
334  // We don't want the first three entries, because they always
335  // contain information about the how the signal handler was
336  // called, the signal handler, and the stacktrace function.
337  prof->commitFrame(arr + 3, arr + stackdepth);
338  }
void commitFrame(void **first, void **last)
static SimpleProfiler * instance()
void ** tempStack()
int stacktrace(void *addresses[], int nmax)
size_type tempStackSize()
int stacktrace ( void *  addresses[],
int  nmax 
)

Definition at line 207 of file SimpleProfiler.cc.

References evf::utils::eip, evf::utils::esp, getBP, getSP, info, REG_EBP, and REG_EIP.

Referenced by evf::FUEventProcessor::handleSignalSlave(), and sigFunc().

207  {
208  ++samples_total;
209 #if __linux && __i386
210 # if ! __x86_64__
211 # define PROBABLY_VSYSCALL_PAGE 0xffff0000
212 # else
213 # define PROBABLY_VSYSCALL_PAGE 0xffffffff00000000
214 # endif
215  struct frame {
216  // Normal frame.
217  frame* ebp;
218  void* eip;
219  // Signal frame stuff, put in here by kernel.
220  int* signo;
221  siginfo_t* info;
222  ucontext_t* ctx;
223  };
224  // register frame* ebp __asm__ ("ebp");
225  // register frame* esp __asm__ ("esp");
226  // use macros to avoid compiler warning.
227 #define getBP(X) asm ( "movl %%ebp,%0" : "=m" (X) )
228 #define getSP(X) asm ( "movl %%esp,%0" : "=m" (X) )
229  register frame* ebp = 0;
230  getBP(ebp);
231  register frame* esp = 0;
232  getSP(esp);
233 
234  frame* fp = ebp;
235  int depth = 0;
236 
237  // Add fake entry to be compatible with other methods
238  if(depth < nmax) addresses[depth++] = reinterpret_cast<void*>(reinterpret_cast<unsigned long>(&stacktrace));
239 
240  // Top-most frame ends with null pointer; check the rest is reasonable
241  while(depth < nmax && fp >= esp) {
242  // Add this stack frame. The return address is the
243  // instruction immediately after the "call". The call
244  // instruction itself is 4 or 6 bytes; we guess 4.
245  addresses[depth++] = (char*)fp->eip - 4;
246 
247  // Recognise signal frames. We use two different methods
248  // depending on the linux kernel version.
249  //
250  // For the "old" kernels / systems we check the instructions
251  // at the caller's return address. We take it to be a signal
252  // frame if we find the signal return code sequence there
253  // and the thread register context structure pointer:
254  //
255  // mov $__NR_rt_sigreturn, %eax
256  // int 0x80
257  //
258  // For the "new" kernels / systems the operating system maps
259  // a "vsyscall" page at a high address, and it may contain
260  // either the above code, or use of the sysenter/sysexit
261  // instructions. We cannot poke at that page so we take the
262  // the high address as an indication this is a signal frame.
263  // (http://www.trilithium.com/johan/2005/08/linux-gate/)
264  // (http://manugarg.googlepages.com/systemcallinlinux2_6.html)
265  //
266  // If we don't recognise the signal frame correctly here, we
267  // lose one stack frame: signal delivery is not a call so
268  // when the signal handler is entered, ebp still points to
269  // what it was just before the signal.
270  unsigned char* insn = (unsigned char*)fp->eip;
271  if(insn
272  && insn[0] == 0xb8 && insn[1] == __NR_rt_sigreturn
273  && insn[5] == 0xcd && insn[6] == 0x80
274  && fp->ctx) {
275  void* retip = (void*)fp->ctx->uc_mcontext.gregs [REG_EIP];
276  if(depth < nmax) addresses[depth++] = retip;
277 
278  fp = (frame*)fp->ctx->uc_mcontext.gregs [REG_EBP];
279  if(fp && (unsigned long) retip > PROBABLY_VSYSCALL_PAGE) {
280  // __kernel_vsyscall stack on system call exit is
281  // [0] %ebp, [1] %edx, [2] %ecx, [3] return address.
282  if(depth < nmax) addresses[depth++] = ((void**)fp)[3];
283  fp = fp->ebp;
284 
285  // It seems the frame _above_ __kernel_syscall (the
286  // syscall implementation in libc, such as __mmap())
287  // is essentially frame-pointer-less, so we should
288  // find also the call above, but I don't know how
289  // to determine how many arguments the system call
290  // pushed on stack to call __kernel_syscall short
291  // of interpreting the DWARF unwind information :-(
292  // So we may lose one level of call stack here.
293  ++samples_missing_framepointer;
294  }
295  }
296 
297  // Otherwise it's a normal frame, process through frame pointer.
298  else
299  fp = fp->ebp;
300  }
301 
302  return depth;
303 #elif __linux
304  return backtrace (addresses, nmax);
305 #elif HAVE_UNWIND_BACKTRACE
306  if(nmax >= 1) {
307  IgHookTraceArgs args = { addresses, 0, nmax };
308  _Unwind_Backtrace (&GCCBackTrace, &args);
309 
310  if(args.count > 1 && args.array [args.count-1] == 0)
311  args.count--;
312 
313  return args.count;
314  }
315  return 0;
316 #else
317  return 0;
318 #endif
319 }
#define getBP(X)
#define getSP(X)
int const REG_EBP
int const REG_EIP
dictionary args
int stacktrace(void *addresses[], int nmax)

Variable Documentation

int const REG_EBP = 6

Definition at line 76 of file SimpleProfiler.cc.

Referenced by stacktrace().

int const REG_EIP = 14

Definition at line 75 of file SimpleProfiler.cc.

Referenced by stacktrace().

int const REG_ESP = 7

Definition at line 77 of file SimpleProfiler.cc.