16
#include <hal/context.h>
18
#include <lib/libds/array.h>
19
#include <util/location.h>
20
#include <lib/libds/hashtable.h>
22
#include <mem/misc/pool.h>
24
#include <debug/symbol.h>
26
#include <kernel/time/clock_source.h>
27
#include <kernel/time/ktime.h>
28
#include <kernel/time/itimer.h>
30
#include <profiler/tracing/trace.h>
32
#include <embox/unit.h>
33
#include "cyg_profile.h"
35
EMBOX_UNIT_INIT(instrument_profiling_init);
37
ARRAY_SPREAD_DEF_TERMINATED(struct __trace_point *,
38
__trace_points_array, NULL);
39
ARRAY_SPREAD_DEF_TERMINATED(struct __trace_block *,
40
__trace_blocks_array, NULL);
42
POOL_DEF(tb_pool, struct __trace_block, FUNC_QUANTITY);
43
POOL_DEF(itimer_pool, struct itimer, FUNC_QUANTITY);
44
POOL_DEF(key_pool, int, FUNC_QUANTITY);
45
POOL_DEF(st_pool, struct tb_time, TB_MAX_DEPTH);
47
POOL_DEF(tb_ht_pool, struct hashtable_item, FUNC_QUANTITY);
50
static profiling_mode p_mode;
51
profiling_mode get_profiling_mode(void) {
54
void set_profiling_mode(profiling_mode new_mode) {
59
void cyg_tracing_profiler_enter(void *func, void *caller) {
64
if (get_profiling_mode() == CYG_PROFILING) {
65
set_profiling_mode(DISABLED);
66
trace_block_func_enter(func);
67
set_profiling_mode(CYG_PROFILING);
71
void cyg_tracing_profiler_exit(void *func, void *caller) {
76
if (get_profiling_mode() == CYG_PROFILING) {
77
set_profiling_mode(DISABLED);
78
trace_block_func_exit(func);
79
set_profiling_mode(CYG_PROFILING);
85
static size_t get_trace_block_hash(void *key) {
93
static int cmp_trace_blocks(void *key1, void *key2) {
100
return 1 - (key1 == key2);
104
HASHTABLE_DEF(tbhash_full,
105
FUNC_QUANTITY * sizeof(struct __trace_block),
106
get_trace_block_hash,
109
static struct hashtable *tbhash = &tbhash_full;
111
static int **prev_key;
114
static struct clock_source *tb_cs = NULL;
116
void __tracepoint_handle(struct __trace_point *tp) {
122
void trace_block_enter(struct __trace_block *tb) {
126
if (tb->active && tb_cs) {
129
cur_time = tb_cs->counter_device->read(tb_cs);
131
t = (struct tb_time*) pool_alloc (&st_pool);
132
if (t) {assert(t != NULL);
133
t->next = tb->time_list_head;
135
tb->time_list_head = t; }
139
void trace_block_leave(struct __trace_block *tb) {
143
if (tb->active && tb_cs) {
152
cur_time = tb_cs->counter_device->read(tb_cs);
154
p = tb->time_list_head;
158
cur_time -= tb->time_list_head->time;
159
cur_time = cur_time > 0 ? cur_time : 0;
160
tb->time += cur_time;
162
if (tb->max_time < cur_time)
163
tb->max_time = cur_time;
165
tb->time_list_head = p->next;
166
pool_free(&st_pool, p); }
170
time64_t trace_block_get_time(struct __trace_block *tb) {
175
int trace_point_get_value(struct __trace_point *tp) {
179
struct __trace_point *trace_point_get_by_name(const char *name) {
180
struct __trace_point *tp;
182
array_spread_nullterm_foreach(tp, __trace_points_array)
184
if (!strcmp(tp->name, name)) {
194
void print_trace_block_info(struct __trace_block *tb) {
196
printf("Trace block info: %p %s\n", tb, tb->name);
197
printf("Time counter pointer:\n");
198
printf("Active: %s\nIs entered: %s\n", tb->active ? "YES" : "NO",
199
tb->is_entered ? "YES" : "NO");
206
void trace_block_func_enter(void *func) {
212
struct __trace_block *tb = NULL;
214
tb = hashtable_get(tbhash, func);
216
struct hashtable_item *ht_item;
221
tb = (struct __trace_block*) pool_alloc (&tb_pool);
224
tb->time = tb->max_time = tb->count = tb->depth = 0;
225
tb->time_list_head = NULL;
227
tb->is_entered = false;
230
ht_item = pool_alloc(&tb_ht_pool);
231
ht_item = hashtable_item_init(ht_item, func, tb);
232
hashtable_put(tbhash, ht_item);
235
trace_block_enter(tb);
238
void trace_block_func_exit(void *func) {
243
struct __trace_block *tb;
247
tb = hashtable_get(tbhash, func);
249
trace_block_leave(tb);
253
struct __trace_block *auto_profile_tb_first(void){
257
prev_key = hashtable_get_key_first(tbhash);
258
return (struct __trace_block *) hashtable_get(tbhash, *prev_key);
262
struct __trace_block *auto_profile_tb_next(struct __trace_block *prev){
266
prev_key = hashtable_get_key_next(tbhash, prev_key);
267
return (struct __trace_block *) hashtable_get(tbhash, *prev_key);
270
static int instrument_profiling_init(void) {
271
set_profiling_mode(DISABLED);
273
tb_cs = clock_source_get_best(CS_WITHOUT_IRQ);
275
ARRAY_SPREAD_DECLARE(cyg_func, __cyg_handler_enter_array);
276
ARRAY_SPREAD_DECLARE(cyg_func, __cyg_handler_exit_array);
277
ARRAY_SPREAD_ADD(__cyg_handler_enter_array, &cyg_tracing_profiler_enter);
278
ARRAY_SPREAD_ADD(__cyg_handler_exit_array, &cyg_tracing_profiler_exit);
283
long long get_current_tb_resolution(void) {
284
if (tb_cs && tb_cs->counter_device)
285
return tb_cs->counter_device->cycle_hz;
290
void trace_block_hashtable_init(void) {
292
profiling_mode c = get_profiling_mode();
293
struct __trace_block *tb1, *tb2;
294
struct hashtable_item *ht_item;
296
set_profiling_mode(DISABLED);
298
tb1 = auto_profile_tb_first();
300
pool_free(&tb_pool, tb1);
302
tb1 = auto_profile_tb_next(tb1);
303
ht_item = hashtable_del(tbhash, tb2->func);
304
pool_free(&tb_ht_pool, ht_item);
307
tb_cs = clock_source_get_best(CS_WITHOUT_IRQ);
309
set_profiling_mode(c);