diff --git a/src/lib/eina/eina_debug_bt.c b/src/lib/eina/eina_debug_bt.c index 68083e271b..61a550bd25 100644 --- a/src/lib/eina/eina_debug_bt.c +++ b/src/lib/eina/eina_debug_bt.c @@ -30,14 +30,15 @@ static Eina_Semaphore _wait_for_bts_sem; -// _bt_buf[0] is always for mainloop, 1 + is for extra threads static void ***_bt_buf; static int *_bt_buf_len; static struct timespec *_bt_ts; static int *_bt_cpu; +static int _bt_threads_nb; /* Used by trace timer */ static double _trace_t0 = 0.0; +static Eina_Debug_Timer *_timer = NULL; static int _prof_get_op = EINA_DEBUG_OPCODE_INVALID; @@ -53,7 +54,7 @@ _eina_debug_dump_fhandle_bt(FILE *f, void **bt, int btlen) { file = NULL; offset = base = 0; - // we have little choice but to hgope/assume dladdr() doesn't alloc + // we have little choice but to hope/assume dladdr() doesn't alloc // anything here if ((dladdr(bt[i], &info)) && (info.dli_fname[0])) { @@ -91,52 +92,6 @@ _eina_debug_unwind_bt(void **bt, int max) return total; } -// this signal handler is called inside each and every thread when the -// thread gets a signal via pthread_kill(). this causes the thread to -// stop here inside this handler and "do something" then when this returns -// resume whatever it was doing like any signal handler -static void -_eina_debug_signal(int sig EINA_UNUSED, - siginfo_t *si EINA_UNUSED, - void *foo EINA_UNUSED) -{ - int i, slot = 0; - pthread_t self = pthread_self(); - clockid_t cid; - - // find which slot in the array of threads we have so we store info - // in the correct slot for us - if (self != _eina_debug_thread_mainloop) - { - for (i = 0; i < _eina_debug_thread_active_num; i++) - { - if (self == _eina_debug_thread_active[i].thread) - { - slot = i + 1; - goto found; - } - } - // we couldn't find out thread reference! help! - e_debug("EINA DEBUG ERROR: can't find thread slot!"); - eina_semaphore_release(&_wait_for_bts_sem, 1); - return; - } -found: - // store thread info like what cpu core we are on now (not reliable - // but hey - better than nothing), the amount of cpu time total - // we have consumed (it's cumulative so subtracing deltas can give - // you an average amount of cpu time consumed between now and the - // previous time we looked) and also a full backtrace - _bt_cpu[slot] = sched_getcpu(); - pthread_getcpuclockid(self, &cid); - clock_gettime(cid, &(_bt_ts[slot])); - _bt_buf_len[slot] = _eina_debug_unwind_bt(_bt_buf[slot], EINA_MAX_BT); - // now wake up the monitor to let them know we are done collecting our - // backtrace info - eina_semaphore_release(&_wait_for_bts_sem, 1); -} - - // a quick and dirty local time point getter func - not portable static inline double get_time(void) @@ -152,18 +107,25 @@ get_time(void) #endif } -static void -_eina_debug_collect_bt(pthread_t pth EINA_UNUSED) +static Eina_Debug_Error +_prof_get_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED) { - // this async signals the thread to switch to the deebug signal handler - // and collect a backtrace and other info from inside the thread - //pthread_kill(pth, SIG); + clockid_t cid; + int slot = eina_debug_thread_id_get(); + if (slot >= _bt_threads_nb) return EINA_DEBUG_OK; + _bt_cpu[slot] = sched_getcpu(); + pthread_getcpuclockid(pthread_self(), &cid); + clock_gettime(cid, &(_bt_ts[slot])); + _bt_buf_len[slot] = _eina_debug_unwind_bt(_bt_buf[slot], EINA_MAX_BT); + return EINA_DEBUG_OK; } static Eina_Bool _trace_cb(void *data) { static Eina_Debug_Packet_Header *hdr = NULL; + static int bts = 0; + int i; if (!hdr) { @@ -173,62 +135,39 @@ _trace_cb(void *data) hdr->opcode = _prof_get_op; } - eina_debug_dispatch(data, (void *)hdr); - return EINA_TRUE; -} - -static Eina_Debug_Error -_prof_get_cb(Eina_Debug_Session *session EINA_UNUSED, int cid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED) -{ - static int bts = 0; - int i; if (!_trace_t0) _trace_t0 = get_time(); - // take a lock on grabbing thread debug info like backtraces - eina_spinlock_take(&_eina_debug_thread_lock); + + _bt_threads_nb = _eina_debug_thread_active_num; // reset our "stack" of memory se use to dump thread info into _eina_debug_chunk_tmp_reset(); // get an array of pointers for the backtrace array for main + th - _bt_buf = _eina_debug_chunk_tmp_push - ((1 + _eina_debug_thread_active_num) * sizeof(void *)); + _bt_buf = _eina_debug_chunk_tmp_push(_bt_threads_nb * sizeof(void *)); if (!_bt_buf) goto err; // get an array of pointers for the timespec array for mainloop + th - _bt_ts = _eina_debug_chunk_tmp_push - ((1 + _eina_debug_thread_active_num) * sizeof(struct timespec)); + _bt_ts = _eina_debug_chunk_tmp_push(_bt_threads_nb * sizeof(struct timespec)); if (!_bt_ts) goto err; // get an array of pointers for the cpuid array for mainloop + th - _bt_cpu = _eina_debug_chunk_tmp_push - ((1 + _eina_debug_thread_active_num) * sizeof(int)); + _bt_cpu = _eina_debug_chunk_tmp_push(_bt_threads_nb * sizeof(int)); if (!_bt_cpu) goto err; - // now get an array of void pts for mainloop bt - _bt_buf[0] = _eina_debug_chunk_tmp_push(EINA_MAX_BT * sizeof(void *)); - if (!_bt_buf[0]) goto err; // get an array of void ptrs for each thread we know about for bt - for (i = 0; i < _eina_debug_thread_active_num; i++) + for (i = 0; i < _bt_threads_nb; i++) { - _bt_buf[i + 1] = _eina_debug_chunk_tmp_push(EINA_MAX_BT * sizeof(void *)); - if (!_bt_buf[i + 1]) goto err; + _bt_buf[i] = _eina_debug_chunk_tmp_push(EINA_MAX_BT * sizeof(void *)); + if (!_bt_buf[i]) goto err; } // get an array of ints to stor the bt len for mainloop + threads - _bt_buf_len = _eina_debug_chunk_tmp_push - ((1 + _eina_debug_thread_active_num) * sizeof(int)); - // collect bt from the mainloop - always there - _eina_debug_collect_bt(_eina_debug_thread_mainloop); + _bt_buf_len = _eina_debug_chunk_tmp_push(_bt_threads_nb * sizeof(int)); + // now collect per thread - for (i = 0; i < _eina_debug_thread_active_num; i++) - _eina_debug_collect_bt(_eina_debug_thread_active[i].thread); - // we're done probing. now collec all the "i'm done" msgs on the - // semaphore for every thread + mainloop - for (i = 0; i < (_eina_debug_thread_active_num + 1); i++) - eina_semaphore_lock(&_wait_for_bts_sem); - // we now have gotten all the data from all threadd + mainloop. + eina_debug_dispatch(data, (void *)hdr); + + // we now have gotten all the data from all threads // we can process it now as we see fit, so release thread lock - //// XXX: some debug so we can see the bt's we collect - will go - // for (i = 0; i < (_eina_debug_thread_active_num + 1); i++) - // { - // _eina_debug_dump_fhandle_bt(stderr, _bt_buf[i], _bt_buf_len[i]); - // } + for (i = 0; i < _eina_debug_thread_active_num; i++) + { + _eina_debug_dump_fhandle_bt(stderr, _bt_buf[i], _bt_buf_len[i]); + } err: - eina_spinlock_release(&_eina_debug_thread_lock); //// XXX: some debug just to see how well we perform - will go bts++; if (bts >= 10000) @@ -239,7 +178,7 @@ err: _trace_t0 = t; bts = 0; } - return EINA_DEBUG_OK; + return EINA_TRUE; } // profiling on with poll time gap as uint payload @@ -251,7 +190,7 @@ _prof_on_cb(Eina_Debug_Session *session, int cid EINA_UNUSED, void *buffer, int { memcpy(&time, buffer, 4); _trace_t0 = 0.0; - eina_debug_timer_add(time, _trace_cb, session); + _timer = eina_debug_timer_add(time, _trace_cb, session); } return EINA_DEBUG_OK; } @@ -259,7 +198,8 @@ _prof_on_cb(Eina_Debug_Session *session, int cid EINA_UNUSED, void *buffer, int static Eina_Debug_Error _prof_off_cb(Eina_Debug_Session *session EINA_UNUSED, int cid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED) { - eina_debug_timer_add(0, NULL, NULL); + eina_debug_timer_del(_timer); + _timer = NULL; return EINA_DEBUG_OK; }