2 #ifndef _POSIX_C_SOURCE
3 #define _POSIX_C_SOURCE 199309
9 # include <sys/syscall.h>
31 #include <sys/resource.h>
40 #ifndef __USE_POSIX199309
41 #error "SimpleProfile requires the definition of __USE_POSIX199309"
48 typedef unsigned char byte;
58 std::ostringstream ost;
59 ost <<
"profdata_" <<
p;
68 #define MUST_BE_ZERO(fun) if((fun)!=0) { perror("function failed"); abort(); }
69 #define getBP(X) asm ( "movl %%ebp,%0" : "=m" (X) )
70 #define getSP(X) asm ( "movl %%esp,%0" : "=m" (X) )
73 #define DODEBUG if(1) std::cerr
75 #define DODEBUG if(0) std::cerr
100 std::ostringstream strinput,stroutput;
101 strinput <<
"/proc/" << pid <<
"/maps";
102 stroutput <<
"profdata_" << pid <<
"_maps";
103 std::ifstream
input(strinput.str().c_str());
104 std::ofstream
output(stroutput.str().c_str());
106 while (getline(
input, line))
output << line <<
'\n';
111 FILE* frame_cond = 0;
116 filename +=
"_condfile";
117 frame_cond = fopen(filename.c_str(),
"w");
120 std::cerr <<
"bad open of profdata_condfile\n";
121 throw std::runtime_error(
"bad open");
125 void writeCond(
int code)
127 fwrite(&code,
sizeof(
int),1,frame_cond);
135 void dumpStack(
const char*
msg,
136 unsigned int*
esp,
unsigned int* ebp,
unsigned char*
eip,
139 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
140 throw std::logic_error(
"Cannot dumpStack on 64 bit build");
142 fprintf(frame_cond, msg);
145 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",
146 eip, eip[0], (
void *)ebp, (
void *)esp, ebp[0], ebp[1], ebp[2]);
151 unsigned int* spp =
esp;
152 for(
int i=15;
i>-5;--
i)
154 fprintf(frame_cond,
" %x esp[%d]= %x\n", (
void*)(spp+
i),
i, (
void*)*(spp+
i));
160 fprintf(frame_cond,
" %p\n", (
void *)ucp->uc_link);
172 int samples_missing_framepointer=0;
179 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
180 # define HAVE_UNWIND_BACKTRACE 1
182 #if !defined MAP_ANONYMOUS && defined MAP_ANON
183 # define MAP_ANONYMOUS MAP_ANON
186 #if HAVE_UNWIND_BACKTRACE
187 struct IgHookTraceArgs {
void **array;
int count;
int size; };
189 typedef unsigned _Unwind_Ptr
__attribute__((__mode__(__pointer__)));
190 struct _Unwind_Context;
191 enum _Unwind_Reason_Code
194 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
195 _URC_FATAL_PHASE2_ERROR = 2,
196 _URC_FATAL_PHASE1_ERROR = 3,
197 _URC_NORMAL_STOP = 4,
198 _URC_END_OF_STACK = 5,
199 _URC_HANDLER_FOUND = 6,
200 _URC_INSTALL_CONTEXT = 7,
201 _URC_CONTINUE_UNWIND = 8
204 typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *,
void *);
205 _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn,
void *);
206 _Unwind_Ptr _Unwind_GetIP (_Unwind_Context *);
210 static _Unwind_Reason_Code
211 GCCBackTrace (_Unwind_Context *context,
void *
arg)
213 IgHookTraceArgs *
args = (IgHookTraceArgs *) arg;
214 if (args->count >= 0 && args->count < args->size)
215 args->array [args->count++] = (
void *) _Unwind_GetIP (context);
217 return _URC_END_OF_STACK;
218 return _URC_NO_REASON;
227 #if __linux && __i386
229 # define PROBABLY_VSYSCALL_PAGE 0xffff0000
231 # define PROBABLY_VSYSCALL_PAGE 0xffffffff00000000
246 #define getBP(X) asm ( "movl %%ebp,%0" : "=m" (X) )
247 #define getSP(X) asm ( "movl %%esp,%0" : "=m" (X) )
248 register frame* ebp = 0;
250 register frame*
esp = 0;
257 if (depth < nmax) addresses[depth++] =
reinterpret_cast<void *
>(
reinterpret_cast<unsigned long>(&
stacktrace));
260 while (depth < nmax && fp >= esp)
265 addresses[depth++] = (
char *) fp->eip - 4;
290 unsigned char *insn = (
unsigned char *) fp->eip;
292 && insn[0] == 0xb8 && insn[1] == __NR_rt_sigreturn
293 && insn[5] == 0xcd && insn[6] == 0x80
296 void *retip = (
void *) fp->ctx->uc_mcontext.gregs [
REG_EIP];
297 if (depth < nmax) addresses[depth++] = retip;
299 fp = (frame *) fp->ctx->uc_mcontext.gregs [
REG_EBP];
300 if (fp && (
unsigned long) retip > PROBABLY_VSYSCALL_PAGE)
304 if (depth < nmax) addresses[depth++] = ((
void **) fp)[3];
315 ++samples_missing_framepointer;
326 return backtrace (addresses, nmax);
327 #elif HAVE_UNWIND_BACKTRACE
330 IgHookTraceArgs args = { addresses, 0, nmax };
331 _Unwind_Backtrace (&GCCBackTrace, &args);
333 if (args.count > 1 && args.array [args.count-1] == 0)
357 assert(stackdepth <= nmax);
377 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
378 throw std::logic_error(
"setStacktop not callable on 64 bit platform");
381 const std::string target_name(
"__libc_start_main");
382 unsigned int* ebp_reg;
384 unsigned int* ebp = (
unsigned int*)(ebp_reg);
385 unsigned int* top = (
unsigned int*)(ebp);
387 void* address_of_target = 0;
388 const int max_stackdepth=30;
389 void* sta[max_stackdepth];
391 int depth = backtrace(sta, max_stackdepth);
393 if (depth > 1) depth-=1;
397 for (
int i=0;
i<cnt && !address_of_target; ++
i)
399 if(dladdr(sta[
i],&look)!=0)
401 if (look.dli_saddr && target_name==look.dli_sname)
403 address_of_target = sta[
i];
412 std::cerr <<
"setStacktop: no function information for "
418 if (address_of_target == 0)
419 throw std::runtime_error(
"no main function found in stack");
429 while (depth>0 && (
void*)*(top+1) != address_of_target)
432 if (top<(
unsigned int*)0x10) fprintf(stderr,
"problem\n");
433 top=(
unsigned int*)(*top);
438 throw std::runtime_error(
"setStacktop: could not find stack bottom");
444 top=(
unsigned int*)(*top);
453 static vector<char> charbuffer(SIGSTKSZ);
455 ss_area.ss_sp = &charbuffer[0];
456 ss_area.ss_flags = 0;
457 ss_area.ss_size = SIGSTKSZ;
463 sigset_t myset,oldset;
466 MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK,&myset,&oldset));
468 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
471 struct sigaction tmpact;
472 memset(&tmpact,0,
sizeof(tmpact));
473 tmpact.sa_handler = SIG_IGN;
484 if(sigaltstack(&ss_area,0)!=0)
486 perror(
"sigaltstack failed for profile timer interrupt");
492 struct sigaction act;
493 memset(&act,0,
sizeof(act));
495 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
500 if(sigaction(mysig,&act,
NULL)!=0)
502 perror(
"sigaction failed");
507 memset(&act,0,
sizeof(act));
508 act.sa_handler = SIG_DFL;
510 if (sigaction(SIGSEGV, &act,
NULL) != 0)
512 perror(
"sigaction failed");
516 struct rlimit limits;
517 if (getrlimit(RLIMIT_CORE, &limits) != 0)
519 perror(
"getrlimit failed");
522 std::cerr <<
"core size limit (soft): " << limits.rlim_cur <<
'\n';
523 std::cerr <<
"core size limit (hard): " << limits.rlim_max <<
'\n';
525 struct itimerval newval;
526 struct itimerval oldval;
528 newval.it_interval.tv_sec = 0;
529 newval.it_interval.tv_usec = 10000;
530 newval.it_value.tv_sec = 0;
531 newval.it_value.tv_usec = 10000;
533 if(setitimer(ITIMER_PROF,&newval,&oldval)!=0)
535 perror(
"setitimer failed");
549 sigset_t myset,oldset;
552 MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK,&myset,&oldset));
555 struct sigaction tmpact;
556 memset(&tmpact,0,
sizeof(tmpact));
557 tmpact.sa_handler = SIG_IGN;
559 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
574 static AdjustSigs global_adjust;
585 if(SimpleProfiler::inst_ == 0)
587 boost::mutex::scoped_lock sl(
lock_);
588 if(SimpleProfiler::inst_ == 0)
591 SimpleProfiler::inst_ = &
p;
598 frame_data_(10*1000*1000),
600 high_water_(&frame_data_[10*1000*1000-10*1000]),
601 curr_(&frame_data_[0]),
603 fd_(open(filename_.c_str(),
605 S_IRWXU|S_IRGRP|S_IROTH|S_IWGRP|S_IWOTH)),
609 stacktop_(setStacktop())
612 std::ostringstream ost;
613 ost <<
"failed to open profiler output file " <<
filename_;
614 throw std::runtime_error(ost.str().c_str());
623 std::cerr <<
"Warning: the profile timer was not stopped,\n"
625 <<
" is probably incomplete and will not be processed\n";
632 void** cnt_ptr =
curr_;
633 *cnt_ptr =
reinterpret_cast<void*
>(std::distance(first,last));
642 if(
curr_ == start)
return;
643 unsigned int cnt = std::distance(start,
curr_) *
sizeof(
void*);
644 unsigned int totwr=0;
646 while (cnt>0 && (totwr=write(
fd_,start,cnt)) != cnt) {
648 throw std::runtime_error(
"SimpleProfiler::doWrite wrote zero bytes");
649 start+=(totwr/
sizeof(
void*));
658 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
659 throw std::logic_error(
"SimpleProfiler not available on 64 bit platform");
662 boost::mutex::scoped_lock sl(
lock_);
665 std::cerr <<
"Warning: second thread " << pthread_self()
666 <<
" requested the profiler timer and another thread\n"
667 <<
owner_ <<
"has already started it.\n"
668 <<
"Only one thread can do profiling at a time.\n"
669 <<
"This second thread will not be profiled.\n";
685 std::cerr <<
"SimpleProfiler::stop - no timer installed to stop\n";
689 if(
owner_ != pthread_self())
691 std::cerr <<
"SimpleProfiler::stop - only owning thread can stop the timer\n";
697 std::cerr <<
"SimpleProfiler::stop - no timer is running\n";
701 struct itimerval newval;
703 newval.it_interval.tv_sec = 0;
704 newval.it_interval.tv_usec = 0;
705 newval.it_value.tv_sec = 0;
706 newval.it_value.tv_usec = 0;
708 if(setitimer(ITIMER_PROF,&newval,0)!=0)
710 perror(
"setitimer call failed - could not stop the timer");
723 if(lseek(
fd_,0,SEEK_SET)<0)
725 std::cerr <<
"SimpleProfiler: could not seek to the start of the profile\n"
726 <<
" data file during completion. Data will be lost.\n";
734 totsname +=
"_sample_info";
735 std::ofstream ost(totsname.c_str());
737 ost <<
"samples_total " << samples_total <<
"\n"
738 <<
"samples_missing_framepointer " << samples_missing_framepointer <<
"\n" ;
std::string makeFileName(const std::string &base, int num)
class Geom::OnePiRange __attribute__
static boost::mutex mutex
void commitFrame(void **first, void **last)
static SimpleProfiler * inst_
static boost::mutex lock_
static SimpleProfiler * instance()
#define MUST_BE_ZERO(fun)
int stacktrace(void *addresses[], int nmax)
perl if(1 lt scalar(@::datatypes))
void writeProfileData(int fd, const std::string &prefix)
void sigFunc(int sig, siginfo_t *info, void *context)
size_type tempStackSize()
tuple size
Write out results.