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