1 #include "timer.h"
2 
3 #ifdef HAVE_TRACING
4 
5 #ifdef ENABLE_EXECINFO
6 #include <execinfo.h>
7 #endif
8 #include <glib.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #define GREEN "\033[1;32m"
14 #define YELLOW "\033[1;33m"
15 #define RED "\033[1;31m"
16 #define BLUE "\033[1;34m"
17 #define RESET "\033[0m"
18 
19 static GList *tracing_events = NULL;
20 static sig_atomic_t tracing = FALSE;
21 
22 typedef struct TracingEvent {
23     void *address;
24     void *caller;
25     double time;
26     gboolean enter;
27 } TracingEvent;
28 
init_tracing()29 void __attribute__ ((constructor)) init_tracing()
30 {
31     tracing_events = NULL;
32     tracing = FALSE;
33 }
34 
cleanup_tracing()35 void cleanup_tracing()
36 {
37     g_list_free_full(tracing_events, free);
38     tracing_events = NULL;
39     tracing = FALSE;
40 }
41 
addr2name(void * func)42 char *addr2name(void *func)
43 {
44 #ifdef ENABLE_EXECINFO
45     void *array[1];
46     array[0] = func;
47     char **strings = backtrace_symbols(array, 1);
48     char *result = strdup(strings[0] ? strings[0] : "??");
49     free(strings);
50     return result;
51 #else
52     const size_t buf_size = 32;
53     char *result = (char*) calloc(buf_size, 1);
54     snprintf(result, buf_size, "%p", func);
55     return result;
56 #endif
57 }
58 
add_tracing_event(void * func,void * caller,gboolean enter)59 void add_tracing_event(void *func, void *caller, gboolean enter)
60 {
61     TracingEvent *entry = (TracingEvent *)calloc(sizeof(TracingEvent), 1);
62     entry->address = func;
63     entry->caller = caller;
64     entry->time = get_time();
65     entry->enter = enter;
66     tracing_events = g_list_append(tracing_events, entry);
67 }
68 
start_tracing(void * root)69 void start_tracing(void *root)
70 {
71     if (tracing_events)
72         cleanup_tracing();
73     add_tracing_event(root, NULL, TRUE);
74     tracing = TRUE;
75 }
76 
stop_tracing()77 void stop_tracing()
78 {
79     tracing = FALSE;
80 }
81 
__cyg_profile_func_enter(void * func,void * caller)82 void __cyg_profile_func_enter(void *func, void *caller)
83 {
84     if (tracing)
85         add_tracing_event(func, caller, TRUE);
86 }
87 
__cyg_profile_func_exit(void * func,void * caller)88 void __cyg_profile_func_exit(void *func, void *caller)
89 {
90     if (tracing)
91         add_tracing_event(func, caller, FALSE);
92 }
93 
print_tracing_events()94 void print_tracing_events()
95 {
96     GList *stack = NULL;
97     int depth = 0;
98     double now = get_time();
99     for (GList *i = tracing_events; i; i = i->next) {
100         TracingEvent *e = (TracingEvent *)i->data;
101         if (e->enter) {
102             // Push a new function on the stack
103             for (int d = 0; d < depth; d++)
104                 fprintf(stderr, "tint2:  ");
105             char *name = addr2name(e->address);
106             char *caller = addr2name(e->caller);
107             fprintf(stderr,
108                     "%s called from %s\n",
109                     name,
110                     caller);
111             stack = g_list_append(stack, e);
112             depth++;
113         } else {
114             // Pop a function from the stack, if matching, and print
115             if (stack) {
116                 TracingEvent *old = (TracingEvent *)g_list_last(stack)->data;
117                 if (old->address == e->address) {
118                     depth--;
119                     for (int d = 0; d < depth; d++)
120                         fprintf(stderr, "tint2:  ");
121                     char *name = addr2name(e->address);
122                     double duration = (e->time - old->time) * 1.0e3;
123                     fprintf(stderr,
124                             "-- %s exited after %.1f ms",
125                             name,
126                             duration);
127                     if (duration >= 1.0) {
128                         fprintf(stderr, YELLOW "tint2:  ");
129                         for (int d = 0; d < duration; d++) {
130                             fprintf(stderr, "tint2: #");
131                         }
132                         fprintf(stderr, RESET);
133                     }
134                     fprintf(stderr, "tint2: \n");
135                     free(name);
136                     stack = g_list_delete_link(stack, g_list_last(stack));
137                 }
138             }
139         }
140     }
141     while (stack) {
142         TracingEvent *old = (TracingEvent *)g_list_last(stack)->data;
143         depth--;
144         for (int d = 0; d < depth; d++)
145             fprintf(stderr, "tint2:  ");
146         char *name = addr2name(old->address);
147         double duration = (now - old->time) * 1.0e3;
148         fprintf(stderr,
149                 "-- %s exited after %.1f ms",
150                 name,
151                 duration);
152         if (duration >= 1.0) {
153             fprintf(stderr, YELLOW "tint2:  ");
154             for (int d = 0; d < duration; d++) {
155                 fprintf(stderr, "tint2: #");
156             }
157             fprintf(stderr, RESET);
158         }
159         fprintf(stderr, "tint2: \n");
160         free(name);
161         stack = g_list_delete_link(stack, g_list_last(stack));
162     }
163 }
164 
165 #endif
166