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/module.h>
22 #include <lttv/stats.h>
23 #include <lttv/lttv.h>
24 #include <ltt/facility.h>
25 #include <ltt/trace.h>
26 #include <ltt/event.h>
31 LTTV_STATS_PROCESS_UNKNOWN
,
34 LTTV_STATS_MODE_TYPES
,
37 LTTV_STATS_EVENT_TYPES
,
39 LTTV_STATS_ELAPSED_TIME
,
41 LTTV_STATS_EVENTS_COUNT
;
44 LTTV_STATS_BEFORE_HOOKS
,
45 LTTV_STATS_AFTER_HOOKS
;
47 static void remove_all_processes(GHashTable
*processes
);
50 find_event_tree(LttvTracefileStats
*tfcs
, GQuark process
, GQuark cpu
,
51 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
52 LttvAttribute
**event_types_tree
);
55 init(LttvTracesetStats
*self
, LttvTraceset
*ts
)
57 guint i
, j
, nb_trace
, nb_tracefile
;
63 LttvTracefileContext
*tfc
;
65 LttvTracefileStats
*tfcs
;
67 LttTime timestamp
= {0,0};
69 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
70 init((LttvTracesetContext
*)self
, ts
);
72 self
->stats
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
73 nb_trace
= lttv_traceset_number(ts
);
75 for(i
= 0 ; i
< nb_trace
; i
++) {
76 tcs
= (LttvTraceStats
*)tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
77 tcs
->stats
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
79 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
80 ltt_trace_per_cpu_tracefile_number(tc
->t
);
82 for(j
= 0 ; j
< nb_tracefile
; j
++) {
83 tfcs
= LTTV_TRACEFILE_STATS(tc
->tracefiles
[j
]);
84 tfcs
->stats
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
85 find_event_tree(tfcs
, LTTV_STATS_PROCESS_UNKNOWN
,
86 tfcs
->parent
.cpu_name
, LTTV_STATE_MODE_UNKNOWN
,
87 LTTV_STATE_SUBMODE_UNKNOWN
, &tfcs
->current_events_tree
,
88 &tfcs
->current_event_types_tree
);
95 fini(LttvTracesetStats
*self
)
97 guint i
, j
, nb_trace
, nb_tracefile
;
101 LttvTraceContext
*tc
;
105 LttvTracefileContext
*tfc
;
107 LttvTracefileStats
*tfcs
;
109 LttTime timestamp
= {0,0};
111 lttv_attribute_recursive_free(self
->stats
);
112 ts
= self
->parent
.parent
.ts
;
113 nb_trace
= lttv_traceset_number(ts
);
115 for(i
= 0 ; i
< nb_trace
; i
++) {
116 tcs
= (LttvTraceStats
*)tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
117 lttv_attribute_recursive_free(tcs
->stats
);
119 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
120 ltt_trace_per_cpu_tracefile_number(tc
->t
);
122 for(j
= 0 ; j
< nb_tracefile
; j
++) {
123 tfcs
= (LttvTracefileStats
*)tfc
= tc
->tracefiles
[j
];
124 lttv_attribute_recursive_free(tfcs
->stats
);
125 tfcs
->current_events_tree
= NULL
;
126 tfcs
->current_event_types_tree
= NULL
;
129 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
130 fini((LttvTracesetContext
*)self
);
134 static LttvTracesetContext
*
135 new_traceset_context(LttvTracesetContext
*self
)
137 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE
, NULL
));
141 static LttvTraceContext
*
142 new_trace_context(LttvTracesetContext
*self
)
144 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE
, NULL
));
148 static LttvTracefileContext
*
149 new_tracefile_context(LttvTracesetContext
*self
)
151 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE
, NULL
));
156 traceset_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
162 traceset_stats_finalize (LttvTracesetStats
*self
)
164 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
165 finalize(G_OBJECT(self
));
170 traceset_stats_class_init (LttvTracesetContextClass
*klass
)
172 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
174 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_stats_finalize
;
175 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
176 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
177 klass
->new_traceset_context
= new_traceset_context
;
178 klass
->new_trace_context
= new_trace_context
;
179 klass
->new_tracefile_context
= new_tracefile_context
;
184 lttv_traceset_stats_get_type(void)
186 static GType type
= 0;
188 static const GTypeInfo info
= {
189 sizeof (LttvTracesetStatsClass
),
190 NULL
, /* base_init */
191 NULL
, /* base_finalize */
192 (GClassInitFunc
) traceset_stats_class_init
, /* class_init */
193 NULL
, /* class_finalize */
194 NULL
, /* class_data */
195 sizeof (LttvTracesetStats
),
197 (GInstanceInitFunc
) traceset_stats_instance_init
/* instance_init */
200 type
= g_type_register_static (LTTV_TRACESET_STATE_TYPE
, "LttvTracesetStatsType",
208 trace_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
214 trace_stats_finalize (LttvTraceStats
*self
)
216 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE
))->
217 finalize(G_OBJECT(self
));
222 trace_stats_class_init (LttvTraceContextClass
*klass
)
224 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
226 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_stats_finalize
;
231 lttv_trace_stats_get_type(void)
233 static GType type
= 0;
235 static const GTypeInfo info
= {
236 sizeof (LttvTraceStatsClass
),
237 NULL
, /* base_init */
238 NULL
, /* base_finalize */
239 (GClassInitFunc
) trace_stats_class_init
, /* class_init */
240 NULL
, /* class_finalize */
241 NULL
, /* class_data */
242 sizeof (LttvTraceStats
),
244 (GInstanceInitFunc
) trace_stats_instance_init
/* instance_init */
247 type
= g_type_register_static (LTTV_TRACE_STATE_TYPE
,
248 "LttvTraceStatsType", &info
, 0);
255 tracefile_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
261 tracefile_stats_finalize (LttvTracefileStats
*self
)
263 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE
))->
264 finalize(G_OBJECT(self
));
269 tracefile_stats_class_init (LttvTracefileStatsClass
*klass
)
271 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
273 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_stats_finalize
;
278 lttv_tracefile_stats_get_type(void)
280 static GType type
= 0;
282 static const GTypeInfo info
= {
283 sizeof (LttvTracefileStatsClass
),
284 NULL
, /* base_init */
285 NULL
, /* base_finalize */
286 (GClassInitFunc
) tracefile_stats_class_init
, /* class_init */
287 NULL
, /* class_finalize */
288 NULL
, /* class_data */
289 sizeof (LttvTracefileStats
),
291 (GInstanceInitFunc
) tracefile_stats_instance_init
/* instance_init */
294 type
= g_type_register_static (LTTV_TRACEFILE_STATE_TYPE
,
295 "LttvTracefileStatsType", &info
, 0);
302 find_event_tree(LttvTracefileStats
*tfcs
, GQuark process
, GQuark cpu
,
303 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
304 LttvAttribute
**event_types_tree
)
308 LttvTraceStats
*tcs
= LTTV_TRACE_STATS(tfcs
->parent
.parent
.t_context
);
309 a
= lttv_attribute_find_subdir(tcs
->stats
, LTTV_STATS_PROCESSES
);
310 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->pid_time
);
311 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_CPU
);
312 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.cpu_name
);
313 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_MODE_TYPES
);
314 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->state
->t
);
315 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_SUBMODES
);
316 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->state
->n
);
318 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_EVENT_TYPES
);
319 *event_types_tree
= a
;
323 static void update_event_tree(LttvTracefileStats
*tfcs
)
325 LttvExecutionState
*es
= tfcs
->parent
.process
->state
;
327 find_event_tree(tfcs
, tfcs
->parent
.process
->pid_time
, tfcs
->parent
.cpu_name
,
328 es
->t
, es
->n
, &(tfcs
->current_events_tree
),
329 &(tfcs
->current_event_types_tree
));
333 static void mode_change(LttvTracefileStats
*tfcs
)
335 LttvAttributeValue cpu_time
;
339 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
340 LTTV_TIME
, &cpu_time
);
341 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
342 tfcs
->parent
.process
->state
->change
);
343 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
347 static void mode_end(LttvTracefileStats
*tfcs
)
349 LttvAttributeValue elapsed_time
, cpu_time
;
353 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_ELAPSED_TIME
,
354 LTTV_TIME
, &elapsed_time
);
355 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
356 tfcs
->parent
.process
->state
->entry
);
357 *(elapsed_time
.v_time
) = ltt_time_add(*(elapsed_time
.v_time
), delta
);
359 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
360 LTTV_TIME
, &cpu_time
);
361 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
362 tfcs
->parent
.process
->state
->change
);
363 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
367 static gboolean
before_syscall_entry(void *hook_data
, void *call_data
)
369 mode_change((LttvTracefileStats
*)call_data
);
374 static gboolean
after_syscall_entry(void *hook_data
, void *call_data
)
376 update_event_tree((LttvTracefileStats
*)call_data
);
381 gboolean
before_syscall_exit(void *hook_data
, void *call_data
)
383 mode_end((LttvTracefileStats
*)call_data
);
388 static gboolean
after_syscall_exit(void *hook_data
, void *call_data
)
390 update_event_tree((LttvTracefileStats
*)call_data
);
395 gboolean
before_trap_entry(void *hook_data
, void *call_data
)
397 mode_change((LttvTracefileStats
*)call_data
);
402 static gboolean
after_trap_entry(void *hook_data
, void *call_data
)
404 update_event_tree((LttvTracefileStats
*)call_data
);
409 gboolean
before_trap_exit(void *hook_data
, void *call_data
)
411 mode_end((LttvTracefileStats
*)call_data
);
416 gboolean
after_trap_exit(void *hook_data
, void *call_data
)
418 update_event_tree((LttvTracefileStats
*)call_data
);
423 gboolean
before_irq_entry(void *hook_data
, void *call_data
)
425 mode_change((LttvTracefileStats
*)call_data
);
430 gboolean
after_irq_entry(void *hook_data
, void *call_data
)
432 update_event_tree((LttvTracefileStats
*)call_data
);
437 gboolean
before_irq_exit(void *hook_data
, void *call_data
)
439 mode_end((LttvTracefileStats
*)call_data
);
444 gboolean
after_irq_exit(void *hook_data
, void *call_data
)
446 update_event_tree((LttvTracefileStats
*)call_data
);
451 gboolean
before_schedchange(void *hook_data
, void *call_data
)
453 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
455 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
457 guint pid_in
, pid_out
, state_out
;
459 LttvProcessState
*process
;
461 pid_in
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f1
);
462 pid_out
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f2
);
463 state_out
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f3
);
465 /* compute the time for the process to schedule out */
469 /* get the information for the process scheduled in */
471 process
= lttv_state_find_process_or_create(&(tfcs
->parent
), pid_in
);
473 find_event_tree(tfcs
, process
->pid_time
, tfcs
->parent
.cpu_name
,
474 process
->state
->t
, process
->state
->n
, &(tfcs
->current_events_tree
),
475 &(tfcs
->current_event_types_tree
));
477 /* compute the time waiting for the process to schedule in */
484 gboolean
process_fork(void *hook_data
, void *call_data
)
486 /* nothing to do for now */
491 gboolean
process_exit(void *hook_data
, void *call_data
)
493 /* We should probably exit all modes here or we could do that at
499 gboolean
every_event(void *hook_data
, void *call_data
)
501 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
503 LttvAttributeValue v
;
505 /* The current branch corresponds to the tracefile/process/interrupt state.
506 Statistics are added within it, to count the number of events of this
507 type occuring in this context. A quark has been pre-allocated for each
508 event type and is used as name. */
510 lttv_attribute_find(tfcs
->current_event_types_tree
,
511 ((LttvTraceState
*)(tfcs
->parent
.parent
.t_context
))->
512 eventtype_names
[ltt_event_eventtype_id(tfcs
->parent
.parent
.e
)],
520 sum_stats(void *hook_data
, void *call_data
)
522 LttvTracesetStats
*tscs
= (LttvTracesetStats
*)call_data
;
526 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
528 LttvAttributeType type
;
530 LttvAttributeValue value
;
532 LttvAttributeName name
;
536 int i
, j
, k
, l
, m
, n
, nb_trace
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
,
539 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
540 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
541 *submode_tree
, *event_types_tree
, *mode_events_tree
,
542 *cpu_events_tree
, *process_modes_tree
, *trace_cpu_tree
,
543 *trace_modes_tree
, *traceset_modes_tree
;
545 traceset_modes_tree
= lttv_attribute_find_subdir(tscs
->stats
,
547 nb_trace
= lttv_traceset_number(traceset
);
549 for(i
= 0 ; i
< nb_trace
; i
++) {
550 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
551 main_tree
= tcs
->stats
;
552 processes_tree
= lttv_attribute_find_subdir(main_tree
,
553 LTTV_STATS_PROCESSES
);
554 trace_modes_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_MODES
);
555 nb_process
= lttv_attribute_get_number(processes_tree
);
557 for(j
= 0 ; j
< nb_process
; j
++) {
558 type
= lttv_attribute_get(processes_tree
, j
, &name
, &value
);
559 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
561 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
562 process_modes_tree
= lttv_attribute_find_subdir(process_tree
,
564 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
566 for(k
= 0 ; k
< nb_cpu
; k
++) {
567 type
= lttv_attribute_get(cpus_tree
, k
, &name
, &value
);
568 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
570 mode_types_tree
= lttv_attribute_find_subdir(cpu_tree
,
571 LTTV_STATS_MODE_TYPES
);
572 cpu_events_tree
= lttv_attribute_find_subdir(cpu_tree
,
574 trace_cpu_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_CPU
);
575 trace_cpu_tree
= lttv_attribute_find_subdir(trace_cpu_tree
, name
);
576 nb_mode_type
= lttv_attribute_get_number(mode_types_tree
);
578 for(l
= 0 ; l
< nb_mode_type
; l
++) {
579 type
= lttv_attribute_get(mode_types_tree
, l
, &name
, &value
);
580 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
582 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,
583 LTTV_STATS_SUBMODES
);
584 mode_events_tree
= lttv_attribute_find_subdir(mode_tree
,
586 nb_submode
= lttv_attribute_get_number(submodes_tree
);
588 for(m
= 0 ; m
< nb_submode
; m
++) {
589 type
= lttv_attribute_get(submodes_tree
, m
, &name
, &value
);
590 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
592 event_types_tree
= lttv_attribute_find_subdir(submode_tree
,
593 LTTV_STATS_EVENT_TYPES
);
594 nb_event_type
= lttv_attribute_get_number(event_types_tree
);
597 for(n
= 0 ; n
< nb_event_type
; n
++) {
598 type
= lttv_attribute_get(event_types_tree
, n
, &name
, &value
);
599 sum
+= *(value
.v_uint
);
601 lttv_attribute_find(submode_tree
, LTTV_STATS_EVENTS_COUNT
,
603 *(value
.v_uint
) = sum
;
604 lttv_attribute_recursive_add(mode_events_tree
, submode_tree
);
606 lttv_attribute_recursive_add(cpu_events_tree
, mode_events_tree
);
608 lttv_attribute_recursive_add(process_modes_tree
, cpu_tree
);
609 lttv_attribute_recursive_add(trace_cpu_tree
, cpu_tree
);
611 lttv_attribute_recursive_add(trace_modes_tree
, process_modes_tree
);
613 lttv_attribute_recursive_add(traceset_modes_tree
, trace_modes_tree
);
619 lttv_stats_add_event_hooks(LttvTracesetStats
*self
)
621 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
623 guint i
, j
, k
, nb_trace
, nb_tracefile
;
631 LttvTracefileStats
*tfs
;
635 GArray
*hooks
, *before_hooks
, *after_hooks
;
639 LttvAttributeValue val
;
641 nb_trace
= lttv_traceset_number(traceset
);
642 for(i
= 0 ; i
< nb_trace
; i
++) {
643 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
645 /* Find the eventtype id for the following events and register the
646 associated by id hooks. */
648 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
649 g_array_set_size(hooks
, 7);
651 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core","syscall_entry",
652 "syscall_id", NULL
, NULL
, before_syscall_entry
,
653 &g_array_index(hooks
, LttvTraceHook
, 0));
655 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "syscall_exit", NULL
,
656 NULL
, NULL
, before_syscall_exit
,
657 &g_array_index(hooks
, LttvTraceHook
, 1));
659 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_entry", "trap_id",
660 NULL
, NULL
, before_trap_entry
,
661 &g_array_index(hooks
, LttvTraceHook
, 2));
663 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_exit", NULL
, NULL
,
664 NULL
, before_trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
666 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_entry", "irq_id",
667 NULL
, NULL
, before_irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
669 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_exit", NULL
, NULL
,
670 NULL
, before_irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
672 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "schedchange", "in",
673 "out", "out_state", before_schedchange
,
674 &g_array_index(hooks
, LttvTraceHook
, 6));
676 before_hooks
= hooks
;
678 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
679 g_array_set_size(hooks
, 8);
681 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core","syscall_entry",
682 "syscall_id", NULL
, NULL
, after_syscall_entry
,
683 &g_array_index(hooks
, LttvTraceHook
, 0));
685 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "syscall_exit", NULL
,
686 NULL
, NULL
, after_syscall_exit
,
687 &g_array_index(hooks
, LttvTraceHook
, 1));
689 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_entry", "trap_id",
690 NULL
, NULL
, after_trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
692 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_exit", NULL
, NULL
,
693 NULL
, after_trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
695 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_entry", "irq_id",
696 NULL
, NULL
, after_irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
698 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_exit", NULL
, NULL
,
699 NULL
, after_irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
701 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "process_fork",
702 "child_pid", NULL
, NULL
, process_fork
,
703 &g_array_index(hooks
, LttvTraceHook
, 6));
705 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "process_exit", NULL
,
706 NULL
, NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 7));
710 /* Add these hooks to each before_event_by_id hooks list */
712 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.parent
.t
) +
713 ltt_trace_per_cpu_tracefile_number(ts
->parent
.parent
.t
);
715 for(j
= 0 ; j
< nb_tracefile
; j
++) {
716 tfs
= LTTV_TRACEFILE_STATS(ts
->parent
.parent
.tracefiles
[j
]);
717 lttv_hooks_add(tfs
->parent
.parent
.after_event
, every_event
, NULL
);
719 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
720 hook
= g_array_index(before_hooks
, LttvTraceHook
, k
);
721 lttv_hooks_add(lttv_hooks_by_id_find(
722 tfs
->parent
.parent
.before_event_by_id
,
723 hook
.id
), hook
.h
, &g_array_index(before_hooks
, LttvTraceHook
, k
));
725 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
726 hook
= g_array_index(after_hooks
, LttvTraceHook
, k
);
727 lttv_hooks_add(lttv_hooks_by_id_find(
728 tfs
->parent
.parent
.after_event_by_id
,
729 hook
.id
), hook
.h
, &g_array_index(after_hooks
, LttvTraceHook
, k
));
732 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
734 *(val
.v_pointer
) = before_hooks
;
735 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
737 *(val
.v_pointer
) = after_hooks
;
739 lttv_hooks_add(self
->parent
.parent
.after
, sum_stats
, NULL
);
743 lttv_stats_remove_event_hooks(LttvTracesetStats
*self
)
745 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
747 guint i
, j
, k
, nb_trace
, nb_tracefile
;
751 LttvTracefileStats
*tfs
;
755 GArray
*before_hooks
, *after_hooks
;
759 LttvAttributeValue val
;
761 nb_trace
= lttv_traceset_number(traceset
);
762 for(i
= 0 ; i
< nb_trace
; i
++) {
763 ts
= LTTV_TRACE_STATS(self
->parent
.parent
.traces
[i
]);
764 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
766 before_hooks
= *(val
.v_pointer
);
767 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
769 after_hooks
= *(val
.v_pointer
);
771 /* Add these hooks to each before_event_by_id hooks list */
773 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.parent
.t
) +
774 ltt_trace_per_cpu_tracefile_number(ts
->parent
.parent
.t
);
776 for(j
= 0 ; j
< nb_tracefile
; j
++) {
777 tfs
= LTTV_TRACEFILE_STATS(ts
->parent
.parent
.tracefiles
[j
]);
778 lttv_hooks_remove_data(tfs
->parent
.parent
.after_event
, every_event
,
781 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
782 hook
= g_array_index(before_hooks
, LttvTraceHook
, k
);
783 lttv_hooks_remove_data(
784 lttv_hooks_by_id_find(tfs
->parent
.parent
.before_event_by_id
,
785 hook
.id
), hook
.h
, &g_array_index(before_hooks
, LttvTraceHook
, k
));
787 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
788 hook
= g_array_index(after_hooks
, LttvTraceHook
, k
);
789 lttv_hooks_remove_data(
790 lttv_hooks_by_id_find(tfs
->parent
.parent
.after_event_by_id
,
791 hook
.id
), hook
.h
, &g_array_index(after_hooks
, LttvTraceHook
, k
));
794 g_debug("lttv_stats_remove_event_hooks()");
795 g_array_free(before_hooks
, TRUE
);
796 g_array_free(after_hooks
, TRUE
);
798 lttv_hooks_remove_data(self
->parent
.parent
.after
, sum_stats
, NULL
);
802 void lttv_stats_save_attribute(LttvAttribute
*attr
, char *indent
, FILE * fp
)
804 LttvAttributeType type
;
805 LttvAttributeValue value
;
806 LttvAttributeName name
;
807 char type_value
[BUF_SIZE
];
808 int i
, nb_attr
, flag
;
810 nb_attr
= lttv_attribute_get_number(attr
);
811 for(i
=0;i
<nb_attr
;i
++){
813 type
= lttv_attribute_get(attr
, i
, &name
, &value
);
816 sprintf(type_value
, "%d\0", *value
.v_int
);
819 sprintf(type_value
, "%u\0", *value
.v_uint
);
822 sprintf(type_value
, "%ld\0", *value
.v_long
);
825 sprintf(type_value
, "%lu\0", *value
.v_ulong
);
828 sprintf(type_value
, "%f\0", (double)*value
.v_float
);
831 sprintf(type_value
, "%f\0", *value
.v_double
);
834 sprintf(type_value
, "%10u.%09u\0", value
.v_time
->tv_sec
,
835 value
.v_time
->tv_nsec
);
838 sprintf(type_value
, "POINTER\0");
841 sprintf(type_value
, "%s\0", *value
.v_string
);
847 if(flag
== 0) continue;
848 fprintf(fp
,"%s<VALUE type=\"%d\" name=\"%s\">",indent
,type
,g_quark_to_string(name
));
849 fprintf(fp
,"%s",type_value
);
850 fprintf(fp
,"</VALUE> \n");
855 void lttv_stats_save_statistics(LttvTracesetStats
*self
)
857 LttvTracesetStats
*tscs
= self
;
859 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
860 LttvAttributeType type
;
861 LttvAttributeValue value
;
862 LttvAttributeName name
;
864 char filename
[BUF_SIZE
];
866 char indent
[10][24]= {" ",
879 int i
, j
, k
, l
, m
, n
, nb_trace
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
;
881 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
882 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
883 *submode_tree
, *event_types_tree
;
885 nb_trace
= lttv_traceset_number(traceset
);
887 for(i
= 0 ; i
< nb_trace
; i
++) {
888 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
891 strcat(filename
,ltt_trace_name(tcs
->parent
.parent
.t
));
892 strcat(filename
,"/statistics.xml");
893 fp
= fopen(filename
,"w");
895 g_warning("can not open the file %s for saving statistics\n", filename
);
899 main_tree
= tcs
->stats
;
900 processes_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_PROCESSES
);
901 nb_process
= lttv_attribute_get_number(processes_tree
);
903 fprintf(fp
, "<NODE name=\"%s\"> \n",g_quark_to_string(LTTV_STATS_PROCESSES
)); //root NODE
905 for(j
= 0 ; j
< nb_process
; j
++) {
906 type
= lttv_attribute_get(processes_tree
, j
, &name
, &value
);
907 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
909 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[0],g_quark_to_string(name
)); //process NODE
910 lttv_stats_save_attribute(process_tree
,indent
[1], fp
);
911 fprintf(fp
,"%s<NODE name=\"%s\"> \n", indent
[1],g_quark_to_string(LTTV_STATS_CPU
)); //cpus NODE
913 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
914 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
916 for(k
= 0 ; k
< nb_cpu
; k
++) {
917 type
= lttv_attribute_get(cpus_tree
, k
, &name
, &value
);
918 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
920 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[2],g_quark_to_string(name
)); //cpu NODE
921 lttv_stats_save_attribute(cpu_tree
,indent
[3], fp
);
922 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[3],g_quark_to_string(LTTV_STATS_MODE_TYPES
)); //mode_types NODE
924 mode_types_tree
= lttv_attribute_find_subdir(cpu_tree
,LTTV_STATS_MODE_TYPES
);
925 nb_mode_type
= lttv_attribute_get_number(mode_types_tree
);
927 for(l
= 0 ; l
< nb_mode_type
; l
++) {
928 type
= lttv_attribute_get(mode_types_tree
, l
, &name
, &value
);
929 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
931 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[4],g_quark_to_string(name
)); //mode NODE
932 lttv_stats_save_attribute(mode_tree
,indent
[5], fp
);
933 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[5],g_quark_to_string(LTTV_STATS_SUBMODES
)); //sub_modes NODE
935 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,LTTV_STATS_SUBMODES
);
936 nb_submode
= lttv_attribute_get_number(submodes_tree
);
938 for(m
= 0 ; m
< nb_submode
; m
++) {
939 type
= lttv_attribute_get(submodes_tree
, m
, &name
, &value
);
940 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
941 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[6],g_quark_to_string(name
)); //sub_mode NODE
942 lttv_stats_save_attribute(submode_tree
,indent
[7], fp
);
943 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[7],g_quark_to_string(LTTV_STATS_EVENT_TYPES
)); //event_types NODE
945 event_types_tree
= lttv_attribute_find_subdir(submode_tree
, LTTV_STATS_EVENT_TYPES
);
946 lttv_stats_save_attribute(event_types_tree
,indent
[8], fp
);
948 fprintf(fp
,"%s</NODE> \n",indent
[7]); //event_types NODE
949 fprintf(fp
,"%s</NODE> \n",indent
[6]); //sub_mode NODE
951 fprintf(fp
,"%s</NODE> \n",indent
[5]); //sub_modes NODE
952 fprintf(fp
,"%s</NODE> \n",indent
[4]); //mode NODE
954 fprintf(fp
,"%s</NODE> \n",indent
[3]); //mode_type NODE
955 fprintf(fp
,"%s</NODE> \n",indent
[2]); //cpu NODE
957 fprintf(fp
,"%s</NODE> \n",indent
[1]); //cpus NODE
958 fprintf(fp
,"%s</NODE> \n", indent
[0]); //process NODE
960 fprintf(fp
, "</NODE>\n"); //root NODE
966 /* Functions to parse statistic.xml file (using glib xml parser) */
968 typedef struct _ParserStruct
{
969 GPtrArray
* attribute
;
970 LttvAttributeType type
;
971 LttvAttributeName name
;
974 static void stats_parser_start_element (GMarkupParseContext
*context
,
975 const gchar
*element_name
,
976 const gchar
**attribute_names
,
977 const gchar
**attribute_values
,
981 ParserStruct
* parser
= (ParserStruct
*)user_data
;
983 LttvAttributeType type
;
984 LttvAttributeName name
;
985 LttvAttribute
* parent_att
, *new_att
;
987 len
= parser
->attribute
->len
;
988 parent_att
= (LttvAttribute
*)g_ptr_array_index (parser
->attribute
, len
-1);
990 if(strcmp("NODE", element_name
) == 0){
992 name
= g_quark_from_string(attribute_values
[0]);
993 new_att
= lttv_attribute_find_subdir(parent_att
,name
);
994 g_ptr_array_add(parser
->attribute
, (gpointer
)new_att
);
995 }else if(strcmp("VALUE", element_name
) == 0){
996 parser
->type
= (LttvAttributeType
) atoi(attribute_values
[0]);
997 parser
->name
= g_quark_from_string(attribute_values
[1]);
999 g_warning("This is not statistics.xml file\n");
1004 static void stats_parser_end_element (GMarkupParseContext
*context
,
1005 const gchar
*element_name
,
1009 ParserStruct
* parser
= (ParserStruct
*)user_data
;
1011 LttvAttribute
* parent_att
;
1013 len
= parser
->attribute
->len
;
1014 parent_att
= (LttvAttribute
*)g_ptr_array_index (parser
->attribute
, len
-1);
1016 if(strcmp("NODE", element_name
) == 0){
1017 g_ptr_array_remove_index(parser
->attribute
, len
-1);
1018 }else if(strcmp("VALUE", element_name
) == 0){
1020 g_warning("This is not statistics.xml file\n");
1026 static void stats_parser_characters (GMarkupParseContext
*context
,
1032 ParserStruct
* parser
= (ParserStruct
*)user_data
;
1033 LttvAttributeValue value
;
1035 LttvAttribute
* parent_att
;
1039 for(len
=0;len
<text_len
;len
++){
1046 if(strlen(pos
) == 0)return;
1048 len
= parser
->attribute
->len
;
1049 parent_att
= (LttvAttribute
*)g_ptr_array_index (parser
->attribute
, len
-1);
1050 if(!lttv_attribute_find(parent_att
,parser
->name
, parser
->type
, &value
)){
1051 g_warning("can not find value\n");
1055 switch(parser
->type
) {
1057 *value
.v_int
= atoi(text
);
1060 *value
.v_uint
= (unsigned)atoi(text
);
1063 *value
.v_long
= atol(text
);
1066 *value
.v_ulong
= (unsigned long)atol(text
);
1069 *value
.v_float
= atof(text
);
1072 *value
.v_float
= atof(text
);
1075 pos
= strrchr(text
,'.');
1079 value
.v_time
->tv_sec
= atol(text
);
1080 value
.v_time
->tv_nsec
= atol(pos
);
1082 g_warning("The time value format is wrong\n");
1089 *value
.v_string
= g_strdup(text
);
1097 gboolean
lttv_stats_load_statistics(LttvTracesetStats
*self
)
1101 LttvTracesetStats
*tscs
= self
;
1102 LttvTraceStats
*tcs
;
1103 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
1104 char filename
[BUF_SIZE
];
1106 GMarkupParseContext
* context
;
1107 GError
* error
= NULL
;
1108 GMarkupParser markup_parser
=
1110 stats_parser_start_element
,
1111 stats_parser_end_element
,
1112 stats_parser_characters
,
1113 NULL
, /* passthrough */
1118 LttvAttribute
*main_tree
;
1119 ParserStruct a_parser_struct
;
1120 a_parser_struct
.attribute
= g_ptr_array_new();
1122 nb_trace
= lttv_traceset_number(traceset
);
1124 for(i
= 0 ; i
< nb_trace
; i
++) {
1125 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
1128 strcat(filename
,ltt_trace_name(tcs
->parent
.parent
.t
));
1129 strcat(filename
,"/statistics.xml");
1130 fp
= fopen(filename
,"r");
1132 g_warning("can not open the file %s for reading statistics\n", filename
);
1136 main_tree
= tcs
->stats
;
1137 g_ptr_array_add(a_parser_struct
.attribute
,(gpointer
)main_tree
);
1139 context
= g_markup_parse_context_new(&markup_parser
, 0, (gpointer
)&a_parser_struct
, NULL
);
1141 while(fgets(buf
,BUF_SIZE
, fp
) != NULL
){
1142 if(!g_markup_parse_context_parse(context
, buf
, BUF_SIZE
, &error
)){
1143 g_warning("Can not parse xml file: \n%s\n", error
->message
);
1150 sum_stats(NULL
, (void *)self
);
1156 static void module_init()
1158 LTTV_STATS_PROCESS_UNKNOWN
= g_quark_from_string("unknown process");
1159 LTTV_STATS_PROCESSES
= g_quark_from_string("processes");
1160 LTTV_STATS_CPU
= g_quark_from_string("cpu");
1161 LTTV_STATS_MODE_TYPES
= g_quark_from_string("mode_types");
1162 LTTV_STATS_MODES
= g_quark_from_string("modes");
1163 LTTV_STATS_SUBMODES
= g_quark_from_string("submodes");
1164 LTTV_STATS_EVENT_TYPES
= g_quark_from_string("event_types");
1165 LTTV_STATS_CPU_TIME
= g_quark_from_string("cpu time");
1166 LTTV_STATS_ELAPSED_TIME
= g_quark_from_string("elapsed time");
1167 LTTV_STATS_EVENTS
= g_quark_from_string("events");
1168 LTTV_STATS_EVENTS_COUNT
= g_quark_from_string("events count");
1169 LTTV_STATS_BEFORE_HOOKS
= g_quark_from_string("saved stats before hooks");
1170 LTTV_STATS_AFTER_HOOKS
= g_quark_from_string("saved stats after hooks");
1173 static void module_destroy()
1178 LTTV_MODULE("stats", "Compute processes statistics", \
1179 "Accumulate statistics for event types, processes and CPUs", \
1180 module_init
, module_destroy
, "state");