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>
36 LTTV_STATS_PROCESS_UNKNOWN
,
39 LTTV_STATS_MODE_TYPES
,
42 LTTV_STATS_EVENT_TYPES
,
44 LTTV_STATS_ELAPSED_TIME
,
46 LTTV_STATS_EVENTS_COUNT
,
49 LTTV_STATS_TRACEFILES
,
53 LTTV_STATS_BEFORE_HOOKS
,
54 LTTV_STATS_AFTER_HOOKS
;
57 find_event_tree(LttvTracefileStats
*tfcs
, GQuark pid_time
, GQuark cpu
,
58 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
59 LttvAttribute
**event_types_tree
);
62 init(LttvTracesetStats
*self
, LttvTraceset
*ts
)
64 guint i
, j
, nb_trace
, nb_tracefile
;
70 LttvTracefileContext
*tfc
;
72 LttvTracefileContext
**tfs
;
73 LttvTracefileStats
*tfcs
;
75 LttTime timestamp
= {0,0};
83 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
84 init((LttvTracesetContext
*)self
, 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
),
125 LTTV_STATE_MODE_UNKNOWN
,
126 LTTV_STATE_SUBMODE_UNKNOWN
, &tfcs
->current_events_tree
,
127 &tfcs
->current_event_types_tree
);
133 fini(LttvTracesetStats
*self
)
135 guint i
, j
, nb_trace
, nb_tracefile
;
139 LttvTraceContext
*tc
;
143 LttvTracefileContext
*tfc
;
145 LttvTracefileStats
*tfcs
;
147 LttTime timestamp
= {0,0};
149 LttvAttributeValue v
;
151 LttvAttribute
*tracefiles_stats
;
153 lttv_attribute_find(self
->parent
.parent
.ts_a
, LTTV_STATS_USE_COUNT
,
157 if(*(v
.v_uint
) == 0) {
158 lttv_attribute_remove_by_name(self
->parent
.parent
.ts_a
, LTTV_STATS
);
162 ts
= self
->parent
.parent
.ts
;
163 nb_trace
= lttv_traceset_number(ts
);
165 for(i
= 0 ; i
< nb_trace
; i
++) {
166 tcs
= (LttvTraceStats
*)(tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]));
168 lttv_attribute_find(tcs
->parent
.parent
.t_a
, LTTV_STATS_USE_COUNT
,
172 if(*(v
.v_uint
) == 0) {
173 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
,LTTV_STATS
);
174 tracefiles_stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,
175 LTTV_STATS_TRACEFILES
);
176 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
,
177 LTTV_STATS_TRACEFILES
);
181 nb_tracefile
= tc
->tracefiles
->len
;
183 for(j
= 0 ; j
< nb_tracefile
; j
++) {
184 tfc
= g_array_index(tc
->tracefiles
,
185 LttvTracefileContext
*, j
);
186 tfcs
= (LttvTracefileStats
*)tfc
;
188 tfcs
->current_events_tree
= NULL
;
189 tfcs
->current_event_types_tree
= NULL
;
192 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
193 fini((LttvTracesetContext
*)self
);
197 static LttvTracesetContext
*
198 new_traceset_context(LttvTracesetContext
*self
)
200 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE
, NULL
));
204 static LttvTraceContext
*
205 new_trace_context(LttvTracesetContext
*self
)
207 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE
, NULL
));
211 static LttvTracefileContext
*
212 new_tracefile_context(LttvTracesetContext
*self
)
214 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE
, NULL
));
219 traceset_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
225 traceset_stats_finalize (LttvTracesetStats
*self
)
227 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
228 finalize(G_OBJECT(self
));
233 traceset_stats_class_init (LttvTracesetContextClass
*klass
)
235 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
237 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_stats_finalize
;
238 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
239 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
240 klass
->new_traceset_context
= new_traceset_context
;
241 klass
->new_trace_context
= new_trace_context
;
242 klass
->new_tracefile_context
= new_tracefile_context
;
247 lttv_traceset_stats_get_type(void)
249 static GType type
= 0;
251 static const GTypeInfo info
= {
252 sizeof (LttvTracesetStatsClass
),
253 NULL
, /* base_init */
254 NULL
, /* base_finalize */
255 (GClassInitFunc
) traceset_stats_class_init
, /* class_init */
256 NULL
, /* class_finalize */
257 NULL
, /* class_data */
258 sizeof (LttvTracesetStats
),
260 (GInstanceInitFunc
) traceset_stats_instance_init
, /* instance_init */
261 NULL
/* Value handling */
264 type
= g_type_register_static (LTTV_TRACESET_STATE_TYPE
,
265 "LttvTracesetStatsType",
273 trace_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
279 trace_stats_finalize (LttvTraceStats
*self
)
281 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE
))->
282 finalize(G_OBJECT(self
));
287 trace_stats_class_init (LttvTraceContextClass
*klass
)
289 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
291 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_stats_finalize
;
296 lttv_trace_stats_get_type(void)
298 static GType type
= 0;
300 static const GTypeInfo info
= {
301 sizeof (LttvTraceStatsClass
),
302 NULL
, /* base_init */
303 NULL
, /* base_finalize */
304 (GClassInitFunc
) trace_stats_class_init
, /* class_init */
305 NULL
, /* class_finalize */
306 NULL
, /* class_data */
307 sizeof (LttvTraceStats
),
309 (GInstanceInitFunc
) trace_stats_instance_init
, /* instance_init */
310 NULL
/* Value handling */
313 type
= g_type_register_static (LTTV_TRACE_STATE_TYPE
,
314 "LttvTraceStatsType", &info
, 0);
321 tracefile_stats_instance_init (GTypeInstance
*instance
, gpointer g_class
)
327 tracefile_stats_finalize (LttvTracefileStats
*self
)
329 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE
))->
330 finalize(G_OBJECT(self
));
335 tracefile_stats_class_init (LttvTracefileStatsClass
*klass
)
337 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
339 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_stats_finalize
;
344 lttv_tracefile_stats_get_type(void)
346 static GType type
= 0;
348 static const GTypeInfo info
= {
349 sizeof (LttvTracefileStatsClass
),
350 NULL
, /* base_init */
351 NULL
, /* base_finalize */
352 (GClassInitFunc
) tracefile_stats_class_init
, /* class_init */
353 NULL
, /* class_finalize */
354 NULL
, /* class_data */
355 sizeof (LttvTracefileStats
),
357 (GInstanceInitFunc
) tracefile_stats_instance_init
, /* instance_init */
358 NULL
/* Value handling */
361 type
= g_type_register_static (LTTV_TRACEFILE_STATE_TYPE
,
362 "LttvTracefileStatsType", &info
, 0);
369 find_event_tree(LttvTracefileStats
*tfcs
,
374 LttvAttribute
**events_tree
,
375 LttvAttribute
**event_types_tree
)
379 LttvTraceStats
*tcs
= (LttvTraceStats
*)tfcs
->parent
.parent
.t_context
;
380 a
= lttv_attribute_find_subdir(tcs
->stats
, LTTV_STATS_PROCESSES
);
381 a
= lttv_attribute_find_subdir(a
, pid_time
);
382 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_CPU
);
383 a
= lttv_attribute_find_subdir(a
, cpu
);
384 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_MODE_TYPES
);
385 a
= lttv_attribute_find_subdir(a
, mode
);
386 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_SUBMODES
);
387 a
= lttv_attribute_find_subdir(a
, sub_mode
);
389 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_EVENT_TYPES
);
390 *event_types_tree
= a
;
394 static void update_event_tree(LttvTracefileStats
*tfcs
)
396 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
397 guint cpu
= ltt_tracefile_num(tfcs
->parent
.parent
.tf
);
398 LttvProcessState
*process
= ts
->running_process
[cpu
];
399 LttvExecutionState
*es
= process
->state
;
401 find_event_tree(tfcs
, process
->pid_time
,
402 ltt_tracefile_long_name(tfcs
->parent
.parent
.tf
),
403 es
->t
, es
->n
, &(tfcs
->current_events_tree
),
404 &(tfcs
->current_event_types_tree
));
408 static void mode_change(LttvTracefileStats
*tfcs
)
410 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
411 guint cpu
= ltt_tracefile_num(tfcs
->parent
.parent
.tf
);
412 LttvProcessState
*process
= ts
->running_process
[cpu
];
413 LttvAttributeValue cpu_time
;
417 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
418 LTTV_TIME
, &cpu_time
);
419 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
420 process
->state
->change
);
421 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
425 static void mode_end(LttvTracefileStats
*tfcs
)
427 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
428 guint cpu
= ltt_tracefile_num(tfcs
->parent
.parent
.tf
);
429 LttvProcessState
*process
= ts
->running_process
[cpu
];
430 LttvAttributeValue elapsed_time
, cpu_time
;
434 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_ELAPSED_TIME
,
435 LTTV_TIME
, &elapsed_time
);
436 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
437 process
->state
->entry
);
438 *(elapsed_time
.v_time
) = ltt_time_add(*(elapsed_time
.v_time
), delta
);
440 lttv_attribute_find(tfcs
->current_events_tree
, LTTV_STATS_CPU_TIME
,
441 LTTV_TIME
, &cpu_time
);
442 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
443 process
->state
->change
);
444 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
448 static gboolean
before_syscall_entry(void *hook_data
, void *call_data
)
450 mode_change((LttvTracefileStats
*)call_data
);
455 static gboolean
after_syscall_entry(void *hook_data
, void *call_data
)
457 update_event_tree((LttvTracefileStats
*)call_data
);
462 gboolean
before_syscall_exit(void *hook_data
, void *call_data
)
464 mode_end((LttvTracefileStats
*)call_data
);
469 static gboolean
after_syscall_exit(void *hook_data
, void *call_data
)
471 update_event_tree((LttvTracefileStats
*)call_data
);
476 gboolean
before_trap_entry(void *hook_data
, void *call_data
)
478 mode_change((LttvTracefileStats
*)call_data
);
483 static gboolean
after_trap_entry(void *hook_data
, void *call_data
)
485 update_event_tree((LttvTracefileStats
*)call_data
);
490 gboolean
before_trap_exit(void *hook_data
, void *call_data
)
492 mode_end((LttvTracefileStats
*)call_data
);
497 gboolean
after_trap_exit(void *hook_data
, void *call_data
)
499 update_event_tree((LttvTracefileStats
*)call_data
);
504 gboolean
before_irq_entry(void *hook_data
, void *call_data
)
506 mode_change((LttvTracefileStats
*)call_data
);
511 gboolean
after_irq_entry(void *hook_data
, void *call_data
)
513 update_event_tree((LttvTracefileStats
*)call_data
);
518 gboolean
before_irq_exit(void *hook_data
, void *call_data
)
520 mode_end((LttvTracefileStats
*)call_data
);
525 gboolean
after_irq_exit(void *hook_data
, void *call_data
)
527 update_event_tree((LttvTracefileStats
*)call_data
);
532 gboolean
before_schedchange(void *hook_data
, void *call_data
)
534 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
536 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
538 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
540 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
542 guint pid_in
, pid_out
;
546 LttvProcessState
*process
;
548 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
549 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
550 state_out
= ltt_event_get_int(e
, thf
->f3
);
552 /* compute the time for the process to schedule out */
556 /* get the information for the process scheduled in */
558 process
= lttv_state_find_process_or_create(ts
,
559 ANY_CPU
, pid_in
, &tfcs
->parent
.parent
.timestamp
);
561 find_event_tree(tfcs
, process
->pid_time
,
562 ltt_tracefile_long_name(tfcs
->parent
.parent
.tf
),
563 process
->state
->t
, process
->state
->n
, &(tfcs
->current_events_tree
),
564 &(tfcs
->current_event_types_tree
));
566 /* compute the time waiting for the process to schedule in */
573 gboolean
process_fork(void *hook_data
, void *call_data
)
575 /* nothing to do for now */
580 gboolean
process_exit(void *hook_data
, void *call_data
)
582 /* We should probably exit all modes here or we could do that at
587 gboolean
process_free(void *hook_data
, void *call_data
)
592 gboolean
every_event(void *hook_data
, void *call_data
)
594 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
596 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
598 LttvAttributeValue v
;
600 /* The current branch corresponds to the tracefile/process/interrupt state.
601 Statistics are added within it, to count the number of events of this
602 type occuring in this context. A quark has been pre-allocated for each
603 event type and is used as name. */
605 lttv_attribute_find(tfcs
->current_event_types_tree
,
606 ltt_eventtype_name(ltt_event_eventtype(e
)),
614 lttv_stats_sum_trace(LttvTraceStats
*self
)
616 LttvAttribute
*sum_container
= self
->stats
;
618 LttvAttributeType type
;
620 LttvAttributeValue value
;
622 LttvAttributeName name
;
626 int i
, j
, k
, l
, m
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
,
629 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
630 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
631 *submode_tree
, *event_types_tree
, *mode_events_tree
,
632 *cpu_events_tree
, *process_modes_tree
, *trace_cpu_tree
,
635 main_tree
= sum_container
;
637 lttv_attribute_find(sum_container
,
640 if(*(value
.v_uint
) != 0) return;
643 processes_tree
= lttv_attribute_find_subdir(main_tree
,
644 LTTV_STATS_PROCESSES
);
645 trace_modes_tree
= lttv_attribute_find_subdir(main_tree
,
647 nb_process
= lttv_attribute_get_number(processes_tree
);
649 for(i
= 0 ; i
< nb_process
; i
++) {
650 type
= lttv_attribute_get(processes_tree
, i
, &name
, &value
);
651 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
653 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
654 process_modes_tree
= lttv_attribute_find_subdir(process_tree
,
656 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
658 for(j
= 0 ; j
< nb_cpu
; j
++) {
659 type
= lttv_attribute_get(cpus_tree
, j
, &name
, &value
);
660 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
662 mode_types_tree
= lttv_attribute_find_subdir(cpu_tree
,
663 LTTV_STATS_MODE_TYPES
);
664 cpu_events_tree
= lttv_attribute_find_subdir(cpu_tree
,
666 trace_cpu_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_CPU
);
667 trace_cpu_tree
= lttv_attribute_find_subdir(trace_cpu_tree
, name
);
668 nb_mode_type
= lttv_attribute_get_number(mode_types_tree
);
670 for(k
= 0 ; k
< nb_mode_type
; k
++) {
671 type
= lttv_attribute_get(mode_types_tree
, k
, &name
, &value
);
672 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
674 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,
675 LTTV_STATS_SUBMODES
);
676 mode_events_tree
= lttv_attribute_find_subdir(mode_tree
,
678 nb_submode
= lttv_attribute_get_number(submodes_tree
);
680 for(l
= 0 ; l
< nb_submode
; l
++) {
681 type
= lttv_attribute_get(submodes_tree
, l
, &name
, &value
);
682 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
684 event_types_tree
= lttv_attribute_find_subdir(submode_tree
,
685 LTTV_STATS_EVENT_TYPES
);
686 nb_event_type
= lttv_attribute_get_number(event_types_tree
);
689 for(m
= 0 ; m
< nb_event_type
; m
++) {
690 type
= lttv_attribute_get(event_types_tree
, m
, &name
, &value
);
691 sum
+= *(value
.v_uint
);
693 lttv_attribute_find(submode_tree
, LTTV_STATS_EVENTS_COUNT
,
695 *(value
.v_uint
) = sum
;
696 lttv_attribute_recursive_add(mode_events_tree
, submode_tree
);
698 lttv_attribute_recursive_add(cpu_events_tree
, mode_events_tree
);
700 lttv_attribute_recursive_add(process_modes_tree
, cpu_tree
);
701 lttv_attribute_recursive_add(trace_cpu_tree
, cpu_tree
);
703 lttv_attribute_recursive_add(trace_modes_tree
, process_modes_tree
);
708 gboolean
lttv_stats_sum_traceset_hook(void *hook_data
, void *call_data
)
710 lttv_stats_sum_traceset((LttvTracesetStats
*)call_data
);
715 lttv_stats_sum_traceset(LttvTracesetStats
*self
)
717 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
718 LttvAttribute
*sum_container
= self
->stats
;
724 LttvAttribute
*main_tree
, *trace_modes_tree
, *traceset_modes_tree
;
726 LttvAttributeValue value
;
728 lttv_attribute_find(sum_container
, LTTV_STATS_SUMMED
,
730 if(*(value
.v_uint
) != 0) return;
733 traceset_modes_tree
= lttv_attribute_find_subdir(sum_container
,
735 nb_trace
= lttv_traceset_number(traceset
);
737 for(i
= 0 ; i
< nb_trace
; i
++) {
738 tcs
= (LttvTraceStats
*)(self
->parent
.parent
.traces
[i
]);
739 lttv_stats_sum_trace(tcs
);
740 main_tree
= tcs
->stats
;
741 trace_modes_tree
= lttv_attribute_find_subdir(main_tree
, LTTV_STATS_MODES
);
742 lttv_attribute_recursive_add(traceset_modes_tree
, trace_modes_tree
);
747 // Hook wrapper. call_data is a traceset context.
748 gboolean
lttv_stats_hook_add_event_hooks(void *hook_data
, void *call_data
)
750 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
752 lttv_stats_add_event_hooks(tss
);
757 void lttv_stats_add_event_hooks(LttvTracesetStats
*self
)
759 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
761 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
765 LttvTracefileStats
*tfs
;
767 GArray
*hooks
, *before_hooks
, *after_hooks
;
771 LttvTraceHookByFacility
*thf
;
773 LttvAttributeValue val
;
777 nb_trace
= lttv_traceset_number(traceset
);
778 for(i
= 0 ; i
< nb_trace
; i
++) {
779 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
781 /* Find the eventtype id for the following events and register the
782 associated by id hooks. */
784 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 7);
785 g_array_set_size(hooks
, 7);
787 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
788 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
789 LTT_FIELD_SYSCALL_ID
, 0, 0,
790 before_syscall_entry
, NULL
,
791 &g_array_index(hooks
, LttvTraceHook
, 0));
794 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
795 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
797 before_syscall_exit
, NULL
,
798 &g_array_index(hooks
, LttvTraceHook
, 1));
801 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
802 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
803 LTT_FIELD_TRAP_ID
, 0, 0,
804 before_trap_entry
, NULL
,
805 &g_array_index(hooks
, LttvTraceHook
, 2));
808 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
809 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
811 before_trap_exit
, NULL
,
812 &g_array_index(hooks
, LttvTraceHook
, 3));
815 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
816 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
817 LTT_FIELD_IRQ_ID
, 0, 0,
818 before_irq_entry
, NULL
,
819 &g_array_index(hooks
, LttvTraceHook
, 4));
822 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
823 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
825 before_irq_exit
, NULL
,
826 &g_array_index(hooks
, LttvTraceHook
, 5));
829 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
830 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
831 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
832 before_schedchange
, NULL
,
833 &g_array_index(hooks
, LttvTraceHook
, 6));
836 before_hooks
= hooks
;
838 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 9);
839 g_array_set_size(hooks
, 9);
841 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
842 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
843 LTT_FIELD_SYSCALL_ID
, 0, 0,
844 after_syscall_entry
, NULL
,
845 &g_array_index(hooks
, LttvTraceHook
, 0));
848 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
849 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
851 after_syscall_exit
, NULL
,
852 &g_array_index(hooks
, LttvTraceHook
, 1));
855 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
856 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
857 LTT_FIELD_TRAP_ID
, 0, 0,
858 after_trap_entry
, NULL
,
859 &g_array_index(hooks
, LttvTraceHook
, 2));
862 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
863 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
865 after_trap_exit
, NULL
,
866 &g_array_index(hooks
, LttvTraceHook
, 3));
869 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
870 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
871 LTT_FIELD_IRQ_ID
, 0, 0,
872 after_irq_entry
, NULL
,
873 &g_array_index(hooks
, LttvTraceHook
, 4));
876 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
877 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
879 after_irq_exit
, NULL
,
880 &g_array_index(hooks
, LttvTraceHook
, 5));
884 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
885 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
886 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
888 &g_array_index(hooks
, LttvTraceHook
, 6));
891 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
892 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
895 &g_array_index(hooks
, LttvTraceHook
, 7));
898 ret
= lttv_trace_find_hook(ts
->parent
.parent
.t
,
899 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
902 &g_array_index(hooks
, LttvTraceHook
, 8));
908 /* Add these hooks to each event_by_id hooks list */
910 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
912 for(j
= 0 ; j
< nb_tracefile
; j
++) {
913 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
914 LttvTracefileContext
*, j
));
915 lttv_hooks_add(tfs
->parent
.parent
.event
, every_event
, NULL
,
918 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
919 hook
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
920 for(l
= 0; l
<hook
->fac_list
->len
;l
++) {
921 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
923 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
926 LTTV_PRIO_STATS_BEFORE_STATE
);
929 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
930 hook
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
931 for(l
= 0; l
<hook
->fac_list
->len
;l
++) {
932 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
934 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
937 LTTV_PRIO_STATS_AFTER_STATE
);
941 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
943 *(val
.v_pointer
) = before_hooks
;
944 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
946 *(val
.v_pointer
) = after_hooks
;
950 // Hook wrapper. call_data is a traceset context.
951 gboolean
lttv_stats_hook_remove_event_hooks(void *hook_data
, void *call_data
)
953 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
955 lttv_stats_remove_event_hooks(tss
);
960 void lttv_stats_remove_event_hooks(LttvTracesetStats
*self
)
962 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
964 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
968 LttvTracefileStats
*tfs
;
972 GArray
*before_hooks
, *after_hooks
;
976 LttvTraceHookByFacility
*thf
;
978 LttvAttributeValue val
;
980 nb_trace
= lttv_traceset_number(traceset
);
981 for(i
= 0 ; i
< nb_trace
; i
++) {
982 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
983 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
985 before_hooks
= *(val
.v_pointer
);
986 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
988 after_hooks
= *(val
.v_pointer
);
990 /* Remove these hooks from each event_by_id hooks list */
992 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
994 for(j
= 0 ; j
< nb_tracefile
; j
++) {
995 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
996 LttvTracefileContext
*, j
));
997 lttv_hooks_remove_data(tfs
->parent
.parent
.event
, every_event
,
1000 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1001 hook
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1002 for(l
= 0 ; l
< hook
->fac_list
->len
; l
++) {
1003 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1004 lttv_hooks_remove_data(
1005 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1010 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1011 hook
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1012 for(l
= 0 ; l
< hook
->fac_list
->len
; l
++) {
1013 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1014 lttv_hooks_remove_data(
1015 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, thf
->id
),
1021 g_debug("lttv_stats_remove_event_hooks()");
1022 g_array_free(before_hooks
, TRUE
);
1023 g_array_free(after_hooks
, TRUE
);
1028 static void module_init()
1030 LTTV_STATS_PROCESS_UNKNOWN
= g_quark_from_string("unknown process");
1031 LTTV_STATS_PROCESSES
= g_quark_from_string("processes");
1032 LTTV_STATS_CPU
= g_quark_from_string("cpu");
1033 LTTV_STATS_MODE_TYPES
= g_quark_from_string("mode_types");
1034 LTTV_STATS_MODES
= g_quark_from_string("modes");
1035 LTTV_STATS_SUBMODES
= g_quark_from_string("submodes");
1036 LTTV_STATS_EVENT_TYPES
= g_quark_from_string("event_types");
1037 LTTV_STATS_CPU_TIME
= g_quark_from_string("cpu time");
1038 LTTV_STATS_ELAPSED_TIME
= g_quark_from_string("elapsed time");
1039 LTTV_STATS_EVENTS
= g_quark_from_string("events");
1040 LTTV_STATS_EVENTS_COUNT
= g_quark_from_string("events count");
1041 LTTV_STATS_BEFORE_HOOKS
= g_quark_from_string("saved stats before hooks");
1042 LTTV_STATS_AFTER_HOOKS
= g_quark_from_string("saved stats after hooks");
1043 LTTV_STATS_USE_COUNT
= g_quark_from_string("stats_use_count");
1044 LTTV_STATS
= g_quark_from_string("statistics");
1045 LTTV_STATS_TRACEFILES
= g_quark_from_string("tracefiles statistics");
1046 LTTV_STATS_SUMMED
= g_quark_from_string("statistics summed");
1049 static void module_destroy()
1054 LTTV_MODULE("stats", "Compute processes statistics", \
1055 "Accumulate statistics for event types, processes and CPUs", \
1056 module_init
, module_destroy
, "state");
1058 /* Change the places where stats are called (create/read/write stats)
1060 Check for options in batchtest.c to reduce writing and see what tests are
1061 best candidates for performance analysis. Once OK, commit, move to main
1062 and run tests. Update the gui for statistics. */