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