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