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
, guint 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 guint cpu
= tfcs
->parent
.cpu
;
124 find_event_tree(tfcs
, LTTV_STATS_PROCESS_UNKNOWN
,
127 LTTV_STATE_MODE_UNKNOWN
,
128 LTTV_STATE_SUBMODE_UNKNOWN
, &tfcs
->current_events_tree
,
129 &tfcs
->current_event_types_tree
);
135 static void lttv_stats_fini(LttvTracesetStats
*self
)
137 guint i
, j
, nb_trace
, nb_tracefile
;
141 LttvTraceContext
*tc
;
145 LttvTracefileContext
*tfc
;
147 LttvTracefileStats
*tfcs
;
149 LttTime timestamp
= {0,0};
151 LttvAttributeValue v
;
153 LttvAttribute
*tracefiles_stats
;
155 lttv_attribute_find(self
->parent
.parent
.ts_a
, LTTV_STATS_USE_COUNT
,
159 if(*(v
.v_uint
) == 0) {
160 lttv_attribute_remove_by_name(self
->parent
.parent
.ts_a
, LTTV_STATS
);
164 ts
= self
->parent
.parent
.ts
;
165 nb_trace
= lttv_traceset_number(ts
);
167 for(i
= 0 ; i
< nb_trace
; i
++) {
168 tcs
= (LttvTraceStats
*)(tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]));
170 lttv_attribute_find(tcs
->parent
.parent
.t_a
, LTTV_STATS_USE_COUNT
,
174 if(*(v
.v_uint
) == 0) {
175 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
,LTTV_STATS
);
176 tracefiles_stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,
177 LTTV_STATS_TRACEFILES
);
178 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
,
179 LTTV_STATS_TRACEFILES
);
183 nb_tracefile
= tc
->tracefiles
->len
;
185 for(j
= 0 ; j
< nb_tracefile
; j
++) {
186 tfc
= g_array_index(tc
->tracefiles
,
187 LttvTracefileContext
*, j
);
188 tfcs
= (LttvTracefileStats
*)tfc
;
190 tfcs
->current_events_tree
= NULL
;
191 tfcs
->current_event_types_tree
= NULL
;
197 void lttv_stats_reset(LttvTracesetStats
*self
)
199 lttv_stats_fini(self
);
200 lttv_stats_init(self
);
206 init(LttvTracesetStats
*self
, LttvTraceset
*ts
)
208 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
209 init((LttvTracesetContext
*)self
, ts
);
211 lttv_stats_init(self
);
216 fini(LttvTracesetStats
*self
)
218 lttv_stats_fini(self
);
220 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
221 fini((LttvTracesetContext
*)self
);
225 static LttvTracesetContext
*
226 new_traceset_context(LttvTracesetContext
*self
)
228 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE
, NULL
));
232 static LttvTraceContext
*
233 new_trace_context(LttvTracesetContext
*self
)
235 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE
, NULL
));
239 static LttvTracefileContext
*
240 new_tracefile_context(LttvTracesetContext
*self
)
242 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE
, NULL
));
247 traceset_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
253 traceset_stats_finalize (LttvTracesetStats
*self
)
255 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
256 finalize(G_OBJECT(self
));
261 traceset_stats_class_init (LttvTracesetContextClass
*klass
)
263 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
265 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_stats_finalize
;
266 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
267 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
268 klass
->new_traceset_context
= new_traceset_context
;
269 klass
->new_trace_context
= new_trace_context
;
270 klass
->new_tracefile_context
= new_tracefile_context
;
275 lttv_traceset_stats_get_type(void)
277 static GType type
= 0;
279 static const GTypeInfo info
= {
280 sizeof (LttvTracesetStatsClass
),
281 NULL
, /* base_init */
282 NULL
, /* base_finalize */
283 (GClassInitFunc
) traceset_stats_class_init
, /* class_init */
284 NULL
, /* class_finalize */
285 NULL
, /* class_data */
286 sizeof (LttvTracesetStats
),
288 (GInstanceInitFunc
) traceset_stats_instance_init
, /* instance_init */
289 NULL
/* Value handling */
292 type
= g_type_register_static (LTTV_TRACESET_STATE_TYPE
,
293 "LttvTracesetStatsType",
301 trace_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
307 trace_stats_finalize (LttvTraceStats
*self
)
309 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE
))->
310 finalize(G_OBJECT(self
));
315 trace_stats_class_init (LttvTraceContextClass
*klass
)
317 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
319 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_stats_finalize
;
324 lttv_trace_stats_get_type(void)
326 static GType type
= 0;
328 static const GTypeInfo info
= {
329 sizeof (LttvTraceStatsClass
),
330 NULL
, /* base_init */
331 NULL
, /* base_finalize */
332 (GClassInitFunc
) trace_stats_class_init
, /* class_init */
333 NULL
, /* class_finalize */
334 NULL
, /* class_data */
335 sizeof (LttvTraceStats
),
337 (GInstanceInitFunc
) trace_stats_instance_init
, /* instance_init */
338 NULL
/* Value handling */
341 type
= g_type_register_static (LTTV_TRACE_STATE_TYPE
,
342 "LttvTraceStatsType", &info
, 0);
349 tracefile_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
355 tracefile_stats_finalize (LttvTracefileStats
*self
)
357 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE
))->
358 finalize(G_OBJECT(self
));
363 tracefile_stats_class_init (LttvTracefileStatsClass
*klass
)
365 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
367 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_stats_finalize
;
372 lttv_tracefile_stats_get_type(void)
374 static GType type
= 0;
376 static const GTypeInfo info
= {
377 sizeof (LttvTracefileStatsClass
),
378 NULL
, /* base_init */
379 NULL
, /* base_finalize */
380 (GClassInitFunc
) tracefile_stats_class_init
, /* class_init */
381 NULL
, /* class_finalize */
382 NULL
, /* class_data */
383 sizeof (LttvTracefileStats
),
385 (GInstanceInitFunc
) tracefile_stats_instance_init
, /* instance_init */
386 NULL
/* Value handling */
389 type
= g_type_register_static (LTTV_TRACEFILE_STATE_TYPE
,
390 "LttvTracefileStatsType", &info
, 0);
397 find_event_tree(LttvTracefileStats
*tfcs
,
403 LttvAttribute
**events_tree
,
404 LttvAttribute
**event_types_tree
)
406 LttvAttribute
*a
, *prev_a
;
407 gchar fstring
[MAX_64_HEX_STRING_LEN
];
409 g_assert(snprintf(fstring
, MAX_64_HEX_STRING_LEN
-1,
410 "0x%llX", function
) > 0);
411 fstring
[MAX_64_HEX_STRING_LEN
-1] = '\0';
413 LttvTraceStats
*tcs
= (LttvTraceStats
*)tfcs
->parent
.parent
.t_context
;
414 a
= lttv_attribute_find_subdir(tcs
->stats
, LTTV_STATS_PROCESSES
);
415 a
= lttv_attribute_find_subdir(a
, pid_time
);
416 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_CPU
);
417 a
= lttv_attribute_find_subdir_unnamed(a
, cpu
);
418 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_FUNCTIONS
);
419 a
= lttv_attribute_find_subdir(a
, g_quark_from_string(fstring
));
420 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_MODE_TYPES
);
421 a
= lttv_attribute_find_subdir(a
, mode
);
422 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_SUBMODES
);
423 a
= lttv_attribute_find_subdir(a
, sub_mode
);
425 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_EVENT_TYPES
);
426 *event_types_tree
= a
;
430 static void update_event_tree(LttvTracefileStats
*tfcs
)
432 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
433 guint cpu
= tfcs
->parent
.cpu
;
434 LttvProcessState
*process
= ts
->running_process
[cpu
];
435 LttvExecutionState
*es
= process
->state
;
437 find_event_tree(tfcs
, process
->pid_time
,
439 process
->current_function
,
440 es
->t
, es
->n
, &(tfcs
->current_events_tree
),
441 &(tfcs
->current_event_types_tree
));
445 static void mode_change(LttvTracefileStats
*tfcs
)
447 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
448 guint cpu
= tfcs
->parent
.cpu
;
449 LttvProcessState
*process
= ts
->running_process
[cpu
];
450 LttvAttributeValue cpu_time
;
454 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
455 LTTV_TIME
, &cpu_time
);
456 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
457 process
->state
->change
);
458 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
462 static void mode_end(LttvTracefileStats
*tfcs
)
464 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
465 guint cpu
= tfcs
->parent
.cpu
;
466 LttvProcessState
*process
= ts
->running_process
[cpu
];
467 LttvAttributeValue elapsed_time
, cpu_time
;
471 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_ELAPSED_TIME
,
472 LTTV_TIME
, &elapsed_time
);
473 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
474 process
->state
->entry
);
475 *(elapsed_time
.v_time
) = ltt_time_add(*(elapsed_time
.v_time
), delta
);
477 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
478 LTTV_TIME
, &cpu_time
);
479 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
480 process
->state
->change
);
481 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
485 static gboolean
before_syscall_entry(void *hook_data
, void *call_data
)
487 mode_change((LttvTracefileStats
*)call_data
);
492 static gboolean
after_syscall_entry(void *hook_data
, void *call_data
)
494 update_event_tree((LttvTracefileStats
*)call_data
);
499 gboolean
before_syscall_exit(void *hook_data
, void *call_data
)
501 mode_end((LttvTracefileStats
*)call_data
);
506 static gboolean
after_syscall_exit(void *hook_data
, void *call_data
)
508 update_event_tree((LttvTracefileStats
*)call_data
);
513 gboolean
before_trap_entry(void *hook_data
, void *call_data
)
515 mode_change((LttvTracefileStats
*)call_data
);
520 static gboolean
after_trap_entry(void *hook_data
, void *call_data
)
522 update_event_tree((LttvTracefileStats
*)call_data
);
527 gboolean
before_trap_exit(void *hook_data
, void *call_data
)
529 mode_end((LttvTracefileStats
*)call_data
);
534 gboolean
after_trap_exit(void *hook_data
, void *call_data
)
536 update_event_tree((LttvTracefileStats
*)call_data
);
541 gboolean
before_irq_entry(void *hook_data
, void *call_data
)
543 mode_change((LttvTracefileStats
*)call_data
);
547 gboolean
after_irq_entry(void *hook_data
, void *call_data
)
549 update_event_tree((LttvTracefileStats
*)call_data
);
554 gboolean
before_irq_exit(void *hook_data
, void *call_data
)
556 mode_end((LttvTracefileStats
*)call_data
);
561 gboolean
after_irq_exit(void *hook_data
, void *call_data
)
563 update_event_tree((LttvTracefileStats
*)call_data
);
568 gboolean
before_soft_irq_entry(void *hook_data
, void *call_data
)
570 mode_change((LttvTracefileStats
*)call_data
);
574 gboolean
after_soft_irq_entry(void *hook_data
, void *call_data
)
576 update_event_tree((LttvTracefileStats
*)call_data
);
581 gboolean
before_soft_irq_exit(void *hook_data
, void *call_data
)
583 mode_end((LttvTracefileStats
*)call_data
);
588 gboolean
after_soft_irq_exit(void *hook_data
, void *call_data
)
590 update_event_tree((LttvTracefileStats
*)call_data
);
594 gboolean
before_function_entry(void *hook_data
, void *call_data
)
596 mode_end((LttvTracefileStats
*)call_data
);
600 gboolean
after_function_entry(void *hook_data
, void *call_data
)
602 update_event_tree((LttvTracefileStats
*)call_data
);
606 gboolean
before_function_exit(void *hook_data
, void *call_data
)
608 mode_end((LttvTracefileStats
*)call_data
);
612 gboolean
after_function_exit(void *hook_data
, void *call_data
)
614 update_event_tree((LttvTracefileStats
*)call_data
);
619 gboolean
before_schedchange(void *hook_data
, void *call_data
)
621 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
623 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
625 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
627 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
629 guint pid_in
, pid_out
;
633 LttvProcessState
*process
;
635 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
636 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
637 state_out
= ltt_event_get_int(e
, thf
->f3
);
639 /* compute the time for the process to schedule out */
643 /* get the information for the process scheduled in */
645 process
= lttv_state_find_process_or_create(ts
,
646 ANY_CPU
, pid_in
, &tfcs
->parent
.parent
.timestamp
);
648 guint cpu
= tfcs
->parent
.cpu
;
650 find_event_tree(tfcs
, process
->pid_time
,
652 process
->current_function
,
653 process
->state
->t
, process
->state
->n
, &(tfcs
->current_events_tree
),
654 &(tfcs
->current_event_types_tree
));
656 /* compute the time waiting for the process to schedule in */
663 gboolean
process_fork(void *hook_data
, void *call_data
)
665 /* nothing to do for now */
670 gboolean
process_exit(void *hook_data
, void *call_data
)
672 /* We should probably exit all modes here or we could do that at
677 gboolean
process_free(void *hook_data
, void *call_data
)
682 gboolean
every_event(void *hook_data
, void *call_data
)
684 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
686 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
688 LttvAttributeValue v
;
690 /* The current branch corresponds to the tracefile/process/interrupt state.
691 Statistics are added within it, to count the number of events of this
692 type occuring in this context. A quark has been pre-allocated for each
693 event type and is used as name. */
695 lttv_attribute_find(tfcs
->current_event_types_tree
,
696 ltt_eventtype_name(ltt_event_eventtype(e
)),
704 lttv_stats_sum_trace(LttvTraceStats
*self
, LttvAttribute
*ts_stats
)
706 LttvAttribute
*sum_container
= self
->stats
;
708 LttvAttributeType type
;
710 LttvAttributeValue value
;
712 LttvAttributeName name
;
720 int i
, j
, k
, l
, m
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
,
721 nb_event_type
, nf
, nb_functions
;
723 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
724 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
725 *submode_tree
, *event_types_tree
, *mode_events_tree
,
728 *function_mode_types_tree
,
731 main_tree
= sum_container
;
733 lttv_attribute_find(sum_container
,
736 trace_is_summed
= *(value
.v_uint
);
739 processes_tree
= lttv_attribute_find_subdir(main_tree
,
740 LTTV_STATS_PROCESSES
);
741 nb_process
= lttv_attribute_get_number(processes_tree
);
743 for(i
= 0 ; i
< nb_process
; i
++) {
744 type
= lttv_attribute_get(processes_tree
, i
, &name
, &value
, &is_named
);
745 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
747 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
748 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
750 for(j
= 0 ; j
< nb_cpu
; j
++) {
751 type
= lttv_attribute_get(cpus_tree
, j
, &name
, &value
, &is_named
);
752 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
754 trace_cpu_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_CPU
);
755 trace_cpu_tree
= lttv_attribute_find_subdir_unnamed(trace_cpu_tree
, name
);
756 cpu_functions_tree
= lttv_attribute_find_subdir(cpu_tree
,
757 LTTV_STATS_FUNCTIONS
);
758 nb_functions
= lttv_attribute_get_number(cpu_functions_tree
);
760 for(nf
=0; nf
< nb_functions
; nf
++) {
761 type
= lttv_attribute_get(cpu_functions_tree
, nf
, &name
, &value
,
763 function_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
764 function_mode_types_tree
= lttv_attribute_find_subdir(function_tree
,
765 LTTV_STATS_MODE_TYPES
);
766 nb_mode_type
= lttv_attribute_get_number(function_mode_types_tree
);
767 for(k
= 0 ; k
< nb_mode_type
; k
++) {
768 type
= lttv_attribute_get(function_mode_types_tree
, k
, &name
, &value
,
770 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
772 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,
773 LTTV_STATS_SUBMODES
);
774 mode_events_tree
= lttv_attribute_find_subdir(mode_tree
,
776 mode_types_tree
= lttv_attribute_find_subdir(mode_tree
,
777 LTTV_STATS_MODE_TYPES
);
779 nb_submode
= lttv_attribute_get_number(submodes_tree
);
781 for(l
= 0 ; l
< nb_submode
; l
++) {
782 type
= lttv_attribute_get(submodes_tree
, l
, &name
, &value
,
784 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
786 event_types_tree
= lttv_attribute_find_subdir(submode_tree
,
787 LTTV_STATS_EVENT_TYPES
);
788 nb_event_type
= lttv_attribute_get_number(event_types_tree
);
791 for(m
= 0 ; m
< nb_event_type
; m
++) {
792 type
= lttv_attribute_get(event_types_tree
, m
, &name
, &value
,
794 sum
+= *(value
.v_uint
);
796 lttv_attribute_find(submode_tree
, LTTV_STATS_EVENTS_COUNT
,
798 *(value
.v_uint
) = sum
;
800 type
= lttv_attribute_get(submodes_tree
, l
, &name
, &value
,
802 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
803 if(!trace_is_summed
) {
804 lttv_attribute_recursive_add(mode_events_tree
, event_types_tree
);
805 lttv_attribute_recursive_add(mode_types_tree
, submode_tree
);
808 if(!trace_is_summed
) {
809 lttv_attribute_recursive_add(main_tree
, mode_types_tree
);
810 lttv_attribute_recursive_add(trace_cpu_tree
, mode_types_tree
);
811 lttv_attribute_recursive_add(process_tree
, mode_types_tree
);
812 lttv_attribute_recursive_add(function_tree
, mode_types_tree
);
814 lttv_attribute_recursive_add(ts_stats
, mode_types_tree
);
817 if(!trace_is_summed
) {
818 lttv_attribute_recursive_add(process_tree
, cpu_tree
);
825 gboolean
lttv_stats_sum_traceset_hook(void *hook_data
, void *call_data
)
827 lttv_stats_sum_traceset((LttvTracesetStats
*)call_data
);
832 lttv_stats_sum_traceset(LttvTracesetStats
*self
)
834 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
835 LttvAttribute
*sum_container
= self
->stats
;
841 LttvAttribute
*main_tree
;
843 LttvAttributeValue value
;
845 lttv_attribute_find(sum_container
, LTTV_STATS_SUMMED
,
847 if(*(value
.v_uint
) != 0) return;
850 nb_trace
= lttv_traceset_number(traceset
);
852 for(i
= 0 ; i
< nb_trace
; i
++) {
853 tcs
= (LttvTraceStats
*)(self
->parent
.parent
.traces
[i
]);
854 lttv_stats_sum_trace(tcs
, self
->stats
);
855 // lttv_attribute_recursive_add(sum_container, tcs->stats);
860 // Hook wrapper. call_data is a traceset context.
861 gboolean
lttv_stats_hook_add_event_hooks(void *hook_data
, void *call_data
)
863 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
865 lttv_stats_add_event_hooks(tss
);
870 void lttv_stats_add_event_hooks(LttvTracesetStats
*self
)
872 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
874 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
878 LttvTracefileStats
*tfs
;
880 GArray
*hooks
, *before_hooks
, *after_hooks
;
884 LttvTraceHookByFacility
*thf
;
886 LttvAttributeValue val
;
891 nb_trace
= lttv_traceset_number(traceset
);
892 for(i
= 0 ; i
< nb_trace
; i
++) {
893 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
895 /* Find the eventtype id for the following events and register the
896 associated by id hooks. */
898 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 11);
899 g_array_set_size(hooks
, 11);
902 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
903 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
904 LTT_FIELD_SYSCALL_ID
, 0, 0,
905 before_syscall_entry
, NULL
,
906 &g_array_index(hooks
, LttvTraceHook
, hn
++));
909 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
910 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
912 before_syscall_exit
, NULL
,
913 &g_array_index(hooks
, LttvTraceHook
, hn
++));
916 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
917 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
918 LTT_FIELD_TRAP_ID
, 0, 0,
919 before_trap_entry
, NULL
,
920 &g_array_index(hooks
, LttvTraceHook
, hn
++));
923 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
924 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
926 before_trap_exit
, NULL
,
927 &g_array_index(hooks
, LttvTraceHook
, hn
++));
930 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
931 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
932 LTT_FIELD_IRQ_ID
, 0, 0,
933 before_irq_entry
, NULL
,
934 &g_array_index(hooks
, LttvTraceHook
, hn
++));
937 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
938 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
940 before_irq_exit
, NULL
,
941 &g_array_index(hooks
, LttvTraceHook
, hn
++));
944 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
945 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
946 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
947 before_soft_irq_entry
, NULL
,
948 &g_array_index(hooks
, LttvTraceHook
, hn
++));
951 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
952 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
954 before_soft_irq_exit
, NULL
,
955 &g_array_index(hooks
, LttvTraceHook
, hn
++));
958 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
959 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
960 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
961 before_schedchange
, NULL
,
962 &g_array_index(hooks
, LttvTraceHook
, hn
++));
965 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
966 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
967 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
968 before_function_entry
, NULL
,
969 &g_array_index(hooks
, LttvTraceHook
, hn
++));
972 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
973 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
974 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
975 before_function_exit
, NULL
,
976 &g_array_index(hooks
, LttvTraceHook
, hn
++));
979 g_array_set_size(hooks
, hn
);
981 before_hooks
= hooks
;
983 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 13);
984 g_array_set_size(hooks
, 13);
987 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
988 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
989 LTT_FIELD_SYSCALL_ID
, 0, 0,
990 after_syscall_entry
, NULL
,
991 &g_array_index(hooks
, LttvTraceHook
, hn
++));
994 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
995 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
997 after_syscall_exit
, NULL
,
998 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1001 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1002 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1003 LTT_FIELD_TRAP_ID
, 0, 0,
1004 after_trap_entry
, NULL
,
1005 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1008 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1009 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1011 after_trap_exit
, NULL
,
1012 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1015 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1016 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1017 LTT_FIELD_IRQ_ID
, 0, 0,
1018 after_irq_entry
, NULL
,
1019 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1022 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1023 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1025 after_irq_exit
, NULL
,
1026 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1029 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1030 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1031 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1032 after_irq_entry
, NULL
,
1033 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1036 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1037 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1039 after_soft_irq_exit
, NULL
,
1040 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1043 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1044 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1045 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1047 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1050 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1051 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1052 LTT_FIELD_PID
, 0, 0,
1054 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1057 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1058 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1059 LTT_FIELD_PID
, 0, 0,
1061 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1064 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1065 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
1066 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1067 after_function_entry
, NULL
,
1068 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1071 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
1072 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
1073 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1074 after_function_exit
, NULL
,
1075 &g_array_index(hooks
, LttvTraceHook
, hn
++));
1078 g_array_set_size(hooks
, hn
);
1080 after_hooks
= hooks
;
1082 /* Add these hooks to each event_by_id hooks list */
1084 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
1086 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1087 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
1088 LttvTracefileContext
*, j
));
1089 lttv_hooks_add(tfs
->parent
.parent
.event
, every_event
, NULL
,
1092 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1093 hook
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1094 for(l
= 0; l
<hook
->fac_list
->len
;l
++) {
1095 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1097 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1100 LTTV_PRIO_STATS_BEFORE_STATE
);
1103 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1104 hook
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1105 for(l
= 0; l
<hook
->fac_list
->len
;l
++) {
1106 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1108 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1111 LTTV_PRIO_STATS_AFTER_STATE
);
1115 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
1116 LTTV_POINTER
, &val
);
1117 *(val
.v_pointer
) = before_hooks
;
1118 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
1119 LTTV_POINTER
, &val
);
1120 *(val
.v_pointer
) = after_hooks
;
1124 // Hook wrapper. call_data is a traceset context.
1125 gboolean
lttv_stats_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1127 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
1129 lttv_stats_remove_event_hooks(tss
);
1134 void lttv_stats_remove_event_hooks(LttvTracesetStats
*self
)
1136 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
1138 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1142 LttvTracefileStats
*tfs
;
1146 GArray
*before_hooks
, *after_hooks
;
1148 LttvTraceHook
*hook
;
1150 LttvTraceHookByFacility
*thf
;
1152 LttvAttributeValue val
;
1154 nb_trace
= lttv_traceset_number(traceset
);
1155 for(i
= 0 ; i
< nb_trace
; i
++) {
1156 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
1157 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
1158 LTTV_POINTER
, &val
);
1159 before_hooks
= *(val
.v_pointer
);
1160 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
1161 LTTV_POINTER
, &val
);
1162 after_hooks
= *(val
.v_pointer
);
1164 /* Remove these hooks from each event_by_id hooks list */
1166 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
1168 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1169 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
1170 LttvTracefileContext
*, j
));
1171 lttv_hooks_remove_data(tfs
->parent
.parent
.event
, every_event
,
1174 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1175 hook
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1176 for(l
= 0 ; l
< hook
->fac_list
->len
; l
++) {
1177 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1178 lttv_hooks_remove_data(
1179 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1184 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1185 hook
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1186 for(l
= 0 ; l
< hook
->fac_list
->len
; l
++) {
1187 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1188 lttv_hooks_remove_data(
1189 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1195 g_debug("lttv_stats_remove_event_hooks()");
1196 g_array_free(before_hooks
, TRUE
);
1197 g_array_free(after_hooks
, TRUE
);
1202 static void module_init()
1204 LTTV_STATS_PROCESS_UNKNOWN
= g_quark_from_string("unknown process");
1205 LTTV_STATS_PROCESSES
= g_quark_from_string("processes");
1206 LTTV_STATS_CPU
= g_quark_from_string("cpu");
1207 LTTV_STATS_MODE_TYPES
= g_quark_from_string("mode_types");
1208 LTTV_STATS_MODES
= g_quark_from_string("modes");
1209 LTTV_STATS_SUBMODES
= g_quark_from_string("submodes");
1210 LTTV_STATS_FUNCTIONS
= g_quark_from_string("functions");
1211 LTTV_STATS_EVENT_TYPES
= g_quark_from_string("event_types");
1212 LTTV_STATS_CPU_TIME
= g_quark_from_string("cpu time");
1213 LTTV_STATS_ELAPSED_TIME
= g_quark_from_string("elapsed time");
1214 LTTV_STATS_EVENTS
= g_quark_from_string("events");
1215 LTTV_STATS_EVENTS_COUNT
= g_quark_from_string("events count");
1216 LTTV_STATS_BEFORE_HOOKS
= g_quark_from_string("saved stats before hooks");
1217 LTTV_STATS_AFTER_HOOKS
= g_quark_from_string("saved stats after hooks");
1218 LTTV_STATS_USE_COUNT
= g_quark_from_string("stats_use_count");
1219 LTTV_STATS
= g_quark_from_string("statistics");
1220 LTTV_STATS_TRACEFILES
= g_quark_from_string("tracefiles statistics");
1221 LTTV_STATS_SUMMED
= g_quark_from_string("statistics summed");
1224 static void module_destroy()
1229 LTTV_MODULE("stats", "Compute processes statistics", \
1230 "Accumulate statistics for event types, processes and CPUs", \
1231 module_init
, module_destroy
, "state");
1233 /* Change the places where stats are called (create/read/write stats)
1235 Check for options in batchtest.c to reduce writing and see what tests are
1236 best candidates for performance analysis. Once OK, commit, move to main
1237 and run tests. Update the gui for statistics. */