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