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"
46 typedef unsigned char byte;
54 std::ostringstream ost;
55 ost <<
"profdata_" <<
p;
64 #define MUST_BE_ZERO(fun) if((fun) != 0) { perror("function failed"); abort(); }
65 #define getBP(X) asm ( "movl %%ebp,%0" : "=m" (X) )
66 #define getSP(X) asm ( "movl %%esp,%0" : "=m" (X) )
69 #define DODEBUG if(1) std::cerr
71 #define DODEBUG if(0) std::cerr
92 std::ostringstream strinput, stroutput;
93 strinput <<
"/proc/" << pid <<
"/maps";
94 stroutput <<
"profdata_" << pid <<
"_maps";
95 std::ifstream
input(strinput.str().c_str());
96 std::ofstream
output(stroutput.str().c_str());
103 FILE* frame_cond = 0;
105 void openCondFile() {
107 filename +=
"_condfile";
108 frame_cond = fopen(filename.c_str(),
"w");
109 if(frame_cond == 0) {
110 std::cerr <<
"bad open of profdata_condfile\n";
111 throw std::runtime_error(
"bad open");
115 void writeCond(
int code) {
116 fwrite(&code,
sizeof(
int), 1, frame_cond);
119 void closeCondFile() {
123 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
124 void dumpStack(
char const*,
unsigned int*,
unsigned int*,
unsigned char*, ucontext_t*) {
125 throw std::logic_error(
"Cannot dumpStack on 64 bit build");
128 void dumpStack(
char const*
msg,
129 unsigned int*
esp,
unsigned int* ebp,
unsigned char*
eip,
131 fprintf(frame_cond, msg);
134 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",
135 eip, eip[0], (
void*)ebp, (
void*)esp, ebp[0], ebp[1], ebp[2]);
139 unsigned int* spp =
esp;
140 for(
int i = 15;
i > -5; --
i) {
141 fprintf(frame_cond,
" %x esp[%d]= %x\n", (
void*)(spp +
i),
i, (
void*)*(spp +
i));
145 while(ucp->uc_link) {
146 fprintf(frame_cond,
" %p\n", (
void*)ucp->uc_link);
156 int samples_total = 0;
157 int samples_missing_framepointer = 0;
164 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
165 # define HAVE_UNWIND_BACKTRACE 1
167 #if !defined MAP_ANONYMOUS && defined MAP_ANON
168 # define MAP_ANONYMOUS MAP_ANON
171 #if HAVE_UNWIND_BACKTRACE
172 struct IgHookTraceArgs {
void** array;
int count;
int size; };
174 typedef unsigned _Unwind_Ptr
__attribute__((__mode__(__pointer__)));
175 struct _Unwind_Context;
176 enum _Unwind_Reason_Code
179 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
180 _URC_FATAL_PHASE2_ERROR = 2,
181 _URC_FATAL_PHASE1_ERROR = 3,
182 _URC_NORMAL_STOP = 4,
183 _URC_END_OF_STACK = 5,
184 _URC_HANDLER_FOUND = 6,
185 _URC_INSTALL_CONTEXT = 7,
186 _URC_CONTINUE_UNWIND = 8
189 typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context*,
void*);
190 _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn,
void*);
191 _Unwind_Ptr _Unwind_GetIP (_Unwind_Context*);
195 static _Unwind_Reason_Code
196 GCCBackTrace (_Unwind_Context* context,
void*
arg) {
197 IgHookTraceArgs*
args = (IgHookTraceArgs*)arg;
198 if(args->count >= 0 && args->count < args->size)
199 args->array [args->count++] = (
void*)_Unwind_GetIP (context);
201 return _URC_END_OF_STACK;
202 return _URC_NO_REASON;
209 #if __linux && __i386
211 # define PROBABLY_VSYSCALL_PAGE 0xffff0000
213 # define PROBABLY_VSYSCALL_PAGE 0xffffffff00000000
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;
231 register frame*
esp = 0;
238 if(depth < nmax) addresses[depth++] =
reinterpret_cast<void*
>(
reinterpret_cast<unsigned long>(&
stacktrace));
241 while(depth < nmax && fp >= esp) {
245 addresses[depth++] = (
char*)fp->eip - 4;
270 unsigned char* insn = (
unsigned char*)fp->eip;
272 && insn[0] == 0xb8 && insn[1] == __NR_rt_sigreturn
273 && insn[5] == 0xcd && insn[6] == 0x80
275 void* retip = (
void*)fp->ctx->uc_mcontext.gregs [
REG_EIP];
276 if(depth < nmax) addresses[depth++] = retip;
278 fp = (frame*)fp->ctx->uc_mcontext.gregs [
REG_EBP];
279 if(fp && (
unsigned long) retip > PROBABLY_VSYSCALL_PAGE) {
282 if(depth < nmax) addresses[depth++] = ((
void**)fp)[3];
293 ++samples_missing_framepointer;
304 return backtrace (addresses, nmax);
305 #elif HAVE_UNWIND_BACKTRACE
307 IgHookTraceArgs args = { addresses, 0, nmax };
308 _Unwind_Backtrace (&GCCBackTrace, &args);
310 if(args.count > 1 && args.array [args.count-1] == 0)
332 assert(stackdepth <= nmax);
349 void* setStacktop() {
350 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
351 throw std::logic_error(
"setStacktop not callable on 64 bit platform");
354 std::string consttarget_name(
"__libc_start_main");
355 unsigned int* ebp_reg;
357 unsigned int* ebp = (
unsigned int*)(ebp_reg);
358 unsigned int* top = (
unsigned int*)(ebp);
360 void* address_of_target = 0;
361 int const max_stackdepth = 30;
362 void* sta[max_stackdepth];
364 int depth = backtrace(sta, max_stackdepth);
366 if(depth > 1) depth -= 1;
370 for(
int i = 0;
i < cnt && !address_of_target; ++
i) {
371 if(dladdr(sta[
i], &look) != 0) {
372 if(look.dli_saddr && target_name == look.dli_sname) {
373 address_of_target = sta[
i];
380 std::cerr <<
"setStacktop: no function information for "
386 if(address_of_target == 0) {
387 throw std::runtime_error(
"no main function found in stack");
398 while(depth > 0 && (
void*)*(top + 1) != address_of_target) {
400 if(top < (
unsigned int*)0x10) fprintf(stderr,
"problem\n");
401 top = (
unsigned int*)(*top);
406 throw std::runtime_error(
"setStacktop: could not find stack bottom");
413 top = (
unsigned int*)(*top);
421 static vector<char> charbuffer(SIGSTKSZ);
423 ss_area.ss_sp = &charbuffer[0];
424 ss_area.ss_flags = 0;
425 ss_area.ss_size = SIGSTKSZ;
431 sigset_t myset, oldset;
434 MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK, &myset, &oldset));
436 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
439 struct sigaction tmpact;
440 memset(&tmpact, 0,
sizeof(tmpact));
441 tmpact.sa_handler = SIG_IGN;
443 for(
int num=SIGRTMIN;
num < SIGRTMAX; ++
num) {
451 if(sigaltstack(&ss_area, 0) != 0) {
452 perror(
"sigaltstack failed for profile timer interrupt");
458 struct sigaction act;
459 memset(&act, 0,
sizeof(act));
461 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
466 if(sigaction(mysig, &act,
NULL) != 0) {
467 perror(
"sigaction failed");
472 memset(&act, 0,
sizeof(act));
473 act.sa_handler = SIG_DFL;
475 if(sigaction(SIGSEGV, &act,
NULL) != 0) {
476 perror(
"sigaction failed");
480 struct rlimit limits;
481 if(getrlimit(RLIMIT_CORE, &limits) != 0) {
482 perror(
"getrlimit failed");
485 std::cerr <<
"core size limit (soft): " << limits.rlim_cur <<
'\n';
486 std::cerr <<
"core size limit (hard): " << limits.rlim_max <<
'\n';
488 struct itimerval newval;
489 struct itimerval oldval;
491 newval.it_interval.tv_sec = 0;
492 newval.it_interval.tv_usec = 10000;
493 newval.it_value.tv_sec = 0;
494 newval.it_value.tv_usec = 10000;
496 if(setitimer(ITIMER_PROF, &newval, &oldval) != 0) {
497 perror(
"setitimer failed");
509 sigset_t myset, oldset;
512 MUST_BE_ZERO(pthread_sigmask(SIG_SETMASK, &myset, &oldset));
515 struct sigaction tmpact;
516 memset(&tmpact, 0,
sizeof(tmpact));
517 tmpact.sa_handler = SIG_IGN;
519 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
521 for(
int num=SIGRTMIN;
num<SIGRTMAX; ++
num) {
533 static AdjustSigs global_adjust;
541 if(SimpleProfiler::inst_ == 0) {
542 boost::mutex::scoped_lock sl(
lock_);
543 if(SimpleProfiler::inst_ == 0) {
545 SimpleProfiler::inst_ = &
p;
552 frame_data_(10*1000*1000),
554 high_water_(&frame_data_[10*1000*1000-10*1000]),
555 curr_(&frame_data_[0]),
557 fd_(open(filename_.c_str(),
559 S_IRWXU|S_IRGRP|S_IROTH|S_IWGRP|S_IWOTH)),
563 stacktop_(setStacktop()) {
565 std::ostringstream ost;
566 ost <<
"failed to open profiler output file " <<
filename_;
567 throw std::runtime_error(ost.str().c_str());
574 std::cerr <<
"Warning: the profile timer was not stopped,\n"
576 <<
" is probably incomplete and will not be processed\n";
582 void** cnt_ptr =
curr_;
583 *cnt_ptr =
reinterpret_cast<void*
>(std::distance(first, last));
591 if(
curr_ == start)
return;
592 unsigned int cnt = std::distance(start,
curr_) *
sizeof(
void*);
593 unsigned int totwr = 0;
595 while(cnt>0 && (totwr =
write(
fd_, start, cnt)) != cnt) {
597 throw std::runtime_error(
"SimpleProfiler::doWrite wrote zero bytes");
598 start += (totwr/
sizeof(
void*));
605 #if defined(__x86_64__) || defined(__LP64__) || defined(_LP64)
607 throw std::logic_error(
"SimpleProfiler not available on 64 bit platform");
612 boost::mutex::scoped_lock sl(
lock_);
615 std::cerr <<
"Warning: second thread " << pthread_self()
616 <<
" requested the profiler timer and another thread\n"
617 <<
owner_ <<
"has already started it.\n"
618 <<
"Only one thread can do profiling at a time.\n"
619 <<
"This second thread will not be profiled.\n";
634 std::cerr <<
"SimpleProfiler::stop - no timer installed to stop\n";
638 if(
owner_ != pthread_self()) {
639 std::cerr <<
"SimpleProfiler::stop - only owning thread can stop the timer\n";
644 std::cerr <<
"SimpleProfiler::stop - no timer is running\n";
648 struct itimerval newval;
650 newval.it_interval.tv_sec = 0;
651 newval.it_interval.tv_usec = 0;
652 newval.it_value.tv_sec = 0;
653 newval.it_value.tv_usec = 0;
655 if(setitimer(ITIMER_PROF, &newval, 0) != 0) {
656 perror(
"setitimer call failed - could not stop the timer");
666 if(lseek(
fd_, 0, SEEK_SET) < 0) {
667 std::cerr <<
"SimpleProfiler: could not seek to the start of the profile\n"
668 <<
" data file during completion. Data will be lost.\n";
676 totsname +=
"_sample_info";
677 std::ofstream ost(totsname.c_str());
679 ost <<
"samples_total " << samples_total <<
"\n"
680 <<
"samples_missing_framepointer " << samples_missing_framepointer <<
"\n" ;
std::string makeFileName(const std::string &base, int num)
static boost::mutex mutex
void commitFrame(void **first, void **last)
static SimpleProfiler * inst_
static boost::mutex lock_
void sigFunc(int, siginfo_t *, void *)
static SimpleProfiler * instance()
#define MUST_BE_ZERO(fun)
int stacktrace(void *addresses[], int nmax)
void writeProfileData(int fd, const std::string &prefix)
size_type tempStackSize()
class Geom::Polar2Cartesian __attribute__
tuple size
Write out results.