Adapt bt stuff to Eina Debug signal infras

This commit is contained in:
Daniel Zaoui 2017-05-10 11:57:07 +03:00
parent 9fadbc00ad
commit 87e68e3ed0
1 changed files with 36 additions and 96 deletions

View File

@ -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;
}