![]() |
![]() |
#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 () |
void * | setStacktop () |
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 _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 | ( | X | ) | asm ( "movl %%ebp,%0" : "=m" (X) ) |
#define getSP | ( | X | ) | 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().
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().
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 }
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 }
Definition at line 118 of file SimpleProfiler.cc.
00119 { 00120 fwrite(&code,sizeof(int),1,frame_cond); 00121 }
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.
Definition at line 75 of file SimpleProfiler.cc.
Referenced by stacktrace(), and IgHookTrace::stacktrace().
Definition at line 74 of file SimpleProfiler.cc.
Referenced by stacktrace(), and IgHookTrace::stacktrace().
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.