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