fix smp in control flow view
[lttv.git] / ltt / branches / poly / lttv / lttv / stats.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #include <lttv/module.h>
25 #include <lttv/stats.h>
26 #include <lttv/lttv.h>
27 #include <lttv/attribute.h>
28 #include <ltt/facility.h>
29 #include <ltt/trace.h>
30 #include <ltt/event.h>
31 #include <ltt/type.h>
32
33 #define BUF_SIZE 256
34
35 GQuark
36 LTTV_STATS_PROCESS_UNKNOWN,
37 LTTV_STATS_PROCESSES,
38 LTTV_STATS_CPU,
39 LTTV_STATS_MODE_TYPES,
40 LTTV_STATS_MODES,
41 LTTV_STATS_SUBMODES,
42 LTTV_STATS_EVENT_TYPES,
43 LTTV_STATS_CPU_TIME,
44 LTTV_STATS_ELAPSED_TIME,
45 LTTV_STATS_EVENTS,
46 LTTV_STATS_EVENTS_COUNT,
47 LTTV_STATS_USE_COUNT,
48 LTTV_STATS,
49 LTTV_STATS_TRACEFILES,
50 LTTV_STATS_SUMMED;
51
52 static GQuark
53 LTTV_STATS_BEFORE_HOOKS,
54 LTTV_STATS_AFTER_HOOKS;
55
56 static void
57 find_event_tree(LttvTracefileStats *tfcs, GQuark pid_time, GQuark cpu,
58 GQuark mode, GQuark sub_mode, LttvAttribute **events_tree,
59 LttvAttribute **event_types_tree);
60
61 static void
62 init(LttvTracesetStats *self, LttvTraceset *ts)
63 {
64 guint i, j, nb_trace, nb_tracefile;
65
66 LttvTraceContext *tc;
67
68 LttvTraceStats *tcs;
69
70 LttvTracefileContext *tfc;
71
72 LttvTracefileContext **tfs;
73 LttvTracefileStats *tfcs;
74
75 LttTime timestamp = {0,0};
76
77 LttvAttributeValue v;
78
79 LttvAttribute
80 *stats_tree,
81 *tracefiles_stats;
82
83 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))->
84 init((LttvTracesetContext *)self, ts);
85
86 self->stats = lttv_attribute_find_subdir(
87 lttv_traceset_attribute(self->parent.parent.ts),
88 LTTV_STATS);
89 lttv_attribute_find(lttv_traceset_attribute(self->parent.parent.ts),
90 LTTV_STATS_USE_COUNT,
91 LTTV_UINT, &v);
92
93 *(v.v_uint)++;
94 if(*(v.v_uint) == 1) {
95 g_assert(lttv_attribute_get_number(self->stats) == 0);
96 }
97
98 nb_trace = lttv_traceset_number(ts);
99
100 for(i = 0 ; i < nb_trace ; i++) {
101 tc = self->parent.parent.traces[i];
102 tcs = LTTV_TRACE_STATS(tc);
103
104 tcs->stats = lttv_attribute_find_subdir(tcs->parent.parent.t_a,LTTV_STATS);
105 tracefiles_stats = lttv_attribute_find_subdir(tcs->parent.parent.t_a,
106 LTTV_STATS_TRACEFILES);
107 lttv_attribute_find(tcs->parent.parent.t_a, LTTV_STATS_USE_COUNT,
108 LTTV_UINT, &v);
109
110 *(v.v_uint)++;
111 if(*(v.v_uint) == 1) {
112 g_assert(lttv_attribute_get_number(tcs->stats) == 0);
113 }
114
115 nb_tracefile = tc->tracefiles->len;
116
117 for(j = 0 ; j < nb_tracefile ; j++) {
118 tfs = &g_array_index(tc->tracefiles,
119 LttvTracefileContext*, j);
120 tfcs = LTTV_TRACEFILE_STATS(*tfs);
121 tfcs->stats = lttv_attribute_find_subdir(tracefiles_stats,
122 ltt_tracefile_long_name(tfcs->parent.parent.tf));
123 find_event_tree(tfcs, LTTV_STATS_PROCESS_UNKNOWN,
124 ltt_tracefile_long_name(tfcs->parent.parent.tf),
125 LTTV_STATE_MODE_UNKNOWN,
126 LTTV_STATE_SUBMODE_UNKNOWN, &tfcs->current_events_tree,
127 &tfcs->current_event_types_tree);
128 }
129 }
130 }
131
132 static void
133 fini(LttvTracesetStats *self)
134 {
135 guint i, j, nb_trace, nb_tracefile;
136
137 LttvTraceset *ts;
138
139 LttvTraceContext *tc;
140
141 LttvTraceStats *tcs;
142
143 LttvTracefileContext *tfc;
144
145 LttvTracefileStats *tfcs;
146
147 LttTime timestamp = {0,0};
148
149 LttvAttributeValue v;
150
151 LttvAttribute *tracefiles_stats;
152
153 lttv_attribute_find(self->parent.parent.ts_a, LTTV_STATS_USE_COUNT,
154 LTTV_UINT, &v);
155 *(v.v_uint)--;
156
157 if(*(v.v_uint) == 0) {
158 lttv_attribute_remove_by_name(self->parent.parent.ts_a, LTTV_STATS);
159 }
160 self->stats = NULL;
161
162 ts = self->parent.parent.ts;
163 nb_trace = lttv_traceset_number(ts);
164
165 for(i = 0 ; i < nb_trace ; i++) {
166 tcs = (LttvTraceStats *)(tc = (LTTV_TRACESET_CONTEXT(self)->traces[i]));
167
168 lttv_attribute_find(tcs->parent.parent.t_a, LTTV_STATS_USE_COUNT,
169 LTTV_UINT, &v);
170 *(v.v_uint)--;
171
172 if(*(v.v_uint) == 0) {
173 lttv_attribute_remove_by_name(tcs->parent.parent.t_a,LTTV_STATS);
174 tracefiles_stats = lttv_attribute_find_subdir(tcs->parent.parent.t_a,
175 LTTV_STATS_TRACEFILES);
176 lttv_attribute_remove_by_name(tcs->parent.parent.t_a,
177 LTTV_STATS_TRACEFILES);
178 }
179 tcs->stats = NULL;
180
181 nb_tracefile = tc->tracefiles->len;
182
183 for(j = 0 ; j < nb_tracefile ; j++) {
184 tfc = g_array_index(tc->tracefiles,
185 LttvTracefileContext*, j);
186 tfcs = (LttvTracefileStats *)tfc;
187 tfcs->stats = NULL;
188 tfcs->current_events_tree = NULL;
189 tfcs->current_event_types_tree = NULL;
190 }
191 }
192 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))->
193 fini((LttvTracesetContext *)self);
194 }
195
196
197 static LttvTracesetContext *
198 new_traceset_context(LttvTracesetContext *self)
199 {
200 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE, NULL));
201 }
202
203
204 static LttvTraceContext *
205 new_trace_context(LttvTracesetContext *self)
206 {
207 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE, NULL));
208 }
209
210
211 static LttvTracefileContext *
212 new_tracefile_context(LttvTracesetContext *self)
213 {
214 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE, NULL));
215 }
216
217
218 static void
219 traceset_stats_instance_init (GTypeInstance *instance, gpointer g_class)
220 {
221 }
222
223
224 static void
225 traceset_stats_finalize (LttvTracesetStats *self)
226 {
227 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))->
228 finalize(G_OBJECT(self));
229 }
230
231
232 static void
233 traceset_stats_class_init (LttvTracesetContextClass *klass)
234 {
235 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
236
237 gobject_class->finalize = (void (*)(GObject *self)) traceset_stats_finalize;
238 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
239 klass->fini = (void (*)(LttvTracesetContext *self))fini;
240 klass->new_traceset_context = new_traceset_context;
241 klass->new_trace_context = new_trace_context;
242 klass->new_tracefile_context = new_tracefile_context;
243 }
244
245
246 GType
247 lttv_traceset_stats_get_type(void)
248 {
249 static GType type = 0;
250 if (type == 0) {
251 static const GTypeInfo info = {
252 sizeof (LttvTracesetStatsClass),
253 NULL, /* base_init */
254 NULL, /* base_finalize */
255 (GClassInitFunc) traceset_stats_class_init, /* class_init */
256 NULL, /* class_finalize */
257 NULL, /* class_data */
258 sizeof (LttvTracesetStats),
259 0, /* n_preallocs */
260 (GInstanceInitFunc) traceset_stats_instance_init, /* instance_init */
261 NULL /* Value handling */
262 };
263
264 type = g_type_register_static (LTTV_TRACESET_STATE_TYPE,
265 "LttvTracesetStatsType",
266 &info, 0);
267 }
268 return type;
269 }
270
271
272 static void
273 trace_stats_instance_init (GTypeInstance *instance, gpointer g_class)
274 {
275 }
276
277
278 static void
279 trace_stats_finalize (LttvTraceStats *self)
280 {
281 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE))->
282 finalize(G_OBJECT(self));
283 }
284
285
286 static void
287 trace_stats_class_init (LttvTraceContextClass *klass)
288 {
289 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
290
291 gobject_class->finalize = (void (*)(GObject *self)) trace_stats_finalize;
292 }
293
294
295 GType
296 lttv_trace_stats_get_type(void)
297 {
298 static GType type = 0;
299 if (type == 0) {
300 static const GTypeInfo info = {
301 sizeof (LttvTraceStatsClass),
302 NULL, /* base_init */
303 NULL, /* base_finalize */
304 (GClassInitFunc) trace_stats_class_init, /* class_init */
305 NULL, /* class_finalize */
306 NULL, /* class_data */
307 sizeof (LttvTraceStats),
308 0, /* n_preallocs */
309 (GInstanceInitFunc) trace_stats_instance_init, /* instance_init */
310 NULL /* Value handling */
311 };
312
313 type = g_type_register_static (LTTV_TRACE_STATE_TYPE,
314 "LttvTraceStatsType", &info, 0);
315 }
316 return type;
317 }
318
319
320 static void
321 tracefile_stats_instance_init (GTypeInstance *instance, gpointer g_class)
322 {
323 }
324
325
326 static void
327 tracefile_stats_finalize (LttvTracefileStats *self)
328 {
329 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE))->
330 finalize(G_OBJECT(self));
331 }
332
333
334 static void
335 tracefile_stats_class_init (LttvTracefileStatsClass *klass)
336 {
337 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
338
339 gobject_class->finalize = (void (*)(GObject *self)) tracefile_stats_finalize;
340 }
341
342
343 GType
344 lttv_tracefile_stats_get_type(void)
345 {
346 static GType type = 0;
347 if (type == 0) {
348 static const GTypeInfo info = {
349 sizeof (LttvTracefileStatsClass),
350 NULL, /* base_init */
351 NULL, /* base_finalize */
352 (GClassInitFunc) tracefile_stats_class_init, /* class_init */
353 NULL, /* class_finalize */
354 NULL, /* class_data */
355 sizeof (LttvTracefileStats),
356 0, /* n_preallocs */
357 (GInstanceInitFunc) tracefile_stats_instance_init, /* instance_init */
358 NULL /* Value handling */
359 };
360
361 type = g_type_register_static (LTTV_TRACEFILE_STATE_TYPE,
362 "LttvTracefileStatsType", &info, 0);
363 }
364 return type;
365 }
366
367
368 static void
369 find_event_tree(LttvTracefileStats *tfcs,
370 GQuark pid_time,
371 GQuark cpu,
372 GQuark mode,
373 GQuark sub_mode,
374 LttvAttribute **events_tree,
375 LttvAttribute **event_types_tree)
376 {
377 LttvAttribute *a;
378
379 LttvTraceStats *tcs = (LttvTraceStats*)tfcs->parent.parent.t_context;
380 a = lttv_attribute_find_subdir(tcs->stats, LTTV_STATS_PROCESSES);
381 a = lttv_attribute_find_subdir(a, pid_time);
382 a = lttv_attribute_find_subdir(a, LTTV_STATS_CPU);
383 a = lttv_attribute_find_subdir(a, cpu);
384 a = lttv_attribute_find_subdir(a, LTTV_STATS_MODE_TYPES);
385 a = lttv_attribute_find_subdir(a, mode);
386 a = lttv_attribute_find_subdir(a, LTTV_STATS_SUBMODES);
387 a = lttv_attribute_find_subdir(a, sub_mode);
388 *events_tree = a;
389 a = lttv_attribute_find_subdir(a, LTTV_STATS_EVENT_TYPES);
390 *event_types_tree = a;
391 }
392
393
394 static void update_event_tree(LttvTracefileStats *tfcs)
395 {
396 LttvTraceState *ts = (LttvTraceState *)tfcs->parent.parent.t_context;
397 guint cpu = ltt_tracefile_num(tfcs->parent.parent.tf);
398 LttvProcessState *process = ts->running_process[cpu];
399 LttvExecutionState *es = process->state;
400
401 find_event_tree(tfcs, process->pid_time,
402 ltt_tracefile_long_name(tfcs->parent.parent.tf),
403 es->t, es->n, &(tfcs->current_events_tree),
404 &(tfcs->current_event_types_tree));
405 }
406
407
408 static void mode_change(LttvTracefileStats *tfcs)
409 {
410 LttvTraceState *ts = (LttvTraceState *)tfcs->parent.parent.t_context;
411 guint cpu = ltt_tracefile_num(tfcs->parent.parent.tf);
412 LttvProcessState *process = ts->running_process[cpu];
413 LttvAttributeValue cpu_time;
414
415 LttTime delta;
416
417 lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CPU_TIME,
418 LTTV_TIME, &cpu_time);
419 delta = ltt_time_sub(tfcs->parent.parent.timestamp,
420 process->state->change);
421 *(cpu_time.v_time) = ltt_time_add(*(cpu_time.v_time), delta);
422 }
423
424
425 static void mode_end(LttvTracefileStats *tfcs)
426 {
427 LttvTraceState *ts = (LttvTraceState *)tfcs->parent.parent.t_context;
428 guint cpu = ltt_tracefile_num(tfcs->parent.parent.tf);
429 LttvProcessState *process = ts->running_process[cpu];
430 LttvAttributeValue elapsed_time, cpu_time;
431
432 LttTime delta;
433
434 lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_ELAPSED_TIME,
435 LTTV_TIME, &elapsed_time);
436 delta = ltt_time_sub(tfcs->parent.parent.timestamp,
437 process->state->entry);
438 *(elapsed_time.v_time) = ltt_time_add(*(elapsed_time.v_time), delta);
439
440 lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CPU_TIME,
441 LTTV_TIME, &cpu_time);
442 delta = ltt_time_sub(tfcs->parent.parent.timestamp,
443 process->state->change);
444 *(cpu_time.v_time) = ltt_time_add(*(cpu_time.v_time), delta);
445 }
446
447
448 static gboolean before_syscall_entry(void *hook_data, void *call_data)
449 {
450 mode_change((LttvTracefileStats *)call_data);
451 return FALSE;
452 }
453
454
455 static gboolean after_syscall_entry(void *hook_data, void *call_data)
456 {
457 update_event_tree((LttvTracefileStats *)call_data);
458 return FALSE;
459 }
460
461
462 gboolean before_syscall_exit(void *hook_data, void *call_data)
463 {
464 mode_end((LttvTracefileStats *)call_data);
465 return FALSE;
466 }
467
468
469 static gboolean after_syscall_exit(void *hook_data, void *call_data)
470 {
471 update_event_tree((LttvTracefileStats *)call_data);
472 return FALSE;
473 }
474
475
476 gboolean before_trap_entry(void *hook_data, void *call_data)
477 {
478 mode_change((LttvTracefileStats *)call_data);
479 return FALSE;
480 }
481
482
483 static gboolean after_trap_entry(void *hook_data, void *call_data)
484 {
485 update_event_tree((LttvTracefileStats *)call_data);
486 return FALSE;
487 }
488
489
490 gboolean before_trap_exit(void *hook_data, void *call_data)
491 {
492 mode_end((LttvTracefileStats *)call_data);
493 return FALSE;
494 }
495
496
497 gboolean after_trap_exit(void *hook_data, void *call_data)
498 {
499 update_event_tree((LttvTracefileStats *)call_data);
500 return FALSE;
501 }
502
503
504 gboolean before_irq_entry(void *hook_data, void *call_data)
505 {
506 mode_change((LttvTracefileStats *)call_data);
507 return FALSE;
508 }
509
510
511 gboolean after_irq_entry(void *hook_data, void *call_data)
512 {
513 update_event_tree((LttvTracefileStats *)call_data);
514 return FALSE;
515 }
516
517
518 gboolean before_irq_exit(void *hook_data, void *call_data)
519 {
520 mode_end((LttvTracefileStats *)call_data);
521 return FALSE;
522 }
523
524
525 gboolean after_irq_exit(void *hook_data, void *call_data)
526 {
527 update_event_tree((LttvTracefileStats *)call_data);
528 return FALSE;
529 }
530
531
532 gboolean before_schedchange(void *hook_data, void *call_data)
533 {
534 LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data;
535
536 LttvTraceState *ts = (LttvTraceState*)tfcs->parent.parent.t_context;
537
538 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.parent.tf);
539
540 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
541
542 guint pid_in, pid_out;
543
544 gint state_out;
545
546 LttvProcessState *process;
547
548 pid_out = ltt_event_get_unsigned(e, thf->f1);
549 pid_in = ltt_event_get_unsigned(e, thf->f2);
550 state_out = ltt_event_get_int(e, thf->f3);
551
552 /* compute the time for the process to schedule out */
553
554 mode_change(tfcs);
555
556 /* get the information for the process scheduled in */
557
558 process = lttv_state_find_process_or_create(ts,
559 ANY_CPU, pid_in, &tfcs->parent.parent.timestamp);
560
561 find_event_tree(tfcs, process->pid_time,
562 ltt_tracefile_long_name(tfcs->parent.parent.tf),
563 process->state->t, process->state->n, &(tfcs->current_events_tree),
564 &(tfcs->current_event_types_tree));
565
566 /* compute the time waiting for the process to schedule in */
567
568 mode_change(tfcs);
569 return FALSE;
570 }
571
572
573 gboolean process_fork(void *hook_data, void *call_data)
574 {
575 /* nothing to do for now */
576 return FALSE;
577 }
578
579
580 gboolean process_exit(void *hook_data, void *call_data)
581 {
582 /* We should probably exit all modes here or we could do that at
583 schedule out. */
584 return FALSE;
585 }
586
587 gboolean process_free(void *hook_data, void *call_data)
588 {
589 return FALSE;
590 }
591
592 gboolean every_event(void *hook_data, void *call_data)
593 {
594 LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data;
595
596 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.parent.tf);
597
598 LttvAttributeValue v;
599
600 /* The current branch corresponds to the tracefile/process/interrupt state.
601 Statistics are added within it, to count the number of events of this
602 type occuring in this context. A quark has been pre-allocated for each
603 event type and is used as name. */
604
605 lttv_attribute_find(tfcs->current_event_types_tree,
606 ltt_eventtype_name(ltt_event_eventtype(e)),
607 LTTV_UINT, &v);
608 (*(v.v_uint))++;
609 return FALSE;
610 }
611
612
613 void
614 lttv_stats_sum_trace(LttvTraceStats *self)
615 {
616 LttvAttribute *sum_container = self->stats;
617
618 LttvAttributeType type;
619
620 LttvAttributeValue value;
621
622 LttvAttributeName name;
623
624 unsigned sum;
625
626 int i, j, k, l, m, nb_process, nb_cpu, nb_mode_type, nb_submode,
627 nb_event_type;
628
629 LttvAttribute *main_tree, *processes_tree, *process_tree, *cpus_tree,
630 *cpu_tree, *mode_tree, *mode_types_tree, *submodes_tree,
631 *submode_tree, *event_types_tree, *mode_events_tree,
632 *cpu_events_tree, *process_modes_tree, *trace_cpu_tree,
633 *trace_modes_tree;
634
635 main_tree = sum_container;
636
637 lttv_attribute_find(sum_container,
638 LTTV_STATS_SUMMED,
639 LTTV_UINT, &value);
640 if(*(value.v_uint) != 0) return;
641 *(value.v_uint) = 1;
642
643 processes_tree = lttv_attribute_find_subdir(main_tree,
644 LTTV_STATS_PROCESSES);
645 trace_modes_tree = lttv_attribute_find_subdir(main_tree,
646 LTTV_STATS_MODES);
647 nb_process = lttv_attribute_get_number(processes_tree);
648
649 for(i = 0 ; i < nb_process ; i++) {
650 type = lttv_attribute_get(processes_tree, i, &name, &value);
651 process_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
652
653 cpus_tree = lttv_attribute_find_subdir(process_tree, LTTV_STATS_CPU);
654 process_modes_tree = lttv_attribute_find_subdir(process_tree,
655 LTTV_STATS_MODES);
656 nb_cpu = lttv_attribute_get_number(cpus_tree);
657
658 for(j = 0 ; j < nb_cpu ; j++) {
659 type = lttv_attribute_get(cpus_tree, j, &name, &value);
660 cpu_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
661
662 mode_types_tree = lttv_attribute_find_subdir(cpu_tree,
663 LTTV_STATS_MODE_TYPES);
664 cpu_events_tree = lttv_attribute_find_subdir(cpu_tree,
665 LTTV_STATS_EVENTS);
666 trace_cpu_tree = lttv_attribute_find_subdir(main_tree, LTTV_STATS_CPU);
667 trace_cpu_tree = lttv_attribute_find_subdir(trace_cpu_tree, name);
668 nb_mode_type = lttv_attribute_get_number(mode_types_tree);
669
670 for(k = 0 ; k < nb_mode_type ; k++) {
671 type = lttv_attribute_get(mode_types_tree, k, &name, &value);
672 mode_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
673
674 submodes_tree = lttv_attribute_find_subdir(mode_tree,
675 LTTV_STATS_SUBMODES);
676 mode_events_tree = lttv_attribute_find_subdir(mode_tree,
677 LTTV_STATS_EVENTS);
678 nb_submode = lttv_attribute_get_number(submodes_tree);
679
680 for(l = 0 ; l < nb_submode ; l++) {
681 type = lttv_attribute_get(submodes_tree, l, &name, &value);
682 submode_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
683
684 event_types_tree = lttv_attribute_find_subdir(submode_tree,
685 LTTV_STATS_EVENT_TYPES);
686 nb_event_type = lttv_attribute_get_number(event_types_tree);
687
688 sum = 0;
689 for(m = 0 ; m < nb_event_type ; m++) {
690 type = lttv_attribute_get(event_types_tree, m, &name, &value);
691 sum += *(value.v_uint);
692 }
693 lttv_attribute_find(submode_tree, LTTV_STATS_EVENTS_COUNT,
694 LTTV_UINT, &value);
695 *(value.v_uint) = sum;
696 lttv_attribute_recursive_add(mode_events_tree, submode_tree);
697 }
698 lttv_attribute_recursive_add(cpu_events_tree, mode_events_tree);
699 }
700 lttv_attribute_recursive_add(process_modes_tree, cpu_tree);
701 lttv_attribute_recursive_add(trace_cpu_tree, cpu_tree);
702 }
703 lttv_attribute_recursive_add(trace_modes_tree, process_modes_tree);
704 }
705 }
706
707
708 gboolean lttv_stats_sum_traceset_hook(void *hook_data, void *call_data)
709 {
710 lttv_stats_sum_traceset((LttvTracesetStats *)call_data);
711 return 0;
712 }
713
714 void
715 lttv_stats_sum_traceset(LttvTracesetStats *self)
716 {
717 LttvTraceset *traceset = self->parent.parent.ts;
718 LttvAttribute *sum_container = self->stats;
719
720 LttvTraceStats *tcs;
721
722 int i, nb_trace;
723
724 LttvAttribute *main_tree, *trace_modes_tree, *traceset_modes_tree;
725
726 LttvAttributeValue value;
727
728 lttv_attribute_find(sum_container, LTTV_STATS_SUMMED,
729 LTTV_UINT, &value);
730 if(*(value.v_uint) != 0) return;
731 *(value.v_uint) = 1;
732
733 traceset_modes_tree = lttv_attribute_find_subdir(sum_container,
734 LTTV_STATS_MODES);
735 nb_trace = lttv_traceset_number(traceset);
736
737 for(i = 0 ; i < nb_trace ; i++) {
738 tcs = (LttvTraceStats *)(self->parent.parent.traces[i]);
739 lttv_stats_sum_trace(tcs);
740 main_tree = tcs->stats;
741 trace_modes_tree = lttv_attribute_find_subdir(main_tree, LTTV_STATS_MODES);
742 lttv_attribute_recursive_add(traceset_modes_tree, trace_modes_tree);
743 }
744 }
745
746
747 // Hook wrapper. call_data is a traceset context.
748 gboolean lttv_stats_hook_add_event_hooks(void *hook_data, void *call_data)
749 {
750 LttvTracesetStats *tss = (LttvTracesetStats*)call_data;
751
752 lttv_stats_add_event_hooks(tss);
753
754 return 0;
755 }
756
757 void lttv_stats_add_event_hooks(LttvTracesetStats *self)
758 {
759 LttvTraceset *traceset = self->parent.parent.ts;
760
761 guint i, j, k, l, nb_trace, nb_tracefile;
762
763 LttvTraceStats *ts;
764
765 LttvTracefileStats *tfs;
766
767 GArray *hooks, *before_hooks, *after_hooks;
768
769 LttvTraceHook *hook;
770
771 LttvTraceHookByFacility *thf;
772
773 LttvAttributeValue val;
774
775 gint ret;
776
777 nb_trace = lttv_traceset_number(traceset);
778 for(i = 0 ; i < nb_trace ; i++) {
779 ts = (LttvTraceStats *)self->parent.parent.traces[i];
780
781 /* Find the eventtype id for the following events and register the
782 associated by id hooks. */
783
784 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 7);
785 g_array_set_size(hooks, 7);
786
787 ret = lttv_trace_find_hook(ts->parent.parent.t,
788 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
789 LTT_FIELD_SYSCALL_ID, 0, 0,
790 before_syscall_entry, NULL,
791 &g_array_index(hooks, LttvTraceHook, 0));
792 g_assert(!ret);
793
794 ret = lttv_trace_find_hook(ts->parent.parent.t,
795 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
796 0, 0, 0,
797 before_syscall_exit, NULL,
798 &g_array_index(hooks, LttvTraceHook, 1));
799 g_assert(!ret);
800
801 ret = lttv_trace_find_hook(ts->parent.parent.t,
802 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
803 LTT_FIELD_TRAP_ID, 0, 0,
804 before_trap_entry, NULL,
805 &g_array_index(hooks, LttvTraceHook, 2));
806 g_assert(!ret);
807
808 ret = lttv_trace_find_hook(ts->parent.parent.t,
809 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
810 0, 0, 0,
811 before_trap_exit, NULL,
812 &g_array_index(hooks, LttvTraceHook, 3));
813 g_assert(!ret);
814
815 ret = lttv_trace_find_hook(ts->parent.parent.t,
816 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
817 LTT_FIELD_IRQ_ID, 0, 0,
818 before_irq_entry, NULL,
819 &g_array_index(hooks, LttvTraceHook, 4));
820 g_assert(!ret);
821
822 ret = lttv_trace_find_hook(ts->parent.parent.t,
823 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
824 0, 0, 0,
825 before_irq_exit, NULL,
826 &g_array_index(hooks, LttvTraceHook, 5));
827 g_assert(!ret);
828
829 ret = lttv_trace_find_hook(ts->parent.parent.t,
830 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
831 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
832 before_schedchange, NULL,
833 &g_array_index(hooks, LttvTraceHook, 6));
834 g_assert(!ret);
835
836 before_hooks = hooks;
837
838 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 9);
839 g_array_set_size(hooks, 9);
840
841 ret = lttv_trace_find_hook(ts->parent.parent.t,
842 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
843 LTT_FIELD_SYSCALL_ID, 0, 0,
844 after_syscall_entry, NULL,
845 &g_array_index(hooks, LttvTraceHook, 0));
846 g_assert(!ret);
847
848 ret = lttv_trace_find_hook(ts->parent.parent.t,
849 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
850 0, 0, 0,
851 after_syscall_exit, NULL,
852 &g_array_index(hooks, LttvTraceHook, 1));
853 g_assert(!ret);
854
855 ret = lttv_trace_find_hook(ts->parent.parent.t,
856 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
857 LTT_FIELD_TRAP_ID, 0, 0,
858 after_trap_entry, NULL,
859 &g_array_index(hooks, LttvTraceHook, 2));
860 g_assert(!ret);
861
862 ret = lttv_trace_find_hook(ts->parent.parent.t,
863 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
864 0, 0, 0,
865 after_trap_exit, NULL,
866 &g_array_index(hooks, LttvTraceHook, 3));
867 g_assert(!ret);
868
869 ret = lttv_trace_find_hook(ts->parent.parent.t,
870 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
871 LTT_FIELD_IRQ_ID, 0, 0,
872 after_irq_entry, NULL,
873 &g_array_index(hooks, LttvTraceHook, 4));
874 g_assert(!ret);
875
876 ret = lttv_trace_find_hook(ts->parent.parent.t,
877 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
878 0, 0, 0,
879 after_irq_exit, NULL,
880 &g_array_index(hooks, LttvTraceHook, 5));
881 g_assert(!ret);
882
883
884 ret = lttv_trace_find_hook(ts->parent.parent.t,
885 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
886 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
887 process_fork, NULL,
888 &g_array_index(hooks, LttvTraceHook, 6));
889 g_assert(!ret);
890
891 ret = lttv_trace_find_hook(ts->parent.parent.t,
892 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
893 LTT_FIELD_PID, 0, 0,
894 process_exit, NULL,
895 &g_array_index(hooks, LttvTraceHook, 7));
896 g_assert(!ret);
897
898 ret = lttv_trace_find_hook(ts->parent.parent.t,
899 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
900 LTT_FIELD_PID, 0, 0,
901 process_free, NULL,
902 &g_array_index(hooks, LttvTraceHook, 8));
903 g_assert(!ret);
904
905
906 after_hooks = hooks;
907
908 /* Add these hooks to each event_by_id hooks list */
909
910 nb_tracefile = ts->parent.parent.tracefiles->len;
911
912 for(j = 0 ; j < nb_tracefile ; j++) {
913 tfs = LTTV_TRACEFILE_STATS(g_array_index(ts->parent.parent.tracefiles,
914 LttvTracefileContext*, j));
915 lttv_hooks_add(tfs->parent.parent.event, every_event, NULL,
916 LTTV_PRIO_DEFAULT);
917
918 for(k = 0 ; k < before_hooks->len ; k++) {
919 hook = &g_array_index(before_hooks, LttvTraceHook, k);
920 for(l = 0; l<hook->fac_list->len;l++) {
921 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
922 lttv_hooks_add(
923 lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
924 thf->h,
925 thf,
926 LTTV_PRIO_STATS_BEFORE_STATE);
927 }
928 }
929 for(k = 0 ; k < after_hooks->len ; k++) {
930 hook = &g_array_index(after_hooks, LttvTraceHook, k);
931 for(l = 0; l<hook->fac_list->len;l++) {
932 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
933 lttv_hooks_add(
934 lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
935 thf->h,
936 thf,
937 LTTV_PRIO_STATS_AFTER_STATE);
938 }
939 }
940 }
941 lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS,
942 LTTV_POINTER, &val);
943 *(val.v_pointer) = before_hooks;
944 lttv_attribute_find(self->parent.parent.a, LTTV_STATS_AFTER_HOOKS,
945 LTTV_POINTER, &val);
946 *(val.v_pointer) = after_hooks;
947 }
948 }
949
950 // Hook wrapper. call_data is a traceset context.
951 gboolean lttv_stats_hook_remove_event_hooks(void *hook_data, void *call_data)
952 {
953 LttvTracesetStats *tss = (LttvTracesetStats*)call_data;
954
955 lttv_stats_remove_event_hooks(tss);
956
957 return 0;
958 }
959
960 void lttv_stats_remove_event_hooks(LttvTracesetStats *self)
961 {
962 LttvTraceset *traceset = self->parent.parent.ts;
963
964 guint i, j, k, l, nb_trace, nb_tracefile;
965
966 LttvTraceStats *ts;
967
968 LttvTracefileStats *tfs;
969
970 void *hook_data;
971
972 GArray *before_hooks, *after_hooks;
973
974 LttvTraceHook *hook;
975
976 LttvTraceHookByFacility *thf;
977
978 LttvAttributeValue val;
979
980 nb_trace = lttv_traceset_number(traceset);
981 for(i = 0 ; i < nb_trace ; i++) {
982 ts = (LttvTraceStats*)self->parent.parent.traces[i];
983 lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS,
984 LTTV_POINTER, &val);
985 before_hooks = *(val.v_pointer);
986 lttv_attribute_find(self->parent.parent.a, LTTV_STATS_AFTER_HOOKS,
987 LTTV_POINTER, &val);
988 after_hooks = *(val.v_pointer);
989
990 /* Remove these hooks from each event_by_id hooks list */
991
992 nb_tracefile = ts->parent.parent.tracefiles->len;
993
994 for(j = 0 ; j < nb_tracefile ; j++) {
995 tfs = LTTV_TRACEFILE_STATS(g_array_index(ts->parent.parent.tracefiles,
996 LttvTracefileContext*, j));
997 lttv_hooks_remove_data(tfs->parent.parent.event, every_event,
998 NULL);
999
1000 for(k = 0 ; k < before_hooks->len ; k++) {
1001 hook = &g_array_index(before_hooks, LttvTraceHook, k);
1002 for(l = 0 ; l < hook->fac_list->len ; l++) {
1003 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1004 lttv_hooks_remove_data(
1005 lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
1006 thf->h,
1007 thf);
1008 }
1009 }
1010 for(k = 0 ; k < after_hooks->len ; k++) {
1011 hook = &g_array_index(after_hooks, LttvTraceHook, k);
1012 for(l = 0 ; l < hook->fac_list->len ; l++) {
1013 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1014 lttv_hooks_remove_data(
1015 lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
1016 thf->h,
1017 thf);
1018 }
1019 }
1020 }
1021 g_debug("lttv_stats_remove_event_hooks()");
1022 g_array_free(before_hooks, TRUE);
1023 g_array_free(after_hooks, TRUE);
1024 }
1025 }
1026
1027
1028 static void module_init()
1029 {
1030 LTTV_STATS_PROCESS_UNKNOWN = g_quark_from_string("unknown process");
1031 LTTV_STATS_PROCESSES = g_quark_from_string("processes");
1032 LTTV_STATS_CPU = g_quark_from_string("cpu");
1033 LTTV_STATS_MODE_TYPES = g_quark_from_string("mode_types");
1034 LTTV_STATS_MODES = g_quark_from_string("modes");
1035 LTTV_STATS_SUBMODES = g_quark_from_string("submodes");
1036 LTTV_STATS_EVENT_TYPES = g_quark_from_string("event_types");
1037 LTTV_STATS_CPU_TIME = g_quark_from_string("cpu time");
1038 LTTV_STATS_ELAPSED_TIME = g_quark_from_string("elapsed time");
1039 LTTV_STATS_EVENTS = g_quark_from_string("events");
1040 LTTV_STATS_EVENTS_COUNT = g_quark_from_string("events count");
1041 LTTV_STATS_BEFORE_HOOKS = g_quark_from_string("saved stats before hooks");
1042 LTTV_STATS_AFTER_HOOKS = g_quark_from_string("saved stats after hooks");
1043 LTTV_STATS_USE_COUNT = g_quark_from_string("stats_use_count");
1044 LTTV_STATS = g_quark_from_string("statistics");
1045 LTTV_STATS_TRACEFILES = g_quark_from_string("tracefiles statistics");
1046 LTTV_STATS_SUMMED = g_quark_from_string("statistics summed");
1047 }
1048
1049 static void module_destroy()
1050 {
1051 }
1052
1053
1054 LTTV_MODULE("stats", "Compute processes statistics", \
1055 "Accumulate statistics for event types, processes and CPUs", \
1056 module_init, module_destroy, "state");
1057
1058 /* Change the places where stats are called (create/read/write stats)
1059
1060 Check for options in batchtest.c to reduce writing and see what tests are
1061 best candidates for performance analysis. Once OK, commit, move to main
1062 and run tests. Update the gui for statistics. */
This page took 0.049503 seconds and 5 git commands to generate.