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