embox

Форк
0
310 строк · 7.8 Кб
1
/**
2
 * @file
3
 * @brief TODO
4
 *
5
 * @date 18.03.2012
6
 * @author Alina Kramar
7
 * @author Denis Deryugin
8
 */
9

10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <string.h>
13
#include <stdbool.h>
14
#include <errno.h>
15

16
#include <hal/context.h>
17

18
#include <lib/libds/array.h>
19
#include <util/location.h>
20
#include <lib/libds/hashtable.h>
21

22
#include <mem/misc/pool.h>
23

24
#include <debug/symbol.h>
25

26
#include <kernel/time/clock_source.h>
27
#include <kernel/time/ktime.h>
28
#include <kernel/time/itimer.h>
29

30
#include <profiler/tracing/trace.h>
31

32
#include <embox/unit.h>
33
#include "cyg_profile.h"
34

35
EMBOX_UNIT_INIT(instrument_profiling_init);
36

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);
41

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);
46

47
POOL_DEF(tb_ht_pool, struct hashtable_item, FUNC_QUANTITY);
48

49
/* This variable contains current profiling mode (see profiler/tracing/trace.h) */
50
static profiling_mode p_mode;
51
profiling_mode get_profiling_mode(void) {
52
	return p_mode;
53
}
54
void set_profiling_mode(profiling_mode new_mode) {
55
	p_mode = new_mode;
56
	return;
57
}
58

59
void cyg_tracing_profiler_enter(void *func, void *caller) {
60
	/* This function is for instrument profiling. It is being called just before
61
	 * every call of instrumented funcion.
62
	 * You can try to get more info by searching for "-finstrument-functions" GCC flag
63
	 */
64
	if (get_profiling_mode() == CYG_PROFILING) {
65
		set_profiling_mode(DISABLED);
66
		trace_block_func_enter(func);
67
		set_profiling_mode(CYG_PROFILING);
68
	}
69
}
70

71
void cyg_tracing_profiler_exit(void *func, void *caller) {
72
	/* This function is for instrument profiling. It is being called after every
73
	 * exit from instrumented funcion.
74
	 * You can try to get more info by searching for "-finstrument-functions" GCC flag
75
	 */
76
	 if (get_profiling_mode() == CYG_PROFILING) {
77
		set_profiling_mode(DISABLED);
78
		trace_block_func_exit(func);
79
		set_profiling_mode(CYG_PROFILING);
80
	}
81
}
82

83
/* Functions for hash */
84

85
static size_t get_trace_block_hash(void *key) {
86
	/* trace_block hash is just the pointer, beacuse
87
	 * it is unique for every functions, and there must be
88
	 * one block for one funcion.
89
	 */
90
	return (size_t) key;
91
}
92

93
static int cmp_trace_blocks(void *key1, void *key2) {
94
	/* trace_block hash is just the pointer, beacuse
95
	 * it is unique for every functions, and there must be
96
	 * one block for one funcion.
97
	 * So it is enough to compare those pointers.
98
	 */
99

100
	return 1 - (key1 == key2);
101
}
102

103
/* Hashtable to keep all dynamically generated trace_blocks */
104
HASHTABLE_DEF(tbhash_full,
105
		FUNC_QUANTITY * sizeof(struct __trace_block),
106
		get_trace_block_hash,
107
		cmp_trace_blocks);
108

109
static struct hashtable *tbhash = &tbhash_full;
110

111
static int **prev_key;
112

113
/* Global clock_source to keep all trace_block consistent */
114
static struct clock_source *tb_cs = NULL;
115

116
void __tracepoint_handle(struct __trace_point *tp) {
117
	if (tp->active) {
118
		tp->count++;
119
	}
120
}
121

122
void trace_block_enter(struct __trace_block *tb) {
123
	/* Necessary actions to capture information on trace_block enter */
124
	time64_t cur_time;
125
	struct tb_time *t;
126
	if (tb->active && tb_cs) {
127
		tb->count++;
128
		tb->depth++;
129
		cur_time = tb_cs->counter_device->read(tb_cs);
130

131
		t = (struct tb_time*) pool_alloc (&st_pool);
132
		if (t) {assert(t != NULL);
133
		t->next = tb->time_list_head;
134
		t->time = cur_time;
135
		tb->time_list_head = t; }
136
	}
137
}
138

139
void trace_block_leave(struct __trace_block *tb) {
140
	/* Necessary actions to capture information on trace_block exit */
141
	time64_t cur_time;
142
	struct tb_time *p;
143
	if (tb->active && tb_cs) {
144

145
		/* When cyg_profiling was enabled during trace_block,
146
		 * tb_leave may occur without tb_enter */
147
		if (tb->depth == 0)
148
			return;
149

150
		tb->depth--;
151

152
		cur_time = tb_cs->counter_device->read(tb_cs);
153

154
		p = tb->time_list_head;
155
		if (p) {
156
		assert(p != NULL);
157

158
		cur_time -= tb->time_list_head->time;
159
		cur_time = cur_time > 0 ? cur_time : 0;
160
		tb->time += cur_time;
161

162
		if (tb->max_time < cur_time)
163
			tb->max_time = cur_time;
164

165
		tb->time_list_head = p->next;
166
		pool_free(&st_pool, p); }
167
	}
168
}
169

170
time64_t trace_block_get_time(struct __trace_block *tb) {
171
	return 0;
172
	//return tb->time;
173
}
174

175
int trace_point_get_value(struct __trace_point *tp) {
176
	return tp->count;
177
}
178

179
struct __trace_point *trace_point_get_by_name(const char *name) {
180
	struct __trace_point *tp;
181

182
	array_spread_nullterm_foreach(tp, __trace_points_array)
183
	{
184
		if (!strcmp(tp->name, name)) {
185
			return tp;
186
		}
187
	}
188

189
	return NULL;
190
}
191

192
/* Functions for debug output */
193

194
void print_trace_block_info(struct __trace_block *tb) {
195
	/* Printing information about trace_block */
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");
200
}
201

202
/* It is assumed that there are traceblocks for every function
203
 * with trace_block_enter just after function call and
204
 * trace_block_exit just before function exit */
205

206
void trace_block_func_enter(void *func) {
207
	/* Function for auto-generated trace_blocks
208
	 * It has to find appropriate trace_block in hash_table
209
	 * or to generate new one
210
	 *	Args: void *func - pointer to functions that is about to enter
211
	 */
212
	struct __trace_block *tb = NULL;
213

214
	tb = hashtable_get(tbhash, func);
215
	if (!tb) {
216
		struct hashtable_item *ht_item;
217
		/* Lazy traceblock initialization.
218
		 * Func name and func location will be retrieved somewhere else,
219
		 * for example, in "trace_blocks -n" shell command. */
220

221
		tb = (struct __trace_block*) pool_alloc (&tb_pool);
222

223
		tb->func = func;
224
		tb->time = tb->max_time = tb->count = tb->depth = 0;
225
		tb->time_list_head = NULL;
226
		tb->active = true;
227
		tb->is_entered = false;
228

229

230
		ht_item = pool_alloc(&tb_ht_pool);
231
		ht_item = hashtable_item_init(ht_item, func, tb);
232
		hashtable_put(tbhash, ht_item);
233
	}
234

235
	trace_block_enter(tb);
236
}
237

238
void trace_block_func_exit(void *func) {
239
	/* Function for auto-generated trace_blocks
240
	 * It has to do all changes according to trace_block_leave
241
	 *	Args: void *func - pointer to functions that just exited
242
	 */
243
	struct __trace_block *tb;
244
	if (!tbhash) {
245
		return;
246
	}
247
	tb = hashtable_get(tbhash, func);
248
	if (tb) {
249
		trace_block_leave(tb);
250
	}
251
}
252

253
struct __trace_block *auto_profile_tb_first(void){
254
	/* Get the pointer to the first trace_block in trace_block hash table */
255
	if (!tbhash)
256
		return NULL;
257
	prev_key = hashtable_get_key_first(tbhash);
258
	return (struct __trace_block *) hashtable_get(tbhash, *prev_key);
259
}
260

261

262
struct __trace_block *auto_profile_tb_next(struct __trace_block *prev){
263
	/* Getting the pointer to the next trace_block
264
	 *	Args:	*prev - pointer to previous trace_block
265
	 */
266
	prev_key = hashtable_get_key_next(tbhash, prev_key);
267
	return (struct __trace_block *) hashtable_get(tbhash, *prev_key);
268
}
269

270
static int instrument_profiling_init(void) {
271
	set_profiling_mode(DISABLED);
272

273
	tb_cs = clock_source_get_best(CS_WITHOUT_IRQ);
274

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);
279

280
	return 0;
281
}
282

283
long long get_current_tb_resolution(void) {
284
	if (tb_cs && tb_cs->counter_device)
285
		return tb_cs->counter_device->cycle_hz;
286
	else
287
		return 1;
288
}
289

290
void trace_block_hashtable_init(void) {
291
	/* Initializing trace_block hash table */
292
	profiling_mode c = get_profiling_mode();
293
	struct __trace_block *tb1, *tb2;
294
	struct hashtable_item *ht_item;
295

296
	set_profiling_mode(DISABLED);
297

298
	tb1 = auto_profile_tb_first();
299
	while (tb1) {
300
		pool_free(&tb_pool, tb1);
301
		tb2 = tb1;
302
		tb1 = auto_profile_tb_next(tb1);
303
		ht_item = hashtable_del(tbhash, tb2->func);
304
		pool_free(&tb_ht_pool, ht_item);
305
	}
306

307
	tb_cs = clock_source_get_best(CS_WITHOUT_IRQ);
308

309
	set_profiling_mode(c);
310
}
311

312

313

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.