1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
21 #include <lttv/stats.h>
22 #include <lttv/lttv.h>
23 #include <ltt/facility.h>
24 #include <ltt/trace.h>
25 #include <ltt/event.h>
30 LTTV_STATS_PROCESS_UNKNOWN
,
33 LTTV_STATS_MODE_TYPES
,
36 LTTV_STATS_EVENT_TYPES
,
38 LTTV_STATS_ELAPSED_TIME
,
40 LTTV_STATS_EVENTS_COUNT
;
43 LTTV_STATS_BEFORE_HOOKS
,
44 LTTV_STATS_AFTER_HOOKS
;
46 static void remove_all_processes(GHashTable
*processes
);
49 find_event_tree(LttvTracefileStats
*tfcs
, GQuark process
, GQuark cpu
,
50 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
51 LttvAttribute
**event_types_tree
);
54 init(LttvTracesetStats
*self
, LttvTraceset
*ts
)
56 guint i
, j
, nb_trace
, nb_tracefile
;
62 LttvTracefileContext
*tfc
;
64 LttvTracefileStats
*tfcs
;
66 LttTime timestamp
= {0,0};
68 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
69 init((LttvTracesetContext
*)self
, ts
);
71 self
->stats
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
72 nb_trace
= lttv_traceset_number(ts
);
74 for(i
= 0 ; i
< nb_trace
; i
++) {
75 tcs
= (LttvTraceStats
*)tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
76 tcs
->stats
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
78 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
79 ltt_trace_per_cpu_tracefile_number(tc
->t
);
81 for(j
= 0 ; j
< nb_tracefile
; j
++) {
82 tfcs
= LTTV_TRACEFILE_STATS(tc
->tracefiles
[j
]);
83 tfcs
->stats
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
84 find_event_tree(tfcs
, LTTV_STATS_PROCESS_UNKNOWN
,
85 tfcs
->parent
.cpu_name
, LTTV_STATE_MODE_UNKNOWN
,
86 LTTV_STATE_SUBMODE_UNKNOWN
, &tfcs
->current_events_tree
,
87 &tfcs
->current_event_types_tree
);
94 fini(LttvTracesetStats
*self
)
96 guint i
, j
, nb_trace
, nb_tracefile
;
100 LttvTraceContext
*tc
;
104 LttvTracefileContext
*tfc
;
106 LttvTracefileStats
*tfcs
;
108 LttTime timestamp
= {0,0};
110 lttv_attribute_recursive_free(self
->stats
);
111 ts
= self
->parent
.parent
.ts
;
112 nb_trace
= lttv_traceset_number(ts
);
114 for(i
= 0 ; i
< nb_trace
; i
++) {
115 tcs
= (LttvTraceStats
*)tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
116 lttv_attribute_recursive_free(tcs
->stats
);
118 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
119 ltt_trace_per_cpu_tracefile_number(tc
->t
);
121 for(j
= 0 ; j
< nb_tracefile
; j
++) {
122 tfcs
= (LttvTracefileStats
*)tfc
= tc
->tracefiles
[j
];
123 lttv_attribute_recursive_free(tfcs
->stats
);
124 tfcs
->current_events_tree
= NULL
;
125 tfcs
->current_event_types_tree
= NULL
;
128 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
129 fini((LttvTracesetContext
*)self
);
133 static LttvTracesetContext
*
134 new_traceset_context(LttvTracesetContext
*self
)
136 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE
, NULL
));
140 static LttvTraceContext
*
141 new_trace_context(LttvTracesetContext
*self
)
143 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE
, NULL
));
147 static LttvTracefileContext
*
148 new_tracefile_context(LttvTracesetContext
*self
)
150 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE
, NULL
));
155 traceset_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
161 traceset_stats_finalize (LttvTracesetStats
*self
)
163 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
164 finalize(G_OBJECT(self
));
169 traceset_stats_class_init (LttvTracesetContextClass
*klass
)
171 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
173 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_stats_finalize
;
174 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
175 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
176 klass
->new_traceset_context
= new_traceset_context
;
177 klass
->new_trace_context
= new_trace_context
;
178 klass
->new_tracefile_context
= new_tracefile_context
;
183 lttv_traceset_stats_get_type(void)
185 static GType type
= 0;
187 static const GTypeInfo info
= {
188 sizeof (LttvTracesetStatsClass
),
189 NULL
, /* base_init */
190 NULL
, /* base_finalize */
191 (GClassInitFunc
) traceset_stats_class_init
, /* class_init */
192 NULL
, /* class_finalize */
193 NULL
, /* class_data */
194 sizeof (LttvTracesetStats
),
196 (GInstanceInitFunc
) traceset_stats_instance_init
/* instance_init */
199 type
= g_type_register_static (LTTV_TRACESET_STATE_TYPE
, "LttvTracesetStatsType",
207 trace_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
213 trace_stats_finalize (LttvTraceStats
*self
)
215 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE
))->
216 finalize(G_OBJECT(self
));
221 trace_stats_class_init (LttvTraceContextClass
*klass
)
223 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
225 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_stats_finalize
;
230 lttv_trace_stats_get_type(void)
232 static GType type
= 0;
234 static const GTypeInfo info
= {
235 sizeof (LttvTraceStatsClass
),
236 NULL
, /* base_init */
237 NULL
, /* base_finalize */
238 (GClassInitFunc
) trace_stats_class_init
, /* class_init */
239 NULL
, /* class_finalize */
240 NULL
, /* class_data */
241 sizeof (LttvTraceStats
),
243 (GInstanceInitFunc
) trace_stats_instance_init
/* instance_init */
246 type
= g_type_register_static (LTTV_TRACE_STATE_TYPE
,
247 "LttvTraceStatsType", &info
, 0);
254 tracefile_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
260 tracefile_stats_finalize (LttvTracefileStats
*self
)
262 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE
))->
263 finalize(G_OBJECT(self
));
268 tracefile_stats_class_init (LttvTracefileStatsClass
*klass
)
270 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
272 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_stats_finalize
;
277 lttv_tracefile_stats_get_type(void)
279 static GType type
= 0;
281 static const GTypeInfo info
= {
282 sizeof (LttvTracefileStatsClass
),
283 NULL
, /* base_init */
284 NULL
, /* base_finalize */
285 (GClassInitFunc
) tracefile_stats_class_init
, /* class_init */
286 NULL
, /* class_finalize */
287 NULL
, /* class_data */
288 sizeof (LttvTracefileStats
),
290 (GInstanceInitFunc
) tracefile_stats_instance_init
/* instance_init */
293 type
= g_type_register_static (LTTV_TRACEFILE_STATE_TYPE
,
294 "LttvTracefileStatsType", &info
, 0);
301 find_event_tree(LttvTracefileStats
*tfcs
, GQuark process
, GQuark cpu
,
302 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
303 LttvAttribute
**event_types_tree
)
307 LttvTraceStats
*tcs
= LTTV_TRACE_STATS(tfcs
->parent
.parent
.t_context
);
308 a
= lttv_attribute_find_subdir(tcs
->stats
, LTTV_STATS_PROCESSES
);
309 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->pid_time
);
310 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_CPU
);
311 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.cpu_name
);
312 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_MODE_TYPES
);
313 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->state
->t
);
314 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_SUBMODES
);
315 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->state
->n
);
317 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_EVENT_TYPES
);
318 *event_types_tree
= a
;
322 static void update_event_tree(LttvTracefileStats
*tfcs
)
324 LttvExecutionState
*es
= tfcs
->parent
.process
->state
;
326 find_event_tree(tfcs
, tfcs
->parent
.process
->pid_time
, tfcs
->parent
.cpu_name
,
327 es
->t
, es
->n
, &(tfcs
->current_events_tree
),
328 &(tfcs
->current_event_types_tree
));
332 static void mode_change(LttvTracefileStats
*tfcs
)
334 LttvAttributeValue cpu_time
;
338 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
339 LTTV_TIME
, &cpu_time
);
340 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
341 tfcs
->parent
.process
->state
->change
);
342 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
346 static void mode_end(LttvTracefileStats
*tfcs
)
348 LttvAttributeValue elapsed_time
, cpu_time
;
352 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_ELAPSED_TIME
,
353 LTTV_TIME
, &elapsed_time
);
354 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
355 tfcs
->parent
.process
->state
->entry
);
356 *(elapsed_time
.v_time
) = ltt_time_add(*(elapsed_time
.v_time
), delta
);
358 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
359 LTTV_TIME
, &cpu_time
);
360 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
361 tfcs
->parent
.process
->state
->change
);
362 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
366 static gboolean
before_syscall_entry(void *hook_data
, void *call_data
)
368 mode_change((LttvTracefileStats
*)call_data
);
373 static gboolean
after_syscall_entry(void *hook_data
, void *call_data
)
375 update_event_tree((LttvTracefileStats
*)call_data
);
380 gboolean
before_syscall_exit(void *hook_data
, void *call_data
)
382 mode_end((LttvTracefileStats
*)call_data
);
387 static gboolean
after_syscall_exit(void *hook_data
, void *call_data
)
389 update_event_tree((LttvTracefileStats
*)call_data
);
394 gboolean
before_trap_entry(void *hook_data
, void *call_data
)
396 mode_change((LttvTracefileStats
*)call_data
);
401 static gboolean
after_trap_entry(void *hook_data
, void *call_data
)
403 update_event_tree((LttvTracefileStats
*)call_data
);
408 gboolean
before_trap_exit(void *hook_data
, void *call_data
)
410 mode_end((LttvTracefileStats
*)call_data
);
415 gboolean
after_trap_exit(void *hook_data
, void *call_data
)
417 update_event_tree((LttvTracefileStats
*)call_data
);
422 gboolean
before_irq_entry(void *hook_data
, void *call_data
)
424 mode_change((LttvTracefileStats
*)call_data
);
429 gboolean
after_irq_entry(void *hook_data
, void *call_data
)
431 update_event_tree((LttvTracefileStats
*)call_data
);
436 gboolean
before_irq_exit(void *hook_data
, void *call_data
)
438 mode_end((LttvTracefileStats
*)call_data
);
443 gboolean
after_irq_exit(void *hook_data
, void *call_data
)
445 update_event_tree((LttvTracefileStats
*)call_data
);
450 gboolean
before_schedchange(void *hook_data
, void *call_data
)
452 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
454 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
456 guint pid_in
, pid_out
, state_out
;
458 LttvProcessState
*process
;
460 pid_in
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f1
);
461 pid_out
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f2
);
462 state_out
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f3
);
464 /* compute the time for the process to schedule out */
468 /* get the information for the process scheduled in */
470 process
= lttv_state_find_process_or_create(&(tfcs
->parent
), pid_in
);
472 find_event_tree(tfcs
, process
->pid_time
, tfcs
->parent
.cpu_name
,
473 process
->state
->t
, process
->state
->n
, &(tfcs
->current_events_tree
),
474 &(tfcs
->current_event_types_tree
));
476 /* compute the time waiting for the process to schedule in */
483 gboolean
process_fork(void *hook_data
, void *call_data
)
485 /* nothing to do for now */
490 gboolean
process_exit(void *hook_data
, void *call_data
)
492 /* We should probably exit all modes here or we could do that at
498 gboolean
every_event(void *hook_data
, void *call_data
)
500 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
502 LttvAttributeValue v
;
504 /* The current branch corresponds to the tracefile/process/interrupt state.
505 Statistics are added within it, to count the number of events of this
506 type occuring in this context. A quark has been pre-allocated for each
507 event type and is used as name. */
509 lttv_attribute_find(tfcs
->current_event_types_tree
,
510 ((LttvTraceState
*)(tfcs
->parent
.parent
.t_context
))->
511 eventtype_names
[ltt_event_eventtype_id(tfcs
->parent
.parent
.e
)],
519 sum_stats(void *hook_data
, void *call_data
)
521 LttvTracesetStats
*tscs
= (LttvTracesetStats
*)call_data
;
525 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
527 LttvAttributeType type
;
529 LttvAttributeValue value
;
531 LttvAttributeName name
;
535 int i
, j
, k
, l
, m
, n
, nb_trace
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
,
538 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
539 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
540 *submode_tree
, *event_types_tree
, *mode_events_tree
,
541 *cpu_events_tree
, *process_modes_tree
, *trace_cpu_tree
,
542 *trace_modes_tree
, *traceset_modes_tree
;
544 traceset_modes_tree
= lttv_attribute_find_subdir(tscs
->stats
,
546 nb_trace
= lttv_traceset_number(traceset
);
548 for(i
= 0 ; i
< nb_trace
; i
++) {
549 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
550 main_tree
= tcs
->stats
;
551 processes_tree
= lttv_attribute_find_subdir(main_tree
,
552 LTTV_STATS_PROCESSES
);
553 trace_modes_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_MODES
);
554 nb_process
= lttv_attribute_get_number(processes_tree
);
556 for(j
= 0 ; j
< nb_process
; j
++) {
557 type
= lttv_attribute_get(processes_tree
, j
, &name
, &value
);
558 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
560 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
561 process_modes_tree
= lttv_attribute_find_subdir(process_tree
,
563 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
565 for(k
= 0 ; k
< nb_cpu
; k
++) {
566 type
= lttv_attribute_get(cpus_tree
, k
, &name
, &value
);
567 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
569 mode_types_tree
= lttv_attribute_find_subdir(cpu_tree
,
570 LTTV_STATS_MODE_TYPES
);
571 cpu_events_tree
= lttv_attribute_find_subdir(cpu_tree
,
573 trace_cpu_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_CPU
);
574 trace_cpu_tree
= lttv_attribute_find_subdir(trace_cpu_tree
, name
);
575 nb_mode_type
= lttv_attribute_get_number(mode_types_tree
);
577 for(l
= 0 ; l
< nb_mode_type
; l
++) {
578 type
= lttv_attribute_get(mode_types_tree
, l
, &name
, &value
);
579 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
581 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,
582 LTTV_STATS_SUBMODES
);
583 mode_events_tree
= lttv_attribute_find_subdir(mode_tree
,
585 nb_submode
= lttv_attribute_get_number(submodes_tree
);
587 for(m
= 0 ; m
< nb_submode
; m
++) {
588 type
= lttv_attribute_get(submodes_tree
, m
, &name
, &value
);
589 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
591 event_types_tree
= lttv_attribute_find_subdir(submode_tree
,
592 LTTV_STATS_EVENT_TYPES
);
593 nb_event_type
= lttv_attribute_get_number(event_types_tree
);
596 for(n
= 0 ; n
< nb_event_type
; n
++) {
597 type
= lttv_attribute_get(event_types_tree
, n
, &name
, &value
);
598 sum
+= *(value
.v_uint
);
600 lttv_attribute_find(submode_tree
, LTTV_STATS_EVENTS_COUNT
,
602 *(value
.v_uint
) = sum
;
603 lttv_attribute_recursive_add(mode_events_tree
, submode_tree
);
605 lttv_attribute_recursive_add(cpu_events_tree
, mode_events_tree
);
607 lttv_attribute_recursive_add(process_modes_tree
, cpu_tree
);
608 lttv_attribute_recursive_add(trace_cpu_tree
, cpu_tree
);
610 lttv_attribute_recursive_add(trace_modes_tree
, process_modes_tree
);
612 lttv_attribute_recursive_add(traceset_modes_tree
, trace_modes_tree
);
618 lttv_stats_add_event_hooks(LttvTracesetStats
*self
)
620 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
622 guint i
, j
, k
, nb_trace
, nb_tracefile
;
630 LttvTracefileStats
*tfs
;
634 GArray
*hooks
, *before_hooks
, *after_hooks
;
638 LttvAttributeValue val
;
640 nb_trace
= lttv_traceset_number(traceset
);
641 for(i
= 0 ; i
< nb_trace
; i
++) {
642 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
644 /* Find the eventtype id for the following events and register the
645 associated by id hooks. */
647 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
648 g_array_set_size(hooks
, 7);
650 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core","syscall_entry",
651 "syscall_id", NULL
, NULL
, before_syscall_entry
,
652 &g_array_index(hooks
, LttvTraceHook
, 0));
654 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "syscall_exit", NULL
,
655 NULL
, NULL
, before_syscall_exit
,
656 &g_array_index(hooks
, LttvTraceHook
, 1));
658 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_entry", "trap_id",
659 NULL
, NULL
, before_trap_entry
,
660 &g_array_index(hooks
, LttvTraceHook
, 2));
662 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_exit", NULL
, NULL
,
663 NULL
, before_trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
665 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_entry", "irq_id",
666 NULL
, NULL
, before_irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
668 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_exit", NULL
, NULL
,
669 NULL
, before_irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
671 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "schedchange", "in",
672 "out", "out_state", before_schedchange
,
673 &g_array_index(hooks
, LttvTraceHook
, 6));
675 before_hooks
= hooks
;
677 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
678 g_array_set_size(hooks
, 8);
680 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core","syscall_entry",
681 "syscall_id", NULL
, NULL
, after_syscall_entry
,
682 &g_array_index(hooks
, LttvTraceHook
, 0));
684 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "syscall_exit", NULL
,
685 NULL
, NULL
, after_syscall_exit
,
686 &g_array_index(hooks
, LttvTraceHook
, 1));
688 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_entry", "trap_id",
689 NULL
, NULL
, after_trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
691 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_exit", NULL
, NULL
,
692 NULL
, after_trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
694 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_entry", "irq_id",
695 NULL
, NULL
, after_irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
697 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_exit", NULL
, NULL
,
698 NULL
, after_irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
700 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "process_fork",
701 "child_pid", NULL
, NULL
, process_fork
,
702 &g_array_index(hooks
, LttvTraceHook
, 6));
704 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "process_exit", NULL
,
705 NULL
, NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 7));
709 /* Add these hooks to each before_event_by_id hooks list */
711 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.parent
.t
) +
712 ltt_trace_per_cpu_tracefile_number(ts
->parent
.parent
.t
);
714 for(j
= 0 ; j
< nb_tracefile
; j
++) {
715 tfs
= LTTV_TRACEFILE_STATS(ts
->parent
.parent
.tracefiles
[j
]);
716 lttv_hooks_add(tfs
->parent
.parent
.after_event
, every_event
, NULL
);
718 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
719 hook
= g_array_index(before_hooks
, LttvTraceHook
, k
);
720 lttv_hooks_add(lttv_hooks_by_id_find(
721 tfs
->parent
.parent
.before_event_by_id
,
722 hook
.id
), hook
.h
, &g_array_index(before_hooks
, LttvTraceHook
, k
));
724 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
725 hook
= g_array_index(after_hooks
, LttvTraceHook
, k
);
726 lttv_hooks_add(lttv_hooks_by_id_find(
727 tfs
->parent
.parent
.after_event_by_id
,
728 hook
.id
), hook
.h
, &g_array_index(after_hooks
, LttvTraceHook
, k
));
731 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
733 *(val
.v_pointer
) = before_hooks
;
734 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
736 *(val
.v_pointer
) = after_hooks
;
738 lttv_hooks_add(self
->parent
.parent
.after
, sum_stats
, NULL
);
742 lttv_stats_remove_event_hooks(LttvTracesetStats
*self
)
744 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
746 guint i
, j
, k
, nb_trace
, nb_tracefile
;
750 LttvTracefileStats
*tfs
;
754 GArray
*before_hooks
, *after_hooks
;
758 LttvAttributeValue val
;
760 nb_trace
= lttv_traceset_number(traceset
);
761 for(i
= 0 ; i
< nb_trace
; i
++) {
762 ts
= LTTV_TRACE_STATS(self
->parent
.parent
.traces
[i
]);
763 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
765 before_hooks
= *(val
.v_pointer
);
766 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
768 after_hooks
= *(val
.v_pointer
);
770 /* Add these hooks to each before_event_by_id hooks list */
772 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.parent
.t
) +
773 ltt_trace_per_cpu_tracefile_number(ts
->parent
.parent
.t
);
775 for(j
= 0 ; j
< nb_tracefile
; j
++) {
776 tfs
= LTTV_TRACEFILE_STATS(ts
->parent
.parent
.tracefiles
[j
]);
777 lttv_hooks_remove_data(tfs
->parent
.parent
.after_event
, every_event
,
780 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
781 hook
= g_array_index(before_hooks
, LttvTraceHook
, k
);
782 lttv_hooks_remove_data(
783 lttv_hooks_by_id_find(tfs
->parent
.parent
.before_event_by_id
,
784 hook
.id
), hook
.h
, &g_array_index(before_hooks
, LttvTraceHook
, k
));
786 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
787 hook
= g_array_index(after_hooks
, LttvTraceHook
, k
);
788 lttv_hooks_remove_data(
789 lttv_hooks_by_id_find(tfs
->parent
.parent
.after_event_by_id
,
790 hook
.id
), hook
.h
, &g_array_index(after_hooks
, LttvTraceHook
, k
));
793 g_debug("lttv_stats_remove_event_hooks()");
794 g_array_free(before_hooks
, TRUE
);
795 g_array_free(after_hooks
, TRUE
);
797 lttv_hooks_remove_data(self
->parent
.parent
.after
, sum_stats
, NULL
);
801 void lttv_stats_init(int argc
, char **argv
)
803 LTTV_STATS_PROCESS_UNKNOWN
= g_quark_from_string("unknown process");
804 LTTV_STATS_PROCESSES
= g_quark_from_string("processes");
805 LTTV_STATS_CPU
= g_quark_from_string("cpu");
806 LTTV_STATS_MODE_TYPES
= g_quark_from_string("mode_types");
807 LTTV_STATS_MODES
= g_quark_from_string("modes");
808 LTTV_STATS_SUBMODES
= g_quark_from_string("submodes");
809 LTTV_STATS_EVENT_TYPES
= g_quark_from_string("event_types");
810 LTTV_STATS_CPU_TIME
= g_quark_from_string("cpu time");
811 LTTV_STATS_ELAPSED_TIME
= g_quark_from_string("elapsed time");
812 LTTV_STATS_EVENTS
= g_quark_from_string("events");
813 LTTV_STATS_EVENTS_COUNT
= g_quark_from_string("events count");
814 LTTV_STATS_BEFORE_HOOKS
= g_quark_from_string("saved stats before hooks");
815 LTTV_STATS_AFTER_HOOKS
= g_quark_from_string("saved stats after hooks");
818 void lttv_stats_destroy()
822 void lttv_stats_save_attribute(LttvAttribute
*attr
, char *indent
, FILE * fp
)
824 LttvAttributeType type
;
825 LttvAttributeValue value
;
826 LttvAttributeName name
;
827 char type_value
[BUF_SIZE
];
828 int i
, nb_attr
, flag
;
830 nb_attr
= lttv_attribute_get_number(attr
);
831 for(i
=0;i
<nb_attr
;i
++){
833 type
= lttv_attribute_get(attr
, i
, &name
, &value
);
836 sprintf(type_value
, "%d\0", *value
.v_int
);
839 sprintf(type_value
, "%u\0", *value
.v_uint
);
842 sprintf(type_value
, "%ld\0", *value
.v_long
);
845 sprintf(type_value
, "%lu\0", *value
.v_ulong
);
848 sprintf(type_value
, "%f\0", (double)*value
.v_float
);
851 sprintf(type_value
, "%f\0", *value
.v_double
);
854 sprintf(type_value
, "%10u.%09u\0", value
.v_time
->tv_sec
,
855 value
.v_time
->tv_nsec
);
858 sprintf(type_value
, "POINTER\0");
861 sprintf(type_value
, "%s\0", *value
.v_string
);
867 if(flag
== 0) continue;
868 fprintf(fp
,"%s<VALUE type=\"%d\" name=\"%s\">",indent
,type
,g_quark_to_string(name
));
869 fprintf(fp
,"%s",type_value
);
870 fprintf(fp
,"</VALUE> \n");
875 void lttv_stats_save_statistics(LttvTracesetStats
*self
)
877 LttvTracesetStats
*tscs
= self
;
879 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
880 LttvAttributeType type
;
881 LttvAttributeValue value
;
882 LttvAttributeName name
;
884 char filename
[BUF_SIZE
];
886 char indent
[10][24]= {" ",
899 int i
, j
, k
, l
, m
, n
, nb_trace
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
;
901 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
902 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
903 *submode_tree
, *event_types_tree
;
905 nb_trace
= lttv_traceset_number(traceset
);
907 for(i
= 0 ; i
< nb_trace
; i
++) {
908 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
911 strcat(filename
,ltt_trace_name(tcs
->parent
.parent
.t
));
912 strcat(filename
,"/statistics.xml");
913 fp
= fopen(filename
,"w");
915 g_warning("can not open the file %s for saving statistics\n", filename
);
919 main_tree
= tcs
->stats
;
920 processes_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_PROCESSES
);
921 nb_process
= lttv_attribute_get_number(processes_tree
);
923 fprintf(fp
, "<NODE name=\"%s\"> \n",g_quark_to_string(LTTV_STATS_PROCESSES
)); //root NODE
925 for(j
= 0 ; j
< nb_process
; j
++) {
926 type
= lttv_attribute_get(processes_tree
, j
, &name
, &value
);
927 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
929 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[0],g_quark_to_string(name
)); //process NODE
930 lttv_stats_save_attribute(process_tree
,indent
[1], fp
);
931 fprintf(fp
,"%s<NODE name=\"%s\"> \n", indent
[1],g_quark_to_string(LTTV_STATS_CPU
)); //cpus NODE
933 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
934 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
936 for(k
= 0 ; k
< nb_cpu
; k
++) {
937 type
= lttv_attribute_get(cpus_tree
, k
, &name
, &value
);
938 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
940 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[2],g_quark_to_string(name
)); //cpu NODE
941 lttv_stats_save_attribute(cpu_tree
,indent
[3], fp
);
942 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[3],g_quark_to_string(LTTV_STATS_MODE_TYPES
)); //mode_types NODE
944 mode_types_tree
= lttv_attribute_find_subdir(cpu_tree
,LTTV_STATS_MODE_TYPES
);
945 nb_mode_type
= lttv_attribute_get_number(mode_types_tree
);
947 for(l
= 0 ; l
< nb_mode_type
; l
++) {
948 type
= lttv_attribute_get(mode_types_tree
, l
, &name
, &value
);
949 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
951 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[4],g_quark_to_string(name
)); //mode NODE
952 lttv_stats_save_attribute(mode_tree
,indent
[5], fp
);
953 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[5],g_quark_to_string(LTTV_STATS_SUBMODES
)); //sub_modes NODE
955 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,LTTV_STATS_SUBMODES
);
956 nb_submode
= lttv_attribute_get_number(submodes_tree
);
958 for(m
= 0 ; m
< nb_submode
; m
++) {
959 type
= lttv_attribute_get(submodes_tree
, m
, &name
, &value
);
960 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
961 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[6],g_quark_to_string(name
)); //sub_mode NODE
962 lttv_stats_save_attribute(submode_tree
,indent
[7], fp
);
963 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[7],g_quark_to_string(LTTV_STATS_EVENT_TYPES
)); //event_types NODE
965 event_types_tree
= lttv_attribute_find_subdir(submode_tree
, LTTV_STATS_EVENT_TYPES
);
966 lttv_stats_save_attribute(event_types_tree
,indent
[8], fp
);
968 fprintf(fp
,"%s</NODE> \n",indent
[7]); //event_types NODE
969 fprintf(fp
,"%s</NODE> \n",indent
[6]); //sub_mode NODE
971 fprintf(fp
,"%s</NODE> \n",indent
[5]); //sub_modes NODE
972 fprintf(fp
,"%s</NODE> \n",indent
[4]); //mode NODE
974 fprintf(fp
,"%s</NODE> \n",indent
[3]); //mode_type NODE
975 fprintf(fp
,"%s</NODE> \n",indent
[2]); //cpu NODE
977 fprintf(fp
,"%s</NODE> \n",indent
[1]); //cpus NODE
978 fprintf(fp
,"%s</NODE> \n", indent
[0]); //process NODE
980 fprintf(fp
, "</NODE>\n"); //root NODE
986 /* Functions to parse statistic.xml file (using glib xml parser) */
988 typedef struct _ParserStruct
{
989 GPtrArray
* attribute
;
990 LttvAttributeType type
;
991 LttvAttributeName name
;
994 static void stats_parser_start_element (GMarkupParseContext
*context
,
995 const gchar
*element_name
,
996 const gchar
**attribute_names
,
997 const gchar
**attribute_values
,
1001 ParserStruct
* parser
= (ParserStruct
*)user_data
;
1003 LttvAttributeType type
;
1004 LttvAttributeName name
;
1005 LttvAttribute
* parent_att
, *new_att
;
1007 len
= parser
->attribute
->len
;
1008 parent_att
= (LttvAttribute
*)g_ptr_array_index (parser
->attribute
, len
-1);
1010 if(strcmp("NODE", element_name
) == 0){
1011 type
= LTTV_GOBJECT
;
1012 name
= g_quark_from_string(attribute_values
[0]);
1013 new_att
= lttv_attribute_find_subdir(parent_att
,name
);
1014 g_ptr_array_add(parser
->attribute
, (gpointer
)new_att
);
1015 }else if(strcmp("VALUE", element_name
) == 0){
1016 parser
->type
= (LttvAttributeType
) atoi(attribute_values
[0]);
1017 parser
->name
= g_quark_from_string(attribute_values
[1]);
1019 g_warning("This is not statistics.xml file\n");
1024 static void stats_parser_end_element (GMarkupParseContext
*context
,
1025 const gchar
*element_name
,
1029 ParserStruct
* parser
= (ParserStruct
*)user_data
;
1031 LttvAttribute
* parent_att
;
1033 len
= parser
->attribute
->len
;
1034 parent_att
= (LttvAttribute
*)g_ptr_array_index (parser
->attribute
, len
-1);
1036 if(strcmp("NODE", element_name
) == 0){
1037 g_ptr_array_remove_index(parser
->attribute
, len
-1);
1038 }else if(strcmp("VALUE", element_name
) == 0){
1040 g_warning("This is not statistics.xml file\n");
1046 static void stats_parser_characters (GMarkupParseContext
*context
,
1052 ParserStruct
* parser
= (ParserStruct
*)user_data
;
1053 LttvAttributeValue value
;
1055 LttvAttribute
* parent_att
;
1059 for(len
=0;len
<text_len
;len
++){
1066 if(strlen(pos
) == 0)return;
1068 len
= parser
->attribute
->len
;
1069 parent_att
= (LttvAttribute
*)g_ptr_array_index (parser
->attribute
, len
-1);
1070 if(!lttv_attribute_find(parent_att
,parser
->name
, parser
->type
, &value
)){
1071 g_warning("can not find value\n");
1075 switch(parser
->type
) {
1077 *value
.v_int
= atoi(text
);
1080 *value
.v_uint
= (unsigned)atoi(text
);
1083 *value
.v_long
= atol(text
);
1086 *value
.v_ulong
= (unsigned long)atol(text
);
1089 *value
.v_float
= atof(text
);
1092 *value
.v_float
= atof(text
);
1095 pos
= strrchr(text
,'.');
1099 value
.v_time
->tv_sec
= atol(text
);
1100 value
.v_time
->tv_nsec
= atol(pos
);
1102 g_warning("The time value format is wrong\n");
1109 *value
.v_string
= g_strdup(text
);
1117 gboolean
lttv_stats_load_statistics(LttvTracesetStats
*self
)
1121 LttvTracesetStats
*tscs
= self
;
1122 LttvTraceStats
*tcs
;
1123 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
1124 char filename
[BUF_SIZE
];
1126 GMarkupParseContext
* context
;
1128 GMarkupParser markup_parser
=
1130 stats_parser_start_element
,
1131 stats_parser_end_element
,
1132 stats_parser_characters
,
1133 NULL
, /* passthrough */
1138 LttvAttribute
*main_tree
;
1139 ParserStruct a_parser_struct
;
1140 a_parser_struct
.attribute
= g_ptr_array_new();
1142 nb_trace
= lttv_traceset_number(traceset
);
1144 for(i
= 0 ; i
< nb_trace
; i
++) {
1145 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
1148 strcat(filename
,ltt_trace_name(tcs
->parent
.parent
.t
));
1149 strcat(filename
,"/statistics.xml");
1150 fp
= fopen(filename
,"r");
1152 g_warning("can not open the file %s for reading statistics\n", filename
);
1156 main_tree
= tcs
->stats
;
1157 g_ptr_array_add(a_parser_struct
.attribute
,(gpointer
)main_tree
);
1159 context
= g_markup_parse_context_new(&markup_parser
, 0, (gpointer
)&a_parser_struct
, NULL
);
1161 while(fgets(buf
,BUF_SIZE
, fp
) != NULL
){
1162 if(!g_markup_parse_context_parse(context
, buf
, BUF_SIZE
, &error
)){
1163 g_warning("Can not parse xml file: \n%s\n", error
->message
);
1170 sum_stats(NULL
, (void *)self
);