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