b445142a |
1 | |
2 | #include <lttv/stats.h> |
3 | #include <ltt/facility.h> |
4 | #include <ltt/trace.h> |
5 | #include <ltt/event.h> |
6 | |
7 | GQuark |
8 | LTTV_STATS_PROCESS_UNKNOWN, |
9 | LTTV_STATS_PROCESSES, |
10 | LTTV_STATS_CPU, |
11 | LTTV_STATS_MODE_TYPES, |
12 | LTTV_STATS_MODES, |
13 | LTTV_STATS_SUBMODES, |
14 | LTTV_STATS_EVENT_TYPES, |
15 | LTTV_STATS_CPU_TIME, |
16 | LTTV_STATS_ELAPSED_TIME, |
17 | LTTV_STATS_EVENTS, |
18 | LTTV_STATS_EVENTS_COUNT; |
19 | |
20 | static GQuark |
21 | LTTV_STATS_BEFORE_HOOKS, |
22 | LTTV_STATS_AFTER_HOOKS; |
23 | |
24 | static void remove_all_processes(GHashTable *processes); |
25 | |
26 | static void |
27 | find_event_tree(LttvTracefileStats *tfcs, GQuark process, GQuark cpu, |
28 | GQuark mode, GQuark sub_mode, LttvAttribute **events_tree, |
29 | LttvAttribute **event_types_tree); |
30 | |
31 | static void |
32 | init(LttvTracesetStats *self, LttvTraceset *ts) |
33 | { |
34 | guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; |
35 | |
36 | LttvTraceContext *tc; |
37 | |
38 | LttvTraceStats *tcs; |
39 | |
40 | LttvTracefileContext *tfc; |
41 | |
42 | LttvTracefileStats *tfcs; |
43 | |
44 | LttTime timestamp = {0,0}; |
45 | |
46 | LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))-> |
47 | init((LttvTracesetContext *)self, ts); |
48 | |
49 | self->stats = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); |
50 | nb_trace = lttv_traceset_number(ts); |
51 | |
52 | for(i = 0 ; i < nb_trace ; i++) { |
53 | tcs = (LttvTraceStats *)tc = (LTTV_TRACESET_CONTEXT(self)->traces[i]); |
54 | tcs->stats = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); |
55 | |
56 | nb_control = ltt_trace_control_tracefile_number(tc->t); |
57 | nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t); |
58 | nb_tracefile = nb_control + nb_per_cpu; |
59 | for(j = 0 ; j < nb_tracefile ; j++) { |
60 | if(j < nb_control) { |
61 | tfcs = LTTV_TRACEFILE_STATS(tc->control_tracefiles[j]); |
62 | } |
63 | else { |
64 | tfcs = LTTV_TRACEFILE_STATS(tc->per_cpu_tracefiles[j - nb_control]); |
65 | } |
66 | |
67 | tfcs->stats = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); |
68 | find_event_tree(tfcs, LTTV_STATS_PROCESS_UNKNOWN, |
69 | tfcs->parent.cpu_name, LTTV_STATE_MODE_UNKNOWN, |
70 | LTTV_STATE_SUBMODE_UNKNOWN, &tfcs->current_events_tree, |
71 | &tfcs->current_event_types_tree); |
72 | } |
73 | } |
74 | } |
75 | |
76 | |
77 | static void |
78 | fini(LttvTracesetStats *self) |
79 | { |
80 | guint i, j, nb_trace, nb_tracefile; |
81 | |
82 | LttvTraceset *ts; |
83 | |
84 | LttvTraceContext *tc; |
85 | |
86 | LttvTraceStats *tcs; |
87 | |
88 | LttvTracefileContext *tfc; |
89 | |
90 | LttvTracefileStats *tfcs; |
91 | |
92 | LttTime timestamp = {0,0}; |
93 | |
94 | lttv_attribute_recursive_free(self->stats); |
95 | ts = self->parent.parent.ts; |
96 | nb_trace = lttv_traceset_number(ts); |
97 | |
98 | for(i = 0 ; i < nb_trace ; i++) { |
99 | tcs = (LttvTraceStats *)tc = (LTTV_TRACESET_CONTEXT(self)->traces[i]); |
100 | lttv_attribute_recursive_free(tcs->stats); |
101 | |
102 | nb_tracefile = ltt_trace_control_tracefile_number(tc->t); |
103 | for(j = 0 ; j < nb_tracefile ; j++) { |
104 | tfcs = (LttvTracefileStats *)tfc = tc->control_tracefiles[j]; |
105 | lttv_attribute_recursive_free(tfcs->stats); |
106 | tfcs->current_events_tree = NULL; |
107 | tfcs->current_event_types_tree = NULL; |
108 | } |
109 | |
110 | nb_tracefile = ltt_trace_per_cpu_tracefile_number(tc->t); |
111 | for(j = 0 ; j < nb_tracefile ; j++) { |
112 | tfcs = (LttvTracefileStats *)tfc = tc->per_cpu_tracefiles[j]; |
113 | lttv_attribute_recursive_free(tfcs->stats); |
114 | tfcs->current_events_tree = NULL; |
115 | tfcs->current_event_types_tree = NULL; |
116 | } |
117 | } |
118 | LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))-> |
119 | fini((LttvTracesetContext *)self); |
120 | } |
121 | |
122 | |
123 | static LttvTracesetContext * |
124 | new_traceset_context(LttvTracesetContext *self) |
125 | { |
126 | return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE, NULL)); |
127 | } |
128 | |
129 | |
130 | static LttvTraceContext * |
131 | new_trace_context(LttvTracesetContext *self) |
132 | { |
133 | return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE, NULL)); |
134 | } |
135 | |
136 | |
137 | static LttvTracefileContext * |
138 | new_tracefile_context(LttvTracesetContext *self) |
139 | { |
140 | return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE, NULL)); |
141 | } |
142 | |
143 | |
144 | static void |
145 | traceset_stats_instance_init (GTypeInstance *instance, gpointer g_class) |
146 | { |
147 | } |
148 | |
149 | |
150 | static void |
151 | traceset_stats_finalize (LttvTracesetStats *self) |
152 | { |
153 | G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))-> |
154 | finalize(G_OBJECT(self)); |
155 | } |
156 | |
157 | |
158 | static void |
159 | traceset_stats_class_init (LttvTracesetContextClass *klass) |
160 | { |
161 | GObjectClass *gobject_class = G_OBJECT_CLASS(klass); |
162 | |
163 | gobject_class->finalize = (void (*)(GObject *self)) traceset_stats_finalize; |
164 | klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init; |
165 | klass->fini = (void (*)(LttvTracesetContext *self))fini; |
166 | klass->new_traceset_context = new_traceset_context; |
167 | klass->new_trace_context = new_trace_context; |
168 | klass->new_tracefile_context = new_tracefile_context; |
169 | } |
170 | |
171 | |
172 | GType |
173 | lttv_traceset_stats_get_type(void) |
174 | { |
175 | static GType type = 0; |
176 | if (type == 0) { |
177 | static const GTypeInfo info = { |
178 | sizeof (LttvTracesetStatsClass), |
179 | NULL, /* base_init */ |
180 | NULL, /* base_finalize */ |
181 | (GClassInitFunc) traceset_stats_class_init, /* class_init */ |
182 | NULL, /* class_finalize */ |
183 | NULL, /* class_data */ |
184 | sizeof (LttvTracesetContext), |
185 | 0, /* n_preallocs */ |
186 | (GInstanceInitFunc) traceset_stats_instance_init /* instance_init */ |
187 | }; |
188 | |
189 | type = g_type_register_static (LTTV_TRACESET_STATE_TYPE, "LttvTracesetStatsType", |
190 | &info, 0); |
191 | } |
192 | return type; |
193 | } |
194 | |
195 | |
196 | static void |
197 | trace_stats_instance_init (GTypeInstance *instance, gpointer g_class) |
198 | { |
199 | } |
200 | |
201 | |
202 | static void |
203 | trace_stats_finalize (LttvTraceStats *self) |
204 | { |
205 | G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE))-> |
206 | finalize(G_OBJECT(self)); |
207 | } |
208 | |
209 | |
210 | static void |
211 | trace_stats_class_init (LttvTraceContextClass *klass) |
212 | { |
213 | GObjectClass *gobject_class = G_OBJECT_CLASS(klass); |
214 | |
215 | gobject_class->finalize = (void (*)(GObject *self)) trace_stats_finalize; |
216 | } |
217 | |
218 | |
219 | GType |
220 | lttv_trace_stats_get_type(void) |
221 | { |
222 | static GType type = 0; |
223 | if (type == 0) { |
224 | static const GTypeInfo info = { |
225 | sizeof (LttvTraceStatsClass), |
226 | NULL, /* base_init */ |
227 | NULL, /* base_finalize */ |
228 | (GClassInitFunc) trace_stats_class_init, /* class_init */ |
229 | NULL, /* class_finalize */ |
230 | NULL, /* class_data */ |
231 | sizeof (LttvTraceStats), |
232 | 0, /* n_preallocs */ |
233 | (GInstanceInitFunc) trace_stats_instance_init /* instance_init */ |
234 | }; |
235 | |
236 | type = g_type_register_static (LTTV_TRACE_STATE_TYPE, |
237 | "LttvTraceStatsType", &info, 0); |
238 | } |
239 | return type; |
240 | } |
241 | |
242 | |
243 | static void |
244 | tracefile_stats_instance_init (GTypeInstance *instance, gpointer g_class) |
245 | { |
246 | } |
247 | |
248 | |
249 | static void |
250 | tracefile_stats_finalize (LttvTracefileStats *self) |
251 | { |
252 | G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE))-> |
253 | finalize(G_OBJECT(self)); |
254 | } |
255 | |
256 | |
257 | static void |
258 | tracefile_stats_class_init (LttvTracefileStatsClass *klass) |
259 | { |
260 | GObjectClass *gobject_class = G_OBJECT_CLASS(klass); |
261 | |
262 | gobject_class->finalize = (void (*)(GObject *self)) tracefile_stats_finalize; |
263 | } |
264 | |
265 | |
266 | GType |
267 | lttv_tracefile_stats_get_type(void) |
268 | { |
269 | static GType type = 0; |
270 | if (type == 0) { |
271 | static const GTypeInfo info = { |
272 | sizeof (LttvTracefileStatsClass), |
273 | NULL, /* base_init */ |
274 | NULL, /* base_finalize */ |
275 | (GClassInitFunc) tracefile_stats_class_init, /* class_init */ |
276 | NULL, /* class_finalize */ |
277 | NULL, /* class_data */ |
278 | sizeof (LttvTracefileStats), |
279 | 0, /* n_preallocs */ |
280 | (GInstanceInitFunc) tracefile_stats_instance_init /* instance_init */ |
281 | }; |
282 | |
283 | type = g_type_register_static (LTTV_TRACEFILE_STATE_TYPE, |
284 | "LttvTracefileStatsType", &info, 0); |
285 | } |
286 | return type; |
287 | } |
288 | |
289 | |
290 | static void |
291 | find_event_tree(LttvTracefileStats *tfcs, GQuark process, GQuark cpu, |
292 | GQuark mode, GQuark sub_mode, LttvAttribute **events_tree, |
293 | LttvAttribute **event_types_tree) |
294 | { |
295 | LttvAttribute *a; |
296 | |
297 | LttvTraceStats *tcs = LTTV_TRACE_STATS(tfcs->parent.parent.t_context); |
298 | a = lttv_attribute_find_subdir(tcs->stats, LTTV_STATS_PROCESSES); |
299 | a = lttv_attribute_find_subdir(a, tfcs->parent.process->pid_time); |
300 | a = lttv_attribute_find_subdir(a, LTTV_STATS_CPU); |
301 | a = lttv_attribute_find_subdir(a, tfcs->parent.cpu_name); |
302 | a = lttv_attribute_find_subdir(a, LTTV_STATS_MODE_TYPES); |
303 | a = lttv_attribute_find_subdir(a, tfcs->parent.process->state->t); |
304 | a = lttv_attribute_find_subdir(a, LTTV_STATS_SUBMODES); |
305 | a = lttv_attribute_find_subdir(a, tfcs->parent.process->state->n); |
306 | *events_tree = a; |
307 | a = lttv_attribute_find_subdir(a, LTTV_STATS_EVENT_TYPES); |
308 | *event_types_tree = a; |
309 | } |
310 | |
311 | |
312 | static void update_event_tree(LttvTracefileStats *tfcs) |
313 | { |
314 | LttvExecutionState *es = tfcs->parent.process->state; |
315 | |
316 | find_event_tree(tfcs, tfcs->parent.process->pid_time, tfcs->parent.cpu_name, |
317 | es->t, es->n, &(tfcs->current_events_tree), |
318 | &(tfcs->current_event_types_tree)); |
319 | } |
320 | |
321 | |
322 | static void mode_change(LttvTracefileStats *tfcs) |
323 | { |
324 | LttvAttributeValue cpu_time; |
325 | |
326 | LttTime delta; |
327 | |
328 | lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CPU_TIME, |
329 | LTTV_TIME, &cpu_time); |
308711e5 |
330 | delta = ltt_time_sub(tfcs->parent.parent.timestamp, |
b445142a |
331 | tfcs->parent.process->state->change); |
308711e5 |
332 | *(cpu_time.v_time) = ltt_time_add(*(cpu_time.v_time), delta); |
b445142a |
333 | } |
334 | |
335 | |
336 | static void mode_end(LttvTracefileStats *tfcs) |
337 | { |
338 | LttvAttributeValue elapsed_time, cpu_time; |
339 | |
340 | LttTime delta; |
341 | |
342 | lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_ELAPSED_TIME, |
343 | LTTV_TIME, &elapsed_time); |
308711e5 |
344 | delta = ltt_time_sub(tfcs->parent.parent.timestamp, |
b445142a |
345 | tfcs->parent.process->state->entry); |
308711e5 |
346 | *(elapsed_time.v_time) = ltt_time_add(*(elapsed_time.v_time), delta); |
b445142a |
347 | |
348 | lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CPU_TIME, |
349 | LTTV_TIME, &cpu_time); |
308711e5 |
350 | delta = ltt_time_sub(tfcs->parent.parent.timestamp, |
b445142a |
351 | tfcs->parent.process->state->change); |
308711e5 |
352 | *(cpu_time.v_time) = ltt_time_add(*(cpu_time.v_time), delta); |
b445142a |
353 | } |
354 | |
355 | |
356 | static gboolean before_syscall_entry(void *hook_data, void *call_data) |
357 | { |
358 | mode_change((LttvTracefileStats *)call_data); |
359 | return FALSE; |
360 | } |
361 | |
362 | |
363 | static gboolean after_syscall_entry(void *hook_data, void *call_data) |
364 | { |
365 | update_event_tree((LttvTracefileStats *)call_data); |
366 | return FALSE; |
367 | } |
368 | |
369 | |
370 | gboolean before_syscall_exit(void *hook_data, void *call_data) |
371 | { |
372 | mode_end((LttvTracefileStats *)call_data); |
373 | return FALSE; |
374 | } |
375 | |
376 | |
377 | static gboolean after_syscall_exit(void *hook_data, void *call_data) |
378 | { |
379 | update_event_tree((LttvTracefileStats *)call_data); |
380 | return FALSE; |
381 | } |
382 | |
383 | |
384 | gboolean before_trap_entry(void *hook_data, void *call_data) |
385 | { |
386 | mode_change((LttvTracefileStats *)call_data); |
387 | return FALSE; |
388 | } |
389 | |
390 | |
391 | static gboolean after_trap_entry(void *hook_data, void *call_data) |
392 | { |
393 | update_event_tree((LttvTracefileStats *)call_data); |
394 | return FALSE; |
395 | } |
396 | |
397 | |
398 | gboolean before_trap_exit(void *hook_data, void *call_data) |
399 | { |
400 | mode_end((LttvTracefileStats *)call_data); |
401 | return FALSE; |
402 | } |
403 | |
404 | |
405 | gboolean after_trap_exit(void *hook_data, void *call_data) |
406 | { |
407 | update_event_tree((LttvTracefileStats *)call_data); |
408 | return FALSE; |
409 | } |
410 | |
411 | |
412 | gboolean before_irq_entry(void *hook_data, void *call_data) |
413 | { |
414 | mode_change((LttvTracefileStats *)call_data); |
415 | return FALSE; |
416 | } |
417 | |
418 | |
419 | gboolean after_irq_entry(void *hook_data, void *call_data) |
420 | { |
421 | update_event_tree((LttvTracefileStats *)call_data); |
422 | return FALSE; |
423 | } |
424 | |
425 | |
426 | gboolean before_irq_exit(void *hook_data, void *call_data) |
427 | { |
428 | mode_end((LttvTracefileStats *)call_data); |
429 | return FALSE; |
430 | } |
431 | |
432 | |
433 | gboolean after_irq_exit(void *hook_data, void *call_data) |
434 | { |
435 | update_event_tree((LttvTracefileStats *)call_data); |
436 | return FALSE; |
437 | } |
438 | |
439 | |
440 | gboolean before_schedchange(void *hook_data, void *call_data) |
441 | { |
442 | LttvTraceHook *h = (LttvTraceHook *)hook_data; |
443 | |
444 | LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data; |
445 | |
446 | guint pid_in, pid_out, state_out; |
447 | |
448 | LttvProcessState *process; |
449 | |
450 | pid_in = ltt_event_get_unsigned(tfcs->parent.parent.e, h->f1); |
451 | pid_out = ltt_event_get_unsigned(tfcs->parent.parent.e, h->f2); |
452 | state_out = ltt_event_get_unsigned(tfcs->parent.parent.e, h->f3); |
453 | |
454 | /* compute the time for the process to schedule out */ |
455 | |
456 | mode_change(tfcs); |
457 | |
458 | /* get the information for the process scheduled in */ |
459 | |
460 | process = lttv_state_find_process(&(tfcs->parent), pid_in); |
461 | |
462 | find_event_tree(tfcs, process->pid_time, tfcs->parent.cpu_name, |
463 | process->state->t, process->state->n, &(tfcs->current_events_tree), |
464 | &(tfcs->current_event_types_tree)); |
465 | |
466 | /* compute the time waiting for the process to schedule in */ |
467 | |
468 | mode_change(tfcs); |
469 | return FALSE; |
470 | } |
471 | |
472 | |
473 | gboolean process_fork(void *hook_data, void *call_data) |
474 | { |
475 | /* nothing to do for now */ |
476 | return FALSE; |
477 | } |
478 | |
479 | |
480 | gboolean process_exit(void *hook_data, void *call_data) |
481 | { |
482 | /* We should probably exit all modes here or we could do that at |
483 | schedule out. */ |
484 | return FALSE; |
485 | } |
486 | |
487 | |
488 | gboolean every_event(void *hook_data, void *call_data) |
489 | { |
490 | LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data; |
491 | |
492 | LttvAttributeValue v; |
493 | |
494 | /* The current branch corresponds to the tracefile/process/interrupt state. |
495 | Statistics are added within it, to count the number of events of this |
496 | type occuring in this context. A quark has been pre-allocated for each |
497 | event type and is used as name. */ |
498 | |
499 | lttv_attribute_find(tfcs->current_event_types_tree, |
500 | ((LttvTraceState *)(tfcs->parent.parent.t_context))-> |
501 | eventtype_names[ltt_event_eventtype_id(tfcs->parent.parent.e)], |
502 | LTTV_UINT, &v); |
503 | (*(v.v_uint))++; |
504 | return FALSE; |
505 | } |
506 | |
507 | |
508 | static gboolean |
509 | sum_stats(void *hook_data, void *call_data) |
510 | { |
511 | LttvTracesetStats *tscs = (LttvTracesetStats *)call_data; |
512 | |
513 | LttvTraceStats *tcs; |
514 | |
515 | LttvTraceset *traceset = tscs->parent.parent.ts; |
516 | |
517 | LttvAttributeType type; |
518 | |
519 | LttvAttributeValue value; |
520 | |
521 | LttvAttributeName name; |
522 | |
523 | unsigned sum; |
524 | |
525 | int i, j, k, l, m, n, nb_trace, nb_process, nb_cpu, nb_mode_type, nb_submode, |
526 | nb_event_type; |
527 | |
528 | LttvAttribute *main_tree, *processes_tree, *process_tree, *cpus_tree, |
529 | *cpu_tree, *mode_tree, *mode_types_tree, *submodes_tree, |
530 | *submode_tree, *event_types_tree, *mode_events_tree, |
531 | *cpu_events_tree, *process_modes_tree, *trace_cpu_tree, |
532 | *trace_modes_tree, *traceset_modes_tree; |
533 | |
534 | traceset_modes_tree = lttv_attribute_find_subdir(tscs->stats, |
535 | LTTV_STATS_MODES); |
536 | nb_trace = lttv_traceset_number(traceset); |
537 | |
538 | for(i = 0 ; i < nb_trace ; i++) { |
539 | tcs = (LttvTraceStats *)(tscs->parent.parent.traces[i]); |
540 | main_tree = tcs->stats; |
541 | processes_tree = lttv_attribute_find_subdir(main_tree, |
542 | LTTV_STATS_PROCESSES); |
543 | trace_modes_tree = lttv_attribute_find_subdir(main_tree, LTTV_STATS_MODES); |
544 | nb_process = lttv_attribute_get_number(processes_tree); |
545 | |
546 | for(j = 0 ; j < nb_process ; j++) { |
547 | type = lttv_attribute_get(processes_tree, j, &name, &value); |
548 | process_tree = LTTV_ATTRIBUTE(*(value.v_gobject)); |
549 | |
550 | cpus_tree = lttv_attribute_find_subdir(process_tree, LTTV_STATS_CPU); |
551 | process_modes_tree = lttv_attribute_find_subdir(process_tree, |
552 | LTTV_STATS_MODES); |
553 | nb_cpu = lttv_attribute_get_number(cpus_tree); |
554 | |
555 | for(k = 0 ; k < nb_cpu ; k++) { |
556 | type = lttv_attribute_get(cpus_tree, k, &name, &value); |
557 | cpu_tree = LTTV_ATTRIBUTE(*(value.v_gobject)); |
558 | |
559 | mode_types_tree = lttv_attribute_find_subdir(cpu_tree, |
560 | LTTV_STATS_MODE_TYPES); |
561 | cpu_events_tree = lttv_attribute_find_subdir(cpu_tree, |
562 | LTTV_STATS_EVENTS); |
563 | trace_cpu_tree = lttv_attribute_find_subdir(main_tree, LTTV_STATS_CPU); |
564 | trace_cpu_tree = lttv_attribute_find_subdir(trace_cpu_tree, name); |
565 | nb_mode_type = lttv_attribute_get_number(mode_types_tree); |
566 | |
567 | for(l = 0 ; l < nb_mode_type ; l++) { |
568 | type = lttv_attribute_get(mode_types_tree, l, &name, &value); |
569 | mode_tree = LTTV_ATTRIBUTE(*(value.v_gobject)); |
570 | |
571 | submodes_tree = lttv_attribute_find_subdir(mode_tree, |
572 | LTTV_STATS_SUBMODES); |
573 | mode_events_tree = lttv_attribute_find_subdir(mode_tree, |
574 | LTTV_STATS_EVENTS); |
575 | nb_submode = lttv_attribute_get_number(submodes_tree); |
576 | |
577 | for(m = 0 ; m < nb_submode ; m++) { |
578 | type = lttv_attribute_get(submodes_tree, m, &name, &value); |
579 | submode_tree = LTTV_ATTRIBUTE(*(value.v_gobject)); |
580 | |
581 | event_types_tree = lttv_attribute_find_subdir(submode_tree, |
582 | LTTV_STATS_EVENT_TYPES); |
583 | nb_event_type = lttv_attribute_get_number(event_types_tree); |
584 | |
585 | sum = 0; |
586 | for(n = 0 ; n < nb_event_type ; n++) { |
587 | type = lttv_attribute_get(event_types_tree, n, &name, &value); |
588 | sum += *(value.v_uint); |
589 | } |
590 | lttv_attribute_find(submode_tree, LTTV_STATS_EVENTS_COUNT, |
591 | LTTV_UINT, &value); |
592 | *(value.v_uint) = sum; |
593 | lttv_attribute_recursive_add(mode_events_tree, submode_tree); |
594 | } |
595 | lttv_attribute_recursive_add(cpu_events_tree, mode_events_tree); |
596 | } |
597 | lttv_attribute_recursive_add(process_modes_tree, cpu_tree); |
598 | lttv_attribute_recursive_add(trace_cpu_tree, cpu_tree); |
599 | } |
600 | lttv_attribute_recursive_add(trace_modes_tree, process_modes_tree); |
601 | } |
602 | lttv_attribute_recursive_add(traceset_modes_tree, trace_modes_tree); |
603 | } |
604 | return FALSE; |
605 | } |
606 | |
607 | |
608 | lttv_stats_add_event_hooks(LttvTracesetStats *self) |
609 | { |
610 | LttvTraceset *traceset = self->parent.parent.ts; |
611 | |
612 | guint i, j, k, nb_trace, nb_control, nb_per_cpu, nb_tracefile; |
613 | |
614 | LttFacility *f; |
615 | |
616 | LttEventType *et; |
617 | |
618 | LttvTraceStats *ts; |
619 | |
620 | LttvTracefileStats *tfs; |
621 | |
622 | void *hook_data; |
623 | |
624 | GArray *hooks, *before_hooks, *after_hooks; |
625 | |
626 | LttvTraceHook hook; |
627 | |
628 | LttvAttributeValue val; |
629 | |
630 | nb_trace = lttv_traceset_number(traceset); |
631 | for(i = 0 ; i < nb_trace ; i++) { |
632 | ts = (LttvTraceStats *)self->parent.parent.traces[i]; |
633 | |
634 | /* Find the eventtype id for the following events and register the |
635 | associated by id hooks. */ |
636 | |
637 | hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook)); |
638 | g_array_set_size(hooks, 7); |
639 | |
640 | lttv_trace_find_hook(ts->parent.parent.t, "core","syscall_entry", |
641 | "syscall_id", NULL, NULL, before_syscall_entry, |
642 | &g_array_index(hooks, LttvTraceHook, 0)); |
643 | |
644 | lttv_trace_find_hook(ts->parent.parent.t, "core", "syscall_exit", NULL, |
645 | NULL, NULL, before_syscall_exit, |
646 | &g_array_index(hooks, LttvTraceHook, 1)); |
647 | |
648 | lttv_trace_find_hook(ts->parent.parent.t, "core", "trap_entry", "trap_id", |
649 | NULL, NULL, before_trap_entry, |
650 | &g_array_index(hooks, LttvTraceHook, 2)); |
651 | |
652 | lttv_trace_find_hook(ts->parent.parent.t, "core", "trap_exit", NULL, NULL, |
653 | NULL, before_trap_exit, &g_array_index(hooks, LttvTraceHook, 3)); |
654 | |
655 | lttv_trace_find_hook(ts->parent.parent.t, "core", "irq_entry", "irq_id", |
656 | NULL, NULL, before_irq_entry, &g_array_index(hooks, LttvTraceHook, 4)); |
657 | |
658 | lttv_trace_find_hook(ts->parent.parent.t, "core", "irq_exit", NULL, NULL, |
659 | NULL, before_irq_exit, &g_array_index(hooks, LttvTraceHook, 5)); |
660 | |
661 | lttv_trace_find_hook(ts->parent.parent.t, "core", "schedchange", "in", |
662 | "out", "out_state", before_schedchange, |
663 | &g_array_index(hooks, LttvTraceHook, 6)); |
664 | |
665 | before_hooks = hooks; |
666 | |
667 | hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook)); |
668 | g_array_set_size(hooks, 8); |
669 | |
670 | lttv_trace_find_hook(ts->parent.parent.t, "core","syscall_entry", |
671 | "syscall_id", NULL, NULL, after_syscall_entry, |
672 | &g_array_index(hooks, LttvTraceHook, 0)); |
673 | |
674 | lttv_trace_find_hook(ts->parent.parent.t, "core", "syscall_exit", NULL, |
675 | NULL, NULL, after_syscall_exit, |
676 | &g_array_index(hooks, LttvTraceHook, 1)); |
677 | |
678 | lttv_trace_find_hook(ts->parent.parent.t, "core", "trap_entry", "trap_id", |
679 | NULL, NULL, after_trap_entry, &g_array_index(hooks, LttvTraceHook, 2)); |
680 | |
681 | lttv_trace_find_hook(ts->parent.parent.t, "core", "trap_exit", NULL, NULL, |
682 | NULL, after_trap_exit, &g_array_index(hooks, LttvTraceHook, 3)); |
683 | |
684 | lttv_trace_find_hook(ts->parent.parent.t, "core", "irq_entry", "irq_id", |
685 | NULL, NULL, after_irq_entry, &g_array_index(hooks, LttvTraceHook, 4)); |
686 | |
687 | lttv_trace_find_hook(ts->parent.parent.t, "core", "irq_exit", NULL, NULL, |
688 | NULL, after_irq_exit, &g_array_index(hooks, LttvTraceHook, 5)); |
689 | |
690 | lttv_trace_find_hook(ts->parent.parent.t, "core", "process_fork", |
691 | "child_pid", NULL, NULL, process_fork, |
692 | &g_array_index(hooks, LttvTraceHook, 6)); |
693 | |
694 | lttv_trace_find_hook(ts->parent.parent.t, "core", "process_exit", NULL, |
695 | NULL, NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 7)); |
696 | |
697 | after_hooks = hooks; |
698 | |
699 | /* Add these hooks to each before_event_by_id hooks list */ |
700 | |
701 | nb_control = ltt_trace_control_tracefile_number(ts->parent.parent.t); |
702 | nb_per_cpu = ltt_trace_per_cpu_tracefile_number(ts->parent.parent.t); |
703 | nb_tracefile = nb_control + nb_per_cpu; |
704 | for(j = 0 ; j < nb_tracefile ; j++) { |
705 | if(j < nb_control) { |
706 | tfs = LTTV_TRACEFILE_STATS(ts->parent.parent.control_tracefiles[j]); |
707 | } |
708 | else { |
709 | tfs = LTTV_TRACEFILE_STATS(ts->parent.parent.per_cpu_tracefiles[ |
710 | j-nb_control]); |
711 | } |
712 | |
713 | lttv_hooks_add(tfs->parent.parent.after_event, every_event, NULL); |
714 | |
715 | for(k = 0 ; k < before_hooks->len ; k++) { |
716 | hook = g_array_index(before_hooks, LttvTraceHook, k); |
717 | lttv_hooks_add(lttv_hooks_by_id_find( |
718 | tfs->parent.parent.before_event_by_id, |
719 | hook.id), hook.h, &g_array_index(before_hooks, LttvTraceHook, k)); |
720 | } |
721 | for(k = 0 ; k < after_hooks->len ; k++) { |
722 | hook = g_array_index(after_hooks, LttvTraceHook, k); |
723 | lttv_hooks_add(lttv_hooks_by_id_find( |
724 | tfs->parent.parent.after_event_by_id, |
725 | hook.id), hook.h, &g_array_index(after_hooks, LttvTraceHook, k)); |
726 | } |
727 | } |
728 | lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS, |
729 | LTTV_POINTER, &val); |
730 | *(val.v_pointer) = before_hooks; |
731 | lttv_attribute_find(self->parent.parent.a, LTTV_STATS_AFTER_HOOKS, |
732 | LTTV_POINTER, &val); |
733 | *(val.v_pointer) = after_hooks; |
734 | } |
735 | lttv_hooks_add(self->parent.parent.after, sum_stats, NULL); |
736 | } |
737 | |
738 | |
739 | lttv_stats_remove_event_hooks(LttvTracesetStats *self) |
740 | { |
741 | LttvTraceset *traceset = self->parent.parent.ts; |
742 | |
743 | guint i, j, k, nb_trace, nb_control, nb_per_cpu, nb_tracefile; |
744 | |
745 | LttvTraceStats *ts; |
746 | |
747 | LttvTracefileStats *tfs; |
748 | |
749 | void *hook_data; |
750 | |
751 | GArray *before_hooks, *after_hooks; |
752 | |
753 | LttvTraceHook hook; |
754 | |
755 | LttvAttributeValue val; |
756 | |
757 | nb_trace = lttv_traceset_number(traceset); |
758 | for(i = 0 ; i < nb_trace ; i++) { |
759 | ts = LTTV_TRACE_STATS(self->parent.parent.traces[i]); |
760 | lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS, |
761 | LTTV_POINTER, &val); |
762 | before_hooks = *(val.v_pointer); |
763 | lttv_attribute_find(self->parent.parent.a, LTTV_STATS_AFTER_HOOKS, |
764 | LTTV_POINTER, &val); |
765 | after_hooks = *(val.v_pointer); |
766 | |
767 | /* Add these hooks to each before_event_by_id hooks list */ |
768 | |
769 | nb_control = ltt_trace_control_tracefile_number(ts->parent.parent.t); |
770 | nb_per_cpu = ltt_trace_per_cpu_tracefile_number(ts->parent.parent.t); |
771 | nb_tracefile = nb_control + nb_per_cpu; |
772 | for(j = 0 ; j < nb_tracefile ; j++) { |
773 | if(j < nb_control) { |
774 | tfs = LTTV_TRACEFILE_STATS(ts->parent.parent.control_tracefiles[j]); |
775 | } |
776 | else { |
777 | tfs =LTTV_TRACEFILE_STATS(ts->parent.parent.per_cpu_tracefiles[ |
778 | j-nb_control]); |
779 | } |
780 | |
781 | lttv_hooks_remove_data(tfs->parent.parent.after_event, every_event, |
782 | NULL); |
783 | |
784 | for(k = 0 ; k < before_hooks->len ; k++) { |
785 | hook = g_array_index(before_hooks, LttvTraceHook, k); |
786 | lttv_hooks_remove_data( |
787 | lttv_hooks_by_id_find(tfs->parent.parent.before_event_by_id, |
788 | hook.id), hook.h, &g_array_index(before_hooks, LttvTraceHook, k)); |
789 | } |
790 | for(k = 0 ; k < after_hooks->len ; k++) { |
791 | hook = g_array_index(after_hooks, LttvTraceHook, k); |
792 | lttv_hooks_remove_data( |
793 | lttv_hooks_by_id_find(tfs->parent.parent.after_event_by_id, |
794 | hook.id), hook.h, &g_array_index(after_hooks, LttvTraceHook, k)); |
795 | } |
796 | } |
f7afe191 |
797 | g_critical("lttv_stats_remove_event_hooks()"); |
b445142a |
798 | g_array_free(before_hooks, TRUE); |
799 | g_array_free(after_hooks, TRUE); |
800 | } |
801 | lttv_hooks_remove_data(self->parent.parent.after, sum_stats, NULL); |
802 | } |
803 | |
804 | |
805 | void lttv_stats_init(int argc, char **argv) |
806 | { |
807 | LTTV_STATS_PROCESS_UNKNOWN = g_quark_from_string("unknown process"); |
808 | LTTV_STATS_PROCESSES = g_quark_from_string("processes"); |
809 | LTTV_STATS_CPU = g_quark_from_string("cpu"); |
810 | LTTV_STATS_MODE_TYPES = g_quark_from_string("mode_types"); |
811 | LTTV_STATS_MODES = g_quark_from_string("modes"); |
812 | LTTV_STATS_SUBMODES = g_quark_from_string("submodes"); |
813 | LTTV_STATS_EVENT_TYPES = g_quark_from_string("event_types"); |
814 | LTTV_STATS_CPU_TIME = g_quark_from_string("cpu time"); |
815 | LTTV_STATS_ELAPSED_TIME = g_quark_from_string("elapsed time"); |
816 | LTTV_STATS_EVENTS = g_quark_from_string("events"); |
817 | LTTV_STATS_EVENTS_COUNT = g_quark_from_string("events count"); |
818 | LTTV_STATS_BEFORE_HOOKS = g_quark_from_string("saved stats before hooks"); |
819 | LTTV_STATS_AFTER_HOOKS = g_quark_from_string("saved stats after hooks"); |
820 | } |
821 | |
822 | void lttv_stats_destroy() |
823 | { |
824 | } |
825 | |