165 lines
4.4 KiB
C
165 lines
4.4 KiB
C
#include "timer.h"
|
|
|
|
#ifdef HAVE_TRACING
|
|
|
|
#ifdef ENABLE_EXECINFO
|
|
#include <execinfo.h>
|
|
#endif
|
|
#include <glib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define GREEN "\033[1;32m"
|
|
#define YELLOW "\033[1;33m"
|
|
#define RED "\033[1;31m"
|
|
#define BLUE "\033[1;34m"
|
|
#define RESET "\033[0m"
|
|
|
|
static GList *tracing_events = NULL;
|
|
static sig_atomic_t tracing = FALSE;
|
|
|
|
typedef struct TracingEvent {
|
|
void *address;
|
|
void *caller;
|
|
double time;
|
|
gboolean enter;
|
|
} TracingEvent;
|
|
|
|
void __attribute__ ((constructor)) init_tracing()
|
|
{
|
|
tracing_events = NULL;
|
|
tracing = FALSE;
|
|
}
|
|
|
|
void cleanup_tracing()
|
|
{
|
|
g_list_free_full(tracing_events, free);
|
|
tracing_events = NULL;
|
|
tracing = FALSE;
|
|
}
|
|
|
|
char *addr2name(void *func)
|
|
{
|
|
#ifdef ENABLE_EXECINFO
|
|
void *array[1];
|
|
array[0] = func;
|
|
char **strings = backtrace_symbols(array, 1);
|
|
char *result = strdup(strings[0] ? strings[0] : "??");
|
|
free(strings);
|
|
return result;
|
|
#else
|
|
const size_t buf_size = 32;
|
|
char *result = (char*) calloc(buf_size, 1);
|
|
snprintf(result, buf_size, "%p", func);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
void add_tracing_event(void *func, void *caller, gboolean enter)
|
|
{
|
|
TracingEvent *entry = (TracingEvent *)calloc(sizeof(TracingEvent), 1);
|
|
entry->address = func;
|
|
entry->caller = caller;
|
|
entry->time = get_time();
|
|
entry->enter = enter;
|
|
tracing_events = g_list_append(tracing_events, entry);
|
|
}
|
|
|
|
void start_tracing(void *root)
|
|
{
|
|
if (tracing_events)
|
|
cleanup_tracing();
|
|
add_tracing_event(root, NULL, TRUE);
|
|
tracing = TRUE;
|
|
}
|
|
|
|
void stop_tracing()
|
|
{
|
|
tracing = FALSE;
|
|
}
|
|
|
|
void __cyg_profile_func_enter(void *func, void *caller)
|
|
{
|
|
if (tracing)
|
|
add_tracing_event(func, caller, TRUE);
|
|
}
|
|
|
|
void __cyg_profile_func_exit(void *func, void *caller)
|
|
{
|
|
if (tracing)
|
|
add_tracing_event(func, caller, FALSE);
|
|
}
|
|
|
|
void print_tracing_events()
|
|
{
|
|
GList *stack = NULL;
|
|
int depth = 0;
|
|
double now = get_time();
|
|
for (GList *i = tracing_events; i; i = i->next) {
|
|
TracingEvent *e = (TracingEvent *)i->data;
|
|
if (e->enter) {
|
|
// Push a new function on the stack
|
|
for (int d = 0; d < depth; d++)
|
|
fprintf(stderr, "tint2: ");
|
|
char *name = addr2name(e->address);
|
|
char *caller = addr2name(e->caller);
|
|
fprintf(stderr,
|
|
"%s called from %s\n",
|
|
name,
|
|
caller);
|
|
stack = g_list_append(stack, e);
|
|
depth++;
|
|
} else {
|
|
// Pop a function from the stack, if matching, and print
|
|
if (stack) {
|
|
TracingEvent *old = (TracingEvent *)g_list_last(stack)->data;
|
|
if (old->address == e->address) {
|
|
depth--;
|
|
for (int d = 0; d < depth; d++)
|
|
fprintf(stderr, "tint2: ");
|
|
char *name = addr2name(e->address);
|
|
double duration = (e->time - old->time) * 1.0e3;
|
|
fprintf(stderr,
|
|
"-- %s exited after %.1f ms",
|
|
name,
|
|
duration);
|
|
if (duration >= 1.0) {
|
|
fprintf(stderr, YELLOW "tint2: ");
|
|
for (int d = 0; d < duration; d++) {
|
|
fprintf(stderr, "tint2: #");
|
|
}
|
|
fprintf(stderr, RESET);
|
|
}
|
|
fprintf(stderr, "tint2: \n");
|
|
free(name);
|
|
stack = g_list_delete_link(stack, g_list_last(stack));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (stack) {
|
|
TracingEvent *old = (TracingEvent *)g_list_last(stack)->data;
|
|
depth--;
|
|
for (int d = 0; d < depth; d++)
|
|
fprintf(stderr, "tint2: ");
|
|
char *name = addr2name(old->address);
|
|
double duration = (now - old->time) * 1.0e3;
|
|
fprintf(stderr,
|
|
"-- %s exited after %.1f ms",
|
|
name,
|
|
duration);
|
|
if (duration >= 1.0) {
|
|
fprintf(stderr, YELLOW "tint2: ");
|
|
for (int d = 0; d < duration; d++) {
|
|
fprintf(stderr, "tint2: #");
|
|
}
|
|
fprintf(stderr, RESET);
|
|
}
|
|
fprintf(stderr, "tint2: \n");
|
|
free(name);
|
|
stack = g_list_delete_link(stack, g_list_last(stack));
|
|
}
|
|
}
|
|
|
|
#endif
|