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