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,
24 #include <lttv/module.h>
25 #include <lttv/stats.h>
26 #include <lttv/lttv.h>
27 #include <lttv/attribute.h>
28 #include <ltt/facility.h>
29 #include <ltt/trace.h>
30 #include <ltt/event.h>
34 #define MAX_64_HEX_STRING_LEN 19
37 LTTV_STATS_PROCESS_UNKNOWN
,
40 LTTV_STATS_MODE_TYPES
,
44 LTTV_STATS_EVENT_TYPES
,
46 LTTV_STATS_ELAPSED_TIME
,
48 LTTV_STATS_EVENTS_COUNT
,
51 LTTV_STATS_TRACEFILES
,
53 LTTV_STATS_BEFORE_HOOKS
,
54 LTTV_STATS_AFTER_HOOKS
;
57 find_event_tree(LttvTracefileStats
*tfcs
, GQuark pid_time
, GQuark cpu
,
59 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
60 LttvAttribute
**event_types_tree
);
63 static void lttv_stats_init(LttvTracesetStats
*self
)
65 guint i
, j
, nb_trace
, nb_tracefile
;
71 LttvTracefileContext
*tfc
;
73 LttvTracefileContext
**tfs
;
74 LttvTracefileStats
*tfcs
;
76 LttTime timestamp
= {0,0};
84 LttvTraceset
*ts
= self
->parent
.parent
.ts
;
86 self
->stats
= lttv_attribute_find_subdir(
87 lttv_traceset_attribute(self
->parent
.parent
.ts
),
89 lttv_attribute_find(lttv_traceset_attribute(self
->parent
.parent
.ts
),
94 if(*(v
.v_uint
) == 1) {
95 g_assert(lttv_attribute_get_number(self
->stats
) == 0);
98 nb_trace
= lttv_traceset_number(ts
);
100 for(i
= 0 ; i
< nb_trace
; i
++) {
101 tc
= self
->parent
.parent
.traces
[i
];
102 tcs
= LTTV_TRACE_STATS(tc
);
104 tcs
->stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,LTTV_STATS
);
105 tracefiles_stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,
106 LTTV_STATS_TRACEFILES
);
107 lttv_attribute_find(tcs
->parent
.parent
.t_a
, LTTV_STATS_USE_COUNT
,
111 if(*(v
.v_uint
) == 1) {
112 g_assert(lttv_attribute_get_number(tcs
->stats
) == 0);
115 nb_tracefile
= tc
->tracefiles
->len
;
117 for(j
= 0 ; j
< nb_tracefile
; j
++) {
118 tfs
= &g_array_index(tc
->tracefiles
,
119 LttvTracefileContext
*, j
);
120 tfcs
= LTTV_TRACEFILE_STATS(*tfs
);
121 tfcs
->stats
= lttv_attribute_find_subdir(tracefiles_stats
,
122 ltt_tracefile_long_name(tfcs
->parent
.parent
.tf
));
123 find_event_tree(tfcs
, LTTV_STATS_PROCESS_UNKNOWN
,
124 ltt_tracefile_long_name(tfcs
->parent
.parent
.tf
),
126 LTTV_STATE_MODE_UNKNOWN
,
127 LTTV_STATE_SUBMODE_UNKNOWN
, &tfcs
->current_events_tree
,
128 &tfcs
->current_event_types_tree
);
134 static void lttv_stats_fini(LttvTracesetStats
*self
)
136 guint i
, j
, nb_trace
, nb_tracefile
;
140 LttvTraceContext
*tc
;
144 LttvTracefileContext
*tfc
;
146 LttvTracefileStats
*tfcs
;
148 LttTime timestamp
= {0,0};
150 LttvAttributeValue v
;
152 LttvAttribute
*tracefiles_stats
;
154 lttv_attribute_find(self
->parent
.parent
.ts_a
, LTTV_STATS_USE_COUNT
,
158 if(*(v
.v_uint
) == 0) {
159 lttv_attribute_remove_by_name(self
->parent
.parent
.ts_a
, LTTV_STATS
);
163 ts
= self
->parent
.parent
.ts
;
164 nb_trace
= lttv_traceset_number(ts
);
166 for(i
= 0 ; i
< nb_trace
; i
++) {
167 tcs
= (LttvTraceStats
*)(tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]));
169 lttv_attribute_find(tcs
->parent
.parent
.t_a
, LTTV_STATS_USE_COUNT
,
173 if(*(v
.v_uint
) == 0) {
174 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
,LTTV_STATS
);
175 tracefiles_stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,
176 LTTV_STATS_TRACEFILES
);
177 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
,
178 LTTV_STATS_TRACEFILES
);
182 nb_tracefile
= tc
->tracefiles
->len
;
184 for(j
= 0 ; j
< nb_tracefile
; j
++) {
185 tfc
= g_array_index(tc
->tracefiles
,
186 LttvTracefileContext
*, j
);
187 tfcs
= (LttvTracefileStats
*)tfc
;
189 tfcs
->current_events_tree
= NULL
;
190 tfcs
->current_event_types_tree
= NULL
;
196 void lttv_stats_reset(LttvTracesetStats
*self
)
198 lttv_stats_fini(self
);
199 lttv_stats_init(self
);
205 init(LttvTracesetStats
*self
, LttvTraceset
*ts
)
207 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
208 init((LttvTracesetContext
*)self
, ts
);
210 lttv_stats_init(self
);
215 fini(LttvTracesetStats
*self
)
217 lttv_stats_fini(self
);
219 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
220 fini((LttvTracesetContext
*)self
);
224 static LttvTracesetContext
*
225 new_traceset_context(LttvTracesetContext
*self
)
227 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE
, NULL
));
231 static LttvTraceContext
*
232 new_trace_context(LttvTracesetContext
*self
)
234 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE
, NULL
));
238 static LttvTracefileContext
*
239 new_tracefile_context(LttvTracesetContext
*self
)
241 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE
, NULL
));
246 traceset_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
252 traceset_stats_finalize (LttvTracesetStats
*self
)
254 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
255 finalize(G_OBJECT(self
));
260 traceset_stats_class_init (LttvTracesetContextClass
*klass
)
262 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
264 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_stats_finalize
;
265 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
266 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
267 klass
->new_traceset_context
= new_traceset_context
;
268 klass
->new_trace_context
= new_trace_context
;
269 klass
->new_tracefile_context
= new_tracefile_context
;
274 lttv_traceset_stats_get_type(void)
276 static GType type
= 0;
278 static const GTypeInfo info
= {
279 sizeof (LttvTracesetStatsClass
),
280 NULL
, /* base_init */
281 NULL
, /* base_finalize */
282 (GClassInitFunc
) traceset_stats_class_init
, /* class_init */
283 NULL
, /* class_finalize */
284 NULL
, /* class_data */
285 sizeof (LttvTracesetStats
),
287 (GInstanceInitFunc
) traceset_stats_instance_init
, /* instance_init */
288 NULL
/* Value handling */
291 type
= g_type_register_static (LTTV_TRACESET_STATE_TYPE
,
292 "LttvTracesetStatsType",
300 trace_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
306 trace_stats_finalize (LttvTraceStats
*self
)
308 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE
))->
309 finalize(G_OBJECT(self
));
314 trace_stats_class_init (LttvTraceContextClass
*klass
)
316 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
318 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_stats_finalize
;
323 lttv_trace_stats_get_type(void)
325 static GType type
= 0;
327 static const GTypeInfo info
= {
328 sizeof (LttvTraceStatsClass
),
329 NULL
, /* base_init */
330 NULL
, /* base_finalize */
331 (GClassInitFunc
) trace_stats_class_init
, /* class_init */
332 NULL
, /* class_finalize */
333 NULL
, /* class_data */
334 sizeof (LttvTraceStats
),
336 (GInstanceInitFunc
) trace_stats_instance_init
, /* instance_init */
337 NULL
/* Value handling */
340 type
= g_type_register_static (LTTV_TRACE_STATE_TYPE
,
341 "LttvTraceStatsType", &info
, 0);
348 tracefile_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
354 tracefile_stats_finalize (LttvTracefileStats
*self
)
356 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE
))->
357 finalize(G_OBJECT(self
));
362 tracefile_stats_class_init (LttvTracefileStatsClass
*klass
)
364 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
366 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_stats_finalize
;
371 lttv_tracefile_stats_get_type(void)
373 static GType type
= 0;
375 static const GTypeInfo info
= {
376 sizeof (LttvTracefileStatsClass
),
377 NULL
, /* base_init */
378 NULL
, /* base_finalize */
379 (GClassInitFunc
) tracefile_stats_class_init
, /* class_init */
380 NULL
, /* class_finalize */
381 NULL
, /* class_data */
382 sizeof (LttvTracefileStats
),
384 (GInstanceInitFunc
) tracefile_stats_instance_init
, /* instance_init */
385 NULL
/* Value handling */
388 type
= g_type_register_static (LTTV_TRACEFILE_STATE_TYPE
,
389 "LttvTracefileStatsType", &info
, 0);
396 find_event_tree(LttvTracefileStats
*tfcs
,
402 LttvAttribute
**events_tree
,
403 LttvAttribute
**event_types_tree
)
406 gchar fstring
[MAX_64_HEX_STRING_LEN
];
408 g_assert(snprintf(fstring
, MAX_64_HEX_STRING_LEN
-1,
409 "0x%llX", function
) > 0);
410 fstring
[MAX_64_HEX_STRING_LEN
-1] = '\0';
412 LttvTraceStats
*tcs
= (LttvTraceStats
*)tfcs
->parent
.parent
.t_context
;
413 a
= lttv_attribute_find_subdir(tcs
->stats
, LTTV_STATS_PROCESSES
);
414 a
= lttv_attribute_find_subdir(a
, pid_time
);
415 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_CPU
);
416 a
= lttv_attribute_find_subdir(a
, cpu
);
417 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_FUNCTIONS
);
418 a
= lttv_attribute_find_subdir(a
, g_quark_from_string(fstring
));
419 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_MODE_TYPES
);
420 a
= lttv_attribute_find_subdir(a
, mode
);
421 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_SUBMODES
);
422 a
= lttv_attribute_find_subdir(a
, sub_mode
);
424 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_EVENT_TYPES
);
425 *event_types_tree
= a
;
429 static void update_event_tree(LttvTracefileStats
*tfcs
)
431 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
432 guint cpu
= tfcs
->parent
.cpu
;
433 LttvProcessState
*process
= ts
->running_process
[cpu
];
434 LttvExecutionState
*es
= process
->state
;
436 find_event_tree(tfcs
, process
->pid_time
,
437 ltt_tracefile_long_name(tfcs
->parent
.parent
.tf
),
438 process
->current_function
,
439 es
->t
, es
->n
, &(tfcs
->current_events_tree
),
440 &(tfcs
->current_event_types_tree
));
444 static void mode_change(LttvTracefileStats
*tfcs
)
446 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
447 guint cpu
= tfcs
->parent
.cpu
;
448 LttvProcessState
*process
= ts
->running_process
[cpu
];
449 LttvAttributeValue cpu_time
;
453 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
454 LTTV_TIME
, &cpu_time
);
455 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
456 process
->state
->change
);
457 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
461 static void mode_end(LttvTracefileStats
*tfcs
)
463 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
464 guint cpu
= tfcs
->parent
.cpu
;
465 LttvProcessState
*process
= ts
->running_process
[cpu
];
466 LttvAttributeValue elapsed_time
, cpu_time
;
470 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_ELAPSED_TIME
,
471 LTTV_TIME
, &elapsed_time
);
472 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
473 process
->state
->entry
);
474 *(elapsed_time
.v_time
) = ltt_time_add(*(elapsed_time
.v_time
), delta
);
476 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
477 LTTV_TIME
, &cpu_time
);
478 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
479 process
->state
->change
);
480 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
484 static gboolean
before_syscall_entry(void *hook_data
, void *call_data
)
486 mode_change((LttvTracefileStats
*)call_data
);
491 static gboolean
after_syscall_entry(void *hook_data
, void *call_data
)
493 update_event_tree((LttvTracefileStats
*)call_data
);
498 gboolean
before_syscall_exit(void *hook_data
, void *call_data
)
500 mode_end((LttvTracefileStats
*)call_data
);
505 static gboolean
after_syscall_exit(void *hook_data
, void *call_data
)
507 update_event_tree((LttvTracefileStats
*)call_data
);
512 gboolean
before_trap_entry(void *hook_data
, void *call_data
)
514 mode_change((LttvTracefileStats
*)call_data
);
519 static gboolean
after_trap_entry(void *hook_data
, void *call_data
)
521 update_event_tree((LttvTracefileStats
*)call_data
);
526 gboolean
before_trap_exit(void *hook_data
, void *call_data
)
528 mode_end((LttvTracefileStats
*)call_data
);
533 gboolean
after_trap_exit(void *hook_data
, void *call_data
)
535 update_event_tree((LttvTracefileStats
*)call_data
);
540 gboolean
before_irq_entry(void *hook_data
, void *call_data
)
542 mode_change((LttvTracefileStats
*)call_data
);
546 gboolean
after_irq_entry(void *hook_data
, void *call_data
)
548 update_event_tree((LttvTracefileStats
*)call_data
);
553 gboolean
before_irq_exit(void *hook_data
, void *call_data
)
555 mode_end((LttvTracefileStats
*)call_data
);
560 gboolean
after_irq_exit(void *hook_data
, void *call_data
)
562 update_event_tree((LttvTracefileStats
*)call_data
);
567 gboolean
before_soft_irq_entry(void *hook_data
, void *call_data
)
569 mode_change((LttvTracefileStats
*)call_data
);
573 gboolean
after_soft_irq_entry(void *hook_data
, void *call_data
)
575 update_event_tree((LttvTracefileStats
*)call_data
);
580 gboolean
before_soft_irq_exit(void *hook_data
, void *call_data
)
582 mode_end((LttvTracefileStats
*)call_data
);
587 gboolean
after_soft_irq_exit(void *hook_data
, void *call_data
)
589 update_event_tree((LttvTracefileStats
*)call_data
);
593 gboolean
before_function_entry(void *hook_data
, void *call_data
)
595 mode_end((LttvTracefileStats
*)call_data
);
599 gboolean
after_function_entry(void *hook_data
, void *call_data
)
601 update_event_tree((LttvTracefileStats
*)call_data
);
605 gboolean
before_function_exit(void *hook_data
, void *call_data
)
607 mode_end((LttvTracefileStats
*)call_data
);
611 gboolean
after_function_exit(void *hook_data
, void *call_data
)
613 update_event_tree((LttvTracefileStats
*)call_data
);
618 gboolean
before_schedchange(void *hook_data
, void *call_data
)
620 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
622 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
624 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
626 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
628 guint pid_in
, pid_out
;
632 LttvProcessState
*process
;
634 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
635 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
636 state_out
= ltt_event_get_int(e
, thf
->f3
);
638 /* compute the time for the process to schedule out */
642 /* get the information for the process scheduled in */
644 process
= lttv_state_find_process_or_create(ts
,
645 ANY_CPU
, pid_in
, &tfcs
->parent
.parent
.timestamp
);
647 find_event_tree(tfcs
, process
->pid_time
,
648 ltt_tracefile_long_name(tfcs
->parent
.parent
.tf
),
649 process
->current_function
,
650 process
->state
->t
, process
->state
->n
, &(tfcs
->current_events_tree
),
651 &(tfcs
->current_event_types_tree
));
653 /* compute the time waiting for the process to schedule in */
660 gboolean
process_fork(void *hook_data
, void *call_data
)
662 /* nothing to do for now */
667 gboolean
process_exit(void *hook_data
, void *call_data
)
669 /* We should probably exit all modes here or we could do that at
674 gboolean
process_free(void *hook_data
, void *call_data
)
679 gboolean
every_event(void *hook_data
, void *call_data
)
681 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
683 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
685 LttvAttributeValue v
;
687 /* The current branch corresponds to the tracefile/process/interrupt state.
688 Statistics are added within it, to count the number of events of this
689 type occuring in this context. A quark has been pre-allocated for each
690 event type and is used as name. */
692 lttv_attribute_find(tfcs
->current_event_types_tree
,
693 ltt_eventtype_name(ltt_event_eventtype(e
)),
701 lttv_stats_sum_trace(LttvTraceStats
*self
)
703 LttvAttribute
*sum_container
= self
->stats
;
705 LttvAttributeType type
;
707 LttvAttributeValue value
;
709 LttvAttributeName name
;
713 int i
, j
, k
, l
, m
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
,
714 nb_event_type
, nf
, nb_functions
;
716 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
717 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
718 *submode_tree
, *event_types_tree
, *mode_events_tree
,
721 *function_mode_types_tree
,
724 main_tree
= sum_container
;
726 lttv_attribute_find(sum_container
,
729 if(*(value
.v_uint
) != 0) return;
732 processes_tree
= lttv_attribute_find_subdir(main_tree
,
733 LTTV_STATS_PROCESSES
);
734 nb_process
= lttv_attribute_get_number(processes_tree
);
736 for(i
= 0 ; i
< nb_process
; i
++) {
737 type
= lttv_attribute_get(processes_tree
, i
, &name
, &value
);
738 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
740 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
741 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
743 for(j
= 0 ; j
< nb_cpu
; j
++) {
744 type
= lttv_attribute_get(cpus_tree
, j
, &name
, &value
);
745 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
747 trace_cpu_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_CPU
);
748 trace_cpu_tree
= lttv_attribute_find_subdir(trace_cpu_tree
, name
);
749 cpu_functions_tree
= lttv_attribute_find_subdir(cpu_tree
,
750 LTTV_STATS_FUNCTIONS
);
751 nb_functions
= lttv_attribute_get_number(cpu_functions_tree
);
753 for(nf
=0; nf
< nb_functions
; nf
++) {
754 type
= lttv_attribute_get(cpu_functions_tree
, nf
, &name
, &value
);
755 function_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
756 function_mode_types_tree
= lttv_attribute_find_subdir(function_tree
,
757 LTTV_STATS_MODE_TYPES
);
758 nb_mode_type
= lttv_attribute_get_number(function_mode_types_tree
);
759 for(k
= 0 ; k
< nb_mode_type
; k
++) {
760 type
= lttv_attribute_get(function_mode_types_tree
, k
, &name
, &value
);
761 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
763 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,
764 LTTV_STATS_SUBMODES
);
765 mode_events_tree
= lttv_attribute_find_subdir(mode_tree
,
767 mode_types_tree
= lttv_attribute_find_subdir(mode_tree
,
768 LTTV_STATS_MODE_TYPES
);
770 nb_submode
= lttv_attribute_get_number(submodes_tree
);
772 for(l
= 0 ; l
< nb_submode
; l
++) {
773 type
= lttv_attribute_get(submodes_tree
, l
, &name
, &value
);
774 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
776 event_types_tree
= lttv_attribute_find_subdir(submode_tree
,
777 LTTV_STATS_EVENT_TYPES
);
778 nb_event_type
= lttv_attribute_get_number(event_types_tree
);
781 for(m
= 0 ; m
< nb_event_type
; m
++) {
782 type
= lttv_attribute_get(event_types_tree
, m
, &name
, &value
);
783 sum
+= *(value
.v_uint
);
785 lttv_attribute_find(submode_tree
, LTTV_STATS_EVENTS_COUNT
,
787 *(value
.v_uint
) = sum
;
789 type
= lttv_attribute_get(submodes_tree
, l
, &name
, &value
);
790 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
791 lttv_attribute_recursive_add(mode_events_tree
, event_types_tree
);
792 lttv_attribute_recursive_add(mode_types_tree
, submode_tree
);
795 lttv_attribute_recursive_add(main_tree
, mode_types_tree
);
796 lttv_attribute_recursive_add(trace_cpu_tree
, mode_types_tree
);
797 lttv_attribute_recursive_add(process_tree
, mode_types_tree
);
798 lttv_attribute_recursive_add(function_tree
, mode_types_tree
);
800 lttv_attribute_recursive_add(process_tree
, cpu_tree
);
806 gboolean
lttv_stats_sum_traceset_hook(void *hook_data
, void *call_data
)
808 lttv_stats_sum_traceset((LttvTracesetStats
*)call_data
);
813 lttv_stats_sum_traceset(LttvTracesetStats
*self
)
815 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
816 LttvAttribute
*sum_container
= self
->stats
;
822 LttvAttribute
*main_tree
;
824 LttvAttributeValue value
;
826 lttv_attribute_find(sum_container
, LTTV_STATS_SUMMED
,
828 if(*(value
.v_uint
) != 0) return;
831 nb_trace
= lttv_traceset_number(traceset
);
833 for(i
= 0 ; i
< nb_trace
; i
++) {
834 tcs
= (LttvTraceStats
*)(self
->parent
.parent
.traces
[i
]);
835 lttv_stats_sum_trace(tcs
);
836 main_tree
= tcs
->stats
;
837 lttv_attribute_recursive_add(sum_container
, main_tree
);
842 // Hook wrapper. call_data is a traceset context.
843 gboolean
lttv_stats_hook_add_event_hooks(void *hook_data
, void *call_data
)
845 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
847 lttv_stats_add_event_hooks(tss
);
852 void lttv_stats_add_event_hooks(LttvTracesetStats
*self
)
854 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
856 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
860 LttvTracefileStats
*tfs
;
862 GArray
*hooks
, *before_hooks
, *after_hooks
;
866 LttvTraceHookByFacility
*thf
;
868 LttvAttributeValue val
;
873 nb_trace
= lttv_traceset_number(traceset
);
874 for(i
= 0 ; i
< nb_trace
; i
++) {
875 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
877 /* Find the eventtype id for the following events and register the
878 associated by id hooks. */
880 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 11);
881 g_array_set_size(hooks
, 11);
884 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
885 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
886 LTT_FIELD_SYSCALL_ID
, 0, 0,
887 before_syscall_entry
, NULL
,
888 &g_array_index(hooks
, LttvTraceHook
, hn
++));
891 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
892 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
894 before_syscall_exit
, NULL
,
895 &g_array_index(hooks
, LttvTraceHook
, hn
++));
898 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
899 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
900 LTT_FIELD_TRAP_ID
, 0, 0,
901 before_trap_entry
, NULL
,
902 &g_array_index(hooks
, LttvTraceHook
, hn
++));
905 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
906 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
908 before_trap_exit
, NULL
,
909 &g_array_index(hooks
, LttvTraceHook
, hn
++));
912 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
913 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
914 LTT_FIELD_IRQ_ID
, 0, 0,
915 before_irq_entry
, NULL
,
916 &g_array_index(hooks
, LttvTraceHook
, hn
++));
919 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
920 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
922 before_irq_exit
, NULL
,
923 &g_array_index(hooks
, LttvTraceHook
, hn
++));
926 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
927 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
928 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
929 before_soft_irq_entry
, NULL
,
930 &g_array_index(hooks
, LttvTraceHook
, hn
++));
933 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
934 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
936 before_soft_irq_exit
, NULL
,
937 &g_array_index(hooks
, LttvTraceHook
, hn
++));
940 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
941 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
942 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
943 before_schedchange
, NULL
,
944 &g_array_index(hooks
, LttvTraceHook
, hn
++));
947 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
948 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
949 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
950 before_function_entry
, NULL
,
951 &g_array_index(hooks
, LttvTraceHook
, hn
++));
954 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
955 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
956 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
957 before_function_exit
, NULL
,
958 &g_array_index(hooks
, LttvTraceHook
, hn
++));
961 g_array_set_size(hooks
, hn
);
963 before_hooks
= hooks
;
965 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 13);
966 g_array_set_size(hooks
, 13);
969 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
970 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
971 LTT_FIELD_SYSCALL_ID
, 0, 0,
972 after_syscall_entry
, NULL
,
973 &g_array_index(hooks
, LttvTraceHook
, hn
++));
976 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
977 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
979 after_syscall_exit
, NULL
,
980 &g_array_index(hooks
, LttvTraceHook
, hn
++));
983 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
984 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
985 LTT_FIELD_TRAP_ID
, 0, 0,
986 after_trap_entry
, NULL
,
987 &g_array_index(hooks
, LttvTraceHook
, hn
++));
990 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
991 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
993 after_trap_exit
, NULL
,
994 &g_array_index(hooks
, LttvTraceHook
, hn
++));
997 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
998 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
999 LTT_FIELD_IRQ_ID
, 0, 0,
1000 after_irq_entry
, NULL
,
1001 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1004 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1005 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1007 after_irq_exit
, NULL
,
1008 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1011 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1012 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1013 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1014 after_irq_entry
, NULL
,
1015 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1018 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1019 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1021 after_soft_irq_exit
, NULL
,
1022 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1025 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1026 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1027 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1029 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1032 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1033 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1034 LTT_FIELD_PID
, 0, 0,
1036 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1039 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1040 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1041 LTT_FIELD_PID
, 0, 0,
1043 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1046 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1047 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
1048 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1049 after_function_entry
, NULL
,
1050 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1053 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1054 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
1055 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1056 after_function_exit
, NULL
,
1057 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1060 g_array_set_size(hooks
, hn
);
1062 after_hooks
= hooks
;
1064 /* Add these hooks to each event_by_id hooks list */
1066 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
1068 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1069 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
1070 LttvTracefileContext
*, j
));
1071 lttv_hooks_add(tfs
->parent
.parent
.event
, every_event
, NULL
,
1074 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1075 hook
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1076 for(l
= 0; l
<hook
->fac_list
->len
;l
++) {
1077 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1079 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1082 LTTV_PRIO_STATS_BEFORE_STATE
);
1085 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1086 hook
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1087 for(l
= 0; l
<hook
->fac_list
->len
;l
++) {
1088 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1090 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1093 LTTV_PRIO_STATS_AFTER_STATE
);
1097 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
1098 LTTV_POINTER
, &val
);
1099 *(val
.v_pointer
) = before_hooks
;
1100 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
1101 LTTV_POINTER
, &val
);
1102 *(val
.v_pointer
) = after_hooks
;
1106 // Hook wrapper. call_data is a traceset context.
1107 gboolean
lttv_stats_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1109 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
1111 lttv_stats_remove_event_hooks(tss
);
1116 void lttv_stats_remove_event_hooks(LttvTracesetStats
*self
)
1118 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
1120 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1124 LttvTracefileStats
*tfs
;
1128 GArray
*before_hooks
, *after_hooks
;
1130 LttvTraceHook
*hook
;
1132 LttvTraceHookByFacility
*thf
;
1134 LttvAttributeValue val
;
1136 nb_trace
= lttv_traceset_number(traceset
);
1137 for(i
= 0 ; i
< nb_trace
; i
++) {
1138 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
1139 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
1140 LTTV_POINTER
, &val
);
1141 before_hooks
= *(val
.v_pointer
);
1142 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
1143 LTTV_POINTER
, &val
);
1144 after_hooks
= *(val
.v_pointer
);
1146 /* Remove these hooks from each event_by_id hooks list */
1148 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
1150 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1151 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
1152 LttvTracefileContext
*, j
));
1153 lttv_hooks_remove_data(tfs
->parent
.parent
.event
, every_event
,
1156 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1157 hook
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1158 for(l
= 0 ; l
< hook
->fac_list
->len
; l
++) {
1159 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1160 lttv_hooks_remove_data(
1161 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1166 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1167 hook
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1168 for(l
= 0 ; l
< hook
->fac_list
->len
; l
++) {
1169 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1170 lttv_hooks_remove_data(
1171 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1177 g_debug("lttv_stats_remove_event_hooks()");
1178 g_array_free(before_hooks
, TRUE
);
1179 g_array_free(after_hooks
, TRUE
);
1184 static void module_init()
1186 LTTV_STATS_PROCESS_UNKNOWN
= g_quark_from_string("unknown process");
1187 LTTV_STATS_PROCESSES
= g_quark_from_string("processes");
1188 LTTV_STATS_CPU
= g_quark_from_string("cpu");
1189 LTTV_STATS_MODE_TYPES
= g_quark_from_string("mode_types");
1190 LTTV_STATS_MODES
= g_quark_from_string("modes");
1191 LTTV_STATS_SUBMODES
= g_quark_from_string("submodes");
1192 LTTV_STATS_FUNCTIONS
= g_quark_from_string("functions");
1193 LTTV_STATS_EVENT_TYPES
= g_quark_from_string("event_types");
1194 LTTV_STATS_CPU_TIME
= g_quark_from_string("cpu time");
1195 LTTV_STATS_ELAPSED_TIME
= g_quark_from_string("elapsed time");
1196 LTTV_STATS_EVENTS
= g_quark_from_string("events");
1197 LTTV_STATS_EVENTS_COUNT
= g_quark_from_string("events count");
1198 LTTV_STATS_BEFORE_HOOKS
= g_quark_from_string("saved stats before hooks");
1199 LTTV_STATS_AFTER_HOOKS
= g_quark_from_string("saved stats after hooks");
1200 LTTV_STATS_USE_COUNT
= g_quark_from_string("stats_use_count");
1201 LTTV_STATS
= g_quark_from_string("statistics");
1202 LTTV_STATS_TRACEFILES
= g_quark_from_string("tracefiles statistics");
1203 LTTV_STATS_SUMMED
= g_quark_from_string("statistics summed");
1206 static void module_destroy()
1211 LTTV_MODULE("stats", "Compute processes statistics", \
1212 "Accumulate statistics for event types, processes and CPUs", \
1213 module_init
, module_destroy
, "state");
1215 /* Change the places where stats are called (create/read/write stats)
1217 Check for options in batchtest.c to reduce writing and see what tests are
1218 best candidates for performance analysis. Once OK, commit, move to main
1219 and run tests. Update the gui for statistics. */