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_control
, nb_per_cpu
, 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_control
= ltt_trace_control_tracefile_number(tc
->t
);
79 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
80 nb_tracefile
= nb_control
+ nb_per_cpu
;
81 for(j
= 0 ; j
< nb_tracefile
; j
++) {
83 tfcs
= LTTV_TRACEFILE_STATS(tc
->control_tracefiles
[j
]);
86 tfcs
= LTTV_TRACEFILE_STATS(tc
->per_cpu_tracefiles
[j
- nb_control
]);
89 tfcs
->stats
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
90 find_event_tree(tfcs
, LTTV_STATS_PROCESS_UNKNOWN
,
91 tfcs
->parent
.cpu_name
, LTTV_STATE_MODE_UNKNOWN
,
92 LTTV_STATE_SUBMODE_UNKNOWN
, &tfcs
->current_events_tree
,
93 &tfcs
->current_event_types_tree
);
100 fini(LttvTracesetStats
*self
)
102 guint i
, j
, nb_trace
, nb_tracefile
;
106 LttvTraceContext
*tc
;
110 LttvTracefileContext
*tfc
;
112 LttvTracefileStats
*tfcs
;
114 LttTime timestamp
= {0,0};
116 lttv_attribute_recursive_free(self
->stats
);
117 ts
= self
->parent
.parent
.ts
;
118 nb_trace
= lttv_traceset_number(ts
);
120 for(i
= 0 ; i
< nb_trace
; i
++) {
121 tcs
= (LttvTraceStats
*)tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
122 lttv_attribute_recursive_free(tcs
->stats
);
124 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
);
125 for(j
= 0 ; j
< nb_tracefile
; j
++) {
126 tfcs
= (LttvTracefileStats
*)tfc
= tc
->control_tracefiles
[j
];
127 lttv_attribute_recursive_free(tfcs
->stats
);
128 tfcs
->current_events_tree
= NULL
;
129 tfcs
->current_event_types_tree
= NULL
;
132 nb_tracefile
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
133 for(j
= 0 ; j
< nb_tracefile
; j
++) {
134 tfcs
= (LttvTracefileStats
*)tfc
= tc
->per_cpu_tracefiles
[j
];
135 lttv_attribute_recursive_free(tfcs
->stats
);
136 tfcs
->current_events_tree
= NULL
;
137 tfcs
->current_event_types_tree
= NULL
;
140 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
141 fini((LttvTracesetContext
*)self
);
145 static LttvTracesetContext
*
146 new_traceset_context(LttvTracesetContext
*self
)
148 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE
, NULL
));
152 static LttvTraceContext
*
153 new_trace_context(LttvTracesetContext
*self
)
155 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE
, NULL
));
159 static LttvTracefileContext
*
160 new_tracefile_context(LttvTracesetContext
*self
)
162 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE
, NULL
));
167 traceset_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
173 traceset_stats_finalize (LttvTracesetStats
*self
)
175 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
176 finalize(G_OBJECT(self
));
181 traceset_stats_class_init (LttvTracesetContextClass
*klass
)
183 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
185 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_stats_finalize
;
186 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
187 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
188 klass
->new_traceset_context
= new_traceset_context
;
189 klass
->new_trace_context
= new_trace_context
;
190 klass
->new_tracefile_context
= new_tracefile_context
;
195 lttv_traceset_stats_get_type(void)
197 static GType type
= 0;
199 static const GTypeInfo info
= {
200 sizeof (LttvTracesetStatsClass
),
201 NULL
, /* base_init */
202 NULL
, /* base_finalize */
203 (GClassInitFunc
) traceset_stats_class_init
, /* class_init */
204 NULL
, /* class_finalize */
205 NULL
, /* class_data */
206 sizeof (LttvTracesetContext
),
208 (GInstanceInitFunc
) traceset_stats_instance_init
/* instance_init */
211 type
= g_type_register_static (LTTV_TRACESET_STATE_TYPE
, "LttvTracesetStatsType",
219 trace_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
225 trace_stats_finalize (LttvTraceStats
*self
)
227 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE
))->
228 finalize(G_OBJECT(self
));
233 trace_stats_class_init (LttvTraceContextClass
*klass
)
235 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
237 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_stats_finalize
;
242 lttv_trace_stats_get_type(void)
244 static GType type
= 0;
246 static const GTypeInfo info
= {
247 sizeof (LttvTraceStatsClass
),
248 NULL
, /* base_init */
249 NULL
, /* base_finalize */
250 (GClassInitFunc
) trace_stats_class_init
, /* class_init */
251 NULL
, /* class_finalize */
252 NULL
, /* class_data */
253 sizeof (LttvTraceStats
),
255 (GInstanceInitFunc
) trace_stats_instance_init
/* instance_init */
258 type
= g_type_register_static (LTTV_TRACE_STATE_TYPE
,
259 "LttvTraceStatsType", &info
, 0);
266 tracefile_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
272 tracefile_stats_finalize (LttvTracefileStats
*self
)
274 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE
))->
275 finalize(G_OBJECT(self
));
280 tracefile_stats_class_init (LttvTracefileStatsClass
*klass
)
282 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
284 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_stats_finalize
;
289 lttv_tracefile_stats_get_type(void)
291 static GType type
= 0;
293 static const GTypeInfo info
= {
294 sizeof (LttvTracefileStatsClass
),
295 NULL
, /* base_init */
296 NULL
, /* base_finalize */
297 (GClassInitFunc
) tracefile_stats_class_init
, /* class_init */
298 NULL
, /* class_finalize */
299 NULL
, /* class_data */
300 sizeof (LttvTracefileStats
),
302 (GInstanceInitFunc
) tracefile_stats_instance_init
/* instance_init */
305 type
= g_type_register_static (LTTV_TRACEFILE_STATE_TYPE
,
306 "LttvTracefileStatsType", &info
, 0);
313 find_event_tree(LttvTracefileStats
*tfcs
, GQuark process
, GQuark cpu
,
314 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
315 LttvAttribute
**event_types_tree
)
319 LttvTraceStats
*tcs
= LTTV_TRACE_STATS(tfcs
->parent
.parent
.t_context
);
320 a
= lttv_attribute_find_subdir(tcs
->stats
, LTTV_STATS_PROCESSES
);
321 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->pid_time
);
322 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_CPU
);
323 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.cpu_name
);
324 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_MODE_TYPES
);
325 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->state
->t
);
326 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_SUBMODES
);
327 a
= lttv_attribute_find_subdir(a
, tfcs
->parent
.process
->state
->n
);
329 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_EVENT_TYPES
);
330 *event_types_tree
= a
;
334 static void update_event_tree(LttvTracefileStats
*tfcs
)
336 LttvExecutionState
*es
= tfcs
->parent
.process
->state
;
338 find_event_tree(tfcs
, tfcs
->parent
.process
->pid_time
, tfcs
->parent
.cpu_name
,
339 es
->t
, es
->n
, &(tfcs
->current_events_tree
),
340 &(tfcs
->current_event_types_tree
));
344 static void mode_change(LttvTracefileStats
*tfcs
)
346 LttvAttributeValue cpu_time
;
350 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
351 LTTV_TIME
, &cpu_time
);
352 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
353 tfcs
->parent
.process
->state
->change
);
354 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
358 static void mode_end(LttvTracefileStats
*tfcs
)
360 LttvAttributeValue elapsed_time
, cpu_time
;
364 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_ELAPSED_TIME
,
365 LTTV_TIME
, &elapsed_time
);
366 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
367 tfcs
->parent
.process
->state
->entry
);
368 *(elapsed_time
.v_time
) = ltt_time_add(*(elapsed_time
.v_time
), delta
);
370 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
371 LTTV_TIME
, &cpu_time
);
372 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
373 tfcs
->parent
.process
->state
->change
);
374 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
378 static gboolean
before_syscall_entry(void *hook_data
, void *call_data
)
380 mode_change((LttvTracefileStats
*)call_data
);
385 static gboolean
after_syscall_entry(void *hook_data
, void *call_data
)
387 update_event_tree((LttvTracefileStats
*)call_data
);
392 gboolean
before_syscall_exit(void *hook_data
, void *call_data
)
394 mode_end((LttvTracefileStats
*)call_data
);
399 static gboolean
after_syscall_exit(void *hook_data
, void *call_data
)
401 update_event_tree((LttvTracefileStats
*)call_data
);
406 gboolean
before_trap_entry(void *hook_data
, void *call_data
)
408 mode_change((LttvTracefileStats
*)call_data
);
413 static gboolean
after_trap_entry(void *hook_data
, void *call_data
)
415 update_event_tree((LttvTracefileStats
*)call_data
);
420 gboolean
before_trap_exit(void *hook_data
, void *call_data
)
422 mode_end((LttvTracefileStats
*)call_data
);
427 gboolean
after_trap_exit(void *hook_data
, void *call_data
)
429 update_event_tree((LttvTracefileStats
*)call_data
);
434 gboolean
before_irq_entry(void *hook_data
, void *call_data
)
436 mode_change((LttvTracefileStats
*)call_data
);
441 gboolean
after_irq_entry(void *hook_data
, void *call_data
)
443 update_event_tree((LttvTracefileStats
*)call_data
);
448 gboolean
before_irq_exit(void *hook_data
, void *call_data
)
450 mode_end((LttvTracefileStats
*)call_data
);
455 gboolean
after_irq_exit(void *hook_data
, void *call_data
)
457 update_event_tree((LttvTracefileStats
*)call_data
);
462 gboolean
before_schedchange(void *hook_data
, void *call_data
)
464 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
466 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
468 guint pid_in
, pid_out
, state_out
;
470 LttvProcessState
*process
;
472 pid_in
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f1
);
473 pid_out
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f2
);
474 state_out
= ltt_event_get_unsigned(tfcs
->parent
.parent
.e
, h
->f3
);
476 /* compute the time for the process to schedule out */
480 /* get the information for the process scheduled in */
482 process
= lttv_state_find_process_or_create(&(tfcs
->parent
), pid_in
);
484 find_event_tree(tfcs
, process
->pid_time
, tfcs
->parent
.cpu_name
,
485 process
->state
->t
, process
->state
->n
, &(tfcs
->current_events_tree
),
486 &(tfcs
->current_event_types_tree
));
488 /* compute the time waiting for the process to schedule in */
495 gboolean
process_fork(void *hook_data
, void *call_data
)
497 /* nothing to do for now */
502 gboolean
process_exit(void *hook_data
, void *call_data
)
504 /* We should probably exit all modes here or we could do that at
510 gboolean
every_event(void *hook_data
, void *call_data
)
512 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
514 LttvAttributeValue v
;
516 /* The current branch corresponds to the tracefile/process/interrupt state.
517 Statistics are added within it, to count the number of events of this
518 type occuring in this context. A quark has been pre-allocated for each
519 event type and is used as name. */
521 lttv_attribute_find(tfcs
->current_event_types_tree
,
522 ((LttvTraceState
*)(tfcs
->parent
.parent
.t_context
))->
523 eventtype_names
[ltt_event_eventtype_id(tfcs
->parent
.parent
.e
)],
531 sum_stats(void *hook_data
, void *call_data
)
533 LttvTracesetStats
*tscs
= (LttvTracesetStats
*)call_data
;
537 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
539 LttvAttributeType type
;
541 LttvAttributeValue value
;
543 LttvAttributeName name
;
547 int i
, j
, k
, l
, m
, n
, nb_trace
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
,
550 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
551 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
552 *submode_tree
, *event_types_tree
, *mode_events_tree
,
553 *cpu_events_tree
, *process_modes_tree
, *trace_cpu_tree
,
554 *trace_modes_tree
, *traceset_modes_tree
;
556 traceset_modes_tree
= lttv_attribute_find_subdir(tscs
->stats
,
558 nb_trace
= lttv_traceset_number(traceset
);
560 for(i
= 0 ; i
< nb_trace
; i
++) {
561 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
562 main_tree
= tcs
->stats
;
563 processes_tree
= lttv_attribute_find_subdir(main_tree
,
564 LTTV_STATS_PROCESSES
);
565 trace_modes_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_MODES
);
566 nb_process
= lttv_attribute_get_number(processes_tree
);
568 for(j
= 0 ; j
< nb_process
; j
++) {
569 type
= lttv_attribute_get(processes_tree
, j
, &name
, &value
);
570 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
572 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
573 process_modes_tree
= lttv_attribute_find_subdir(process_tree
,
575 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
577 for(k
= 0 ; k
< nb_cpu
; k
++) {
578 type
= lttv_attribute_get(cpus_tree
, k
, &name
, &value
);
579 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
581 mode_types_tree
= lttv_attribute_find_subdir(cpu_tree
,
582 LTTV_STATS_MODE_TYPES
);
583 cpu_events_tree
= lttv_attribute_find_subdir(cpu_tree
,
585 trace_cpu_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_CPU
);
586 trace_cpu_tree
= lttv_attribute_find_subdir(trace_cpu_tree
, name
);
587 nb_mode_type
= lttv_attribute_get_number(mode_types_tree
);
589 for(l
= 0 ; l
< nb_mode_type
; l
++) {
590 type
= lttv_attribute_get(mode_types_tree
, l
, &name
, &value
);
591 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
593 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,
594 LTTV_STATS_SUBMODES
);
595 mode_events_tree
= lttv_attribute_find_subdir(mode_tree
,
597 nb_submode
= lttv_attribute_get_number(submodes_tree
);
599 for(m
= 0 ; m
< nb_submode
; m
++) {
600 type
= lttv_attribute_get(submodes_tree
, m
, &name
, &value
);
601 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
603 event_types_tree
= lttv_attribute_find_subdir(submode_tree
,
604 LTTV_STATS_EVENT_TYPES
);
605 nb_event_type
= lttv_attribute_get_number(event_types_tree
);
608 for(n
= 0 ; n
< nb_event_type
; n
++) {
609 type
= lttv_attribute_get(event_types_tree
, n
, &name
, &value
);
610 sum
+= *(value
.v_uint
);
612 lttv_attribute_find(submode_tree
, LTTV_STATS_EVENTS_COUNT
,
614 *(value
.v_uint
) = sum
;
615 lttv_attribute_recursive_add(mode_events_tree
, submode_tree
);
617 lttv_attribute_recursive_add(cpu_events_tree
, mode_events_tree
);
619 lttv_attribute_recursive_add(process_modes_tree
, cpu_tree
);
620 lttv_attribute_recursive_add(trace_cpu_tree
, cpu_tree
);
622 lttv_attribute_recursive_add(trace_modes_tree
, process_modes_tree
);
624 lttv_attribute_recursive_add(traceset_modes_tree
, trace_modes_tree
);
630 lttv_stats_add_event_hooks(LttvTracesetStats
*self
)
632 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
634 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
642 LttvTracefileStats
*tfs
;
646 GArray
*hooks
, *before_hooks
, *after_hooks
;
650 LttvAttributeValue val
;
652 nb_trace
= lttv_traceset_number(traceset
);
653 for(i
= 0 ; i
< nb_trace
; i
++) {
654 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
656 /* Find the eventtype id for the following events and register the
657 associated by id hooks. */
659 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
660 g_array_set_size(hooks
, 7);
662 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core","syscall_entry",
663 "syscall_id", NULL
, NULL
, before_syscall_entry
,
664 &g_array_index(hooks
, LttvTraceHook
, 0));
666 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "syscall_exit", NULL
,
667 NULL
, NULL
, before_syscall_exit
,
668 &g_array_index(hooks
, LttvTraceHook
, 1));
670 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_entry", "trap_id",
671 NULL
, NULL
, before_trap_entry
,
672 &g_array_index(hooks
, LttvTraceHook
, 2));
674 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_exit", NULL
, NULL
,
675 NULL
, before_trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
677 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_entry", "irq_id",
678 NULL
, NULL
, before_irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
680 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_exit", NULL
, NULL
,
681 NULL
, before_irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
683 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "schedchange", "in",
684 "out", "out_state", before_schedchange
,
685 &g_array_index(hooks
, LttvTraceHook
, 6));
687 before_hooks
= hooks
;
689 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
690 g_array_set_size(hooks
, 8);
692 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core","syscall_entry",
693 "syscall_id", NULL
, NULL
, after_syscall_entry
,
694 &g_array_index(hooks
, LttvTraceHook
, 0));
696 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "syscall_exit", NULL
,
697 NULL
, NULL
, after_syscall_exit
,
698 &g_array_index(hooks
, LttvTraceHook
, 1));
700 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_entry", "trap_id",
701 NULL
, NULL
, after_trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
703 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "trap_exit", NULL
, NULL
,
704 NULL
, after_trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
706 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_entry", "irq_id",
707 NULL
, NULL
, after_irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
709 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "irq_exit", NULL
, NULL
,
710 NULL
, after_irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
712 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "process_fork",
713 "child_pid", NULL
, NULL
, process_fork
,
714 &g_array_index(hooks
, LttvTraceHook
, 6));
716 lttv_trace_find_hook(ts
->parent
.parent
.t
, "core", "process_exit", NULL
,
717 NULL
, NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 7));
721 /* Add these hooks to each before_event_by_id hooks list */
723 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.parent
.t
);
724 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.parent
.t
);
725 nb_tracefile
= nb_control
+ nb_per_cpu
;
726 for(j
= 0 ; j
< nb_tracefile
; j
++) {
728 tfs
= LTTV_TRACEFILE_STATS(ts
->parent
.parent
.control_tracefiles
[j
]);
731 tfs
= LTTV_TRACEFILE_STATS(ts
->parent
.parent
.per_cpu_tracefiles
[
735 lttv_hooks_add(tfs
->parent
.parent
.after_event
, every_event
, NULL
);
737 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
738 hook
= g_array_index(before_hooks
, LttvTraceHook
, k
);
739 lttv_hooks_add(lttv_hooks_by_id_find(
740 tfs
->parent
.parent
.before_event_by_id
,
741 hook
.id
), hook
.h
, &g_array_index(before_hooks
, LttvTraceHook
, k
));
743 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
744 hook
= g_array_index(after_hooks
, LttvTraceHook
, k
);
745 lttv_hooks_add(lttv_hooks_by_id_find(
746 tfs
->parent
.parent
.after_event_by_id
,
747 hook
.id
), hook
.h
, &g_array_index(after_hooks
, LttvTraceHook
, k
));
750 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
752 *(val
.v_pointer
) = before_hooks
;
753 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
755 *(val
.v_pointer
) = after_hooks
;
757 lttv_hooks_add(self
->parent
.parent
.after
, sum_stats
, NULL
);
761 lttv_stats_remove_event_hooks(LttvTracesetStats
*self
)
763 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
765 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
769 LttvTracefileStats
*tfs
;
773 GArray
*before_hooks
, *after_hooks
;
777 LttvAttributeValue val
;
779 nb_trace
= lttv_traceset_number(traceset
);
780 for(i
= 0 ; i
< nb_trace
; i
++) {
781 ts
= LTTV_TRACE_STATS(self
->parent
.parent
.traces
[i
]);
782 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
784 before_hooks
= *(val
.v_pointer
);
785 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
787 after_hooks
= *(val
.v_pointer
);
789 /* Add these hooks to each before_event_by_id hooks list */
791 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.parent
.t
);
792 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.parent
.t
);
793 nb_tracefile
= nb_control
+ nb_per_cpu
;
794 for(j
= 0 ; j
< nb_tracefile
; j
++) {
796 tfs
= LTTV_TRACEFILE_STATS(ts
->parent
.parent
.control_tracefiles
[j
]);
799 tfs
=LTTV_TRACEFILE_STATS(ts
->parent
.parent
.per_cpu_tracefiles
[
803 lttv_hooks_remove_data(tfs
->parent
.parent
.after_event
, every_event
,
806 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
807 hook
= g_array_index(before_hooks
, LttvTraceHook
, k
);
808 lttv_hooks_remove_data(
809 lttv_hooks_by_id_find(tfs
->parent
.parent
.before_event_by_id
,
810 hook
.id
), hook
.h
, &g_array_index(before_hooks
, LttvTraceHook
, k
));
812 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
813 hook
= g_array_index(after_hooks
, LttvTraceHook
, k
);
814 lttv_hooks_remove_data(
815 lttv_hooks_by_id_find(tfs
->parent
.parent
.after_event_by_id
,
816 hook
.id
), hook
.h
, &g_array_index(after_hooks
, LttvTraceHook
, k
));
819 g_debug("lttv_stats_remove_event_hooks()");
820 g_array_free(before_hooks
, TRUE
);
821 g_array_free(after_hooks
, TRUE
);
823 lttv_hooks_remove_data(self
->parent
.parent
.after
, sum_stats
, NULL
);
827 void lttv_stats_init(int argc
, char **argv
)
829 LTTV_STATS_PROCESS_UNKNOWN
= g_quark_from_string("unknown process");
830 LTTV_STATS_PROCESSES
= g_quark_from_string("processes");
831 LTTV_STATS_CPU
= g_quark_from_string("cpu");
832 LTTV_STATS_MODE_TYPES
= g_quark_from_string("mode_types");
833 LTTV_STATS_MODES
= g_quark_from_string("modes");
834 LTTV_STATS_SUBMODES
= g_quark_from_string("submodes");
835 LTTV_STATS_EVENT_TYPES
= g_quark_from_string("event_types");
836 LTTV_STATS_CPU_TIME
= g_quark_from_string("cpu time");
837 LTTV_STATS_ELAPSED_TIME
= g_quark_from_string("elapsed time");
838 LTTV_STATS_EVENTS
= g_quark_from_string("events");
839 LTTV_STATS_EVENTS_COUNT
= g_quark_from_string("events count");
840 LTTV_STATS_BEFORE_HOOKS
= g_quark_from_string("saved stats before hooks");
841 LTTV_STATS_AFTER_HOOKS
= g_quark_from_string("saved stats after hooks");
844 void lttv_stats_destroy()
848 void lttv_stats_save_attribute(LttvAttribute
*attr
, char *indent
, FILE * fp
)
850 LttvAttributeType type
;
851 LttvAttributeValue value
;
852 LttvAttributeName name
;
853 char type_value
[BUF_SIZE
];
854 int i
, nb_attr
, flag
;
856 nb_attr
= lttv_attribute_get_number(attr
);
857 for(i
=0;i
<nb_attr
;i
++){
859 type
= lttv_attribute_get(attr
, i
, &name
, &value
);
862 sprintf(type_value
, "%d\0", *value
.v_int
);
865 sprintf(type_value
, "%u\0", *value
.v_uint
);
868 sprintf(type_value
, "%ld\0", *value
.v_long
);
871 sprintf(type_value
, "%lu\0", *value
.v_ulong
);
874 sprintf(type_value
, "%f\0", (double)*value
.v_float
);
877 sprintf(type_value
, "%f\0", *value
.v_double
);
880 sprintf(type_value
, "%10u.%09u\0", value
.v_time
->tv_sec
,
881 value
.v_time
->tv_nsec
);
884 sprintf(type_value
, "POINTER\0");
887 sprintf(type_value
, "%s\0", *value
.v_string
);
893 if(flag
== 0) continue;
894 fprintf(fp
,"%s<VALUE type=\"%d\" name=\"%s\">",indent
,type
,g_quark_to_string(name
));
895 fprintf(fp
,"%s",type_value
);
896 fprintf(fp
,"</VALUE> \n");
901 void lttv_stats_save_statistics(LttvTracesetStats
*self
)
903 LttvTracesetStats
*tscs
= self
;
905 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
906 LttvAttributeType type
;
907 LttvAttributeValue value
;
908 LttvAttributeName name
;
910 char filename
[BUF_SIZE
];
912 char indent
[10][24]= {" ",
925 int i
, j
, k
, l
, m
, n
, nb_trace
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
;
927 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
928 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
929 *submode_tree
, *event_types_tree
;
931 nb_trace
= lttv_traceset_number(traceset
);
933 for(i
= 0 ; i
< nb_trace
; i
++) {
934 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
937 strcat(filename
,ltt_trace_name(tcs
->parent
.parent
.t
));
938 strcat(filename
,"/statistics.xml");
939 fp
= fopen(filename
,"w");
941 g_warning("can not open the file %s for saving statistics\n", filename
);
945 main_tree
= tcs
->stats
;
946 processes_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_PROCESSES
);
947 nb_process
= lttv_attribute_get_number(processes_tree
);
949 fprintf(fp
, "<NODE name=\"%s\"> \n",g_quark_to_string(LTTV_STATS_PROCESSES
)); //root NODE
951 for(j
= 0 ; j
< nb_process
; j
++) {
952 type
= lttv_attribute_get(processes_tree
, j
, &name
, &value
);
953 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
955 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[0],g_quark_to_string(name
)); //process NODE
956 lttv_stats_save_attribute(process_tree
,indent
[1], fp
);
957 fprintf(fp
,"%s<NODE name=\"%s\"> \n", indent
[1],g_quark_to_string(LTTV_STATS_CPU
)); //cpus NODE
959 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
960 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
962 for(k
= 0 ; k
< nb_cpu
; k
++) {
963 type
= lttv_attribute_get(cpus_tree
, k
, &name
, &value
);
964 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
966 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[2],g_quark_to_string(name
)); //cpu NODE
967 lttv_stats_save_attribute(cpu_tree
,indent
[3], fp
);
968 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[3],g_quark_to_string(LTTV_STATS_MODE_TYPES
)); //mode_types NODE
970 mode_types_tree
= lttv_attribute_find_subdir(cpu_tree
,LTTV_STATS_MODE_TYPES
);
971 nb_mode_type
= lttv_attribute_get_number(mode_types_tree
);
973 for(l
= 0 ; l
< nb_mode_type
; l
++) {
974 type
= lttv_attribute_get(mode_types_tree
, l
, &name
, &value
);
975 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
977 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[4],g_quark_to_string(name
)); //mode NODE
978 lttv_stats_save_attribute(mode_tree
,indent
[5], fp
);
979 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[5],g_quark_to_string(LTTV_STATS_SUBMODES
)); //sub_modes NODE
981 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,LTTV_STATS_SUBMODES
);
982 nb_submode
= lttv_attribute_get_number(submodes_tree
);
984 for(m
= 0 ; m
< nb_submode
; m
++) {
985 type
= lttv_attribute_get(submodes_tree
, m
, &name
, &value
);
986 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
987 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[6],g_quark_to_string(name
)); //sub_mode NODE
988 lttv_stats_save_attribute(submode_tree
,indent
[7], fp
);
989 fprintf(fp
,"%s<NODE name=\"%s\"> \n",indent
[7],g_quark_to_string(LTTV_STATS_EVENT_TYPES
)); //event_types NODE
991 event_types_tree
= lttv_attribute_find_subdir(submode_tree
, LTTV_STATS_EVENT_TYPES
);
992 lttv_stats_save_attribute(event_types_tree
,indent
[8], fp
);
994 fprintf(fp
,"%s</NODE> \n",indent
[7]); //event_types NODE
995 fprintf(fp
,"%s</NODE> \n",indent
[6]); //sub_mode NODE
997 fprintf(fp
,"%s</NODE> \n",indent
[5]); //sub_modes NODE
998 fprintf(fp
,"%s</NODE> \n",indent
[4]); //mode NODE
1000 fprintf(fp
,"%s</NODE> \n",indent
[3]); //mode_type NODE
1001 fprintf(fp
,"%s</NODE> \n",indent
[2]); //cpu NODE
1003 fprintf(fp
,"%s</NODE> \n",indent
[1]); //cpus NODE
1004 fprintf(fp
,"%s</NODE> \n", indent
[0]); //process NODE
1006 fprintf(fp
, "</NODE>\n"); //root NODE
1012 /* Functions to parse statistic.xml file (using glib xml parser) */
1014 typedef struct _ParserStruct
{
1015 GPtrArray
* attribute
;
1016 LttvAttributeType type
;
1017 LttvAttributeName name
;
1020 static void stats_parser_start_element (GMarkupParseContext
*context
,
1021 const gchar
*element_name
,
1022 const gchar
**attribute_names
,
1023 const gchar
**attribute_values
,
1027 ParserStruct
* parser
= (ParserStruct
*)user_data
;
1029 LttvAttributeType type
;
1030 LttvAttributeName name
;
1031 LttvAttribute
* parent_att
, *new_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 type
= LTTV_GOBJECT
;
1038 name
= g_quark_from_string(attribute_values
[0]);
1039 new_att
= lttv_attribute_find_subdir(parent_att
,name
);
1040 g_ptr_array_add(parser
->attribute
, (gpointer
)new_att
);
1041 }else if(strcmp("VALUE", element_name
) == 0){
1042 parser
->type
= (LttvAttributeType
) atoi(attribute_values
[0]);
1043 parser
->name
= g_quark_from_string(attribute_values
[1]);
1045 g_warning("This is not statistics.xml file\n");
1050 static void stats_parser_end_element (GMarkupParseContext
*context
,
1051 const gchar
*element_name
,
1055 ParserStruct
* parser
= (ParserStruct
*)user_data
;
1057 LttvAttribute
* parent_att
;
1059 len
= parser
->attribute
->len
;
1060 parent_att
= (LttvAttribute
*)g_ptr_array_index (parser
->attribute
, len
-1);
1062 if(strcmp("NODE", element_name
) == 0){
1063 g_ptr_array_remove_index(parser
->attribute
, len
-1);
1064 }else if(strcmp("VALUE", element_name
) == 0){
1066 g_warning("This is not statistics.xml file\n");
1072 static void stats_parser_characters (GMarkupParseContext
*context
,
1078 ParserStruct
* parser
= (ParserStruct
*)user_data
;
1079 LttvAttributeValue value
;
1081 LttvAttribute
* parent_att
;
1085 for(len
=0;len
<text_len
;len
++){
1092 if(strlen(pos
) == 0)return;
1094 len
= parser
->attribute
->len
;
1095 parent_att
= (LttvAttribute
*)g_ptr_array_index (parser
->attribute
, len
-1);
1096 if(!lttv_attribute_find(parent_att
,parser
->name
, parser
->type
, &value
)){
1097 g_warning("can not find value\n");
1101 switch(parser
->type
) {
1103 *value
.v_int
= atoi(text
);
1106 *value
.v_uint
= (unsigned)atoi(text
);
1109 *value
.v_long
= atol(text
);
1112 *value
.v_ulong
= (unsigned long)atol(text
);
1115 *value
.v_float
= atof(text
);
1118 *value
.v_float
= atof(text
);
1121 pos
= strrchr(text
,'.');
1125 value
.v_time
->tv_sec
= atol(text
);
1126 value
.v_time
->tv_nsec
= atol(pos
);
1128 g_warning("The time value format is wrong\n");
1135 *value
.v_string
= g_strdup(text
);
1143 gboolean
lttv_stats_load_statistics(LttvTracesetStats
*self
)
1147 LttvTracesetStats
*tscs
= self
;
1148 LttvTraceStats
*tcs
;
1149 LttvTraceset
*traceset
= tscs
->parent
.parent
.ts
;
1150 char filename
[BUF_SIZE
];
1152 GMarkupParseContext
* context
;
1154 GMarkupParser markup_parser
=
1156 stats_parser_start_element
,
1157 stats_parser_end_element
,
1158 stats_parser_characters
,
1159 NULL
, /* passthrough */
1164 LttvAttribute
*main_tree
;
1165 ParserStruct a_parser_struct
;
1166 a_parser_struct
.attribute
= g_ptr_array_new();
1168 nb_trace
= lttv_traceset_number(traceset
);
1170 for(i
= 0 ; i
< nb_trace
; i
++) {
1171 tcs
= (LttvTraceStats
*)(tscs
->parent
.parent
.traces
[i
]);
1174 strcat(filename
,ltt_trace_name(tcs
->parent
.parent
.t
));
1175 strcat(filename
,"/statistics.xml");
1176 fp
= fopen(filename
,"r");
1178 g_warning("can not open the file %s for reading statistics\n", filename
);
1182 main_tree
= tcs
->stats
;
1183 g_ptr_array_add(a_parser_struct
.attribute
,(gpointer
)main_tree
);
1185 context
= g_markup_parse_context_new(&markup_parser
, 0, (gpointer
)&a_parser_struct
, NULL
);
1187 while(fgets(buf
,BUF_SIZE
, fp
) != NULL
){
1188 if(!g_markup_parse_context_parse(context
, buf
, BUF_SIZE
, &error
)){
1189 g_warning("Can not parse xml file: \n%s\n", error
->message
);
1196 sum_stats(NULL
, (void *)self
);