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