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,
25 #include <lttv/module.h>
26 #include <lttv/stats.h>
27 #include <lttv/lttv.h>
28 #include <lttv/attribute.h>
29 #include <ltt/trace.h>
30 #include <ltt/event.h>
33 #define MAX_64_HEX_STRING_LEN 19
36 LTTV_STATS_PROCESS_UNKNOWN
,
39 LTTV_STATS_MODE_TYPES
,
43 LTTV_STATS_EVENT_TYPES
,
45 LTTV_STATS_CUMULATIVE_CPU_TIME
,
46 LTTV_STATS_ELAPSED_TIME
,
48 LTTV_STATS_EVENTS_COUNT
,
52 LTTV_STATS_BEFORE_HOOKS
,
53 LTTV_STATS_AFTER_HOOKS
;
55 static void find_event_tree(LttvCPUStats
*cpu_stats
, GQuark pid_time
,
56 guint cpu
, guint64 function
,
57 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
58 LttvAttribute
**event_types_tree
);
61 static void lttv_stats_init(LttvTracesetStats
*self
)
63 guint i
, j
, nb_trace
, nb_cpu
, nb_tracefile
;
69 LttvTracefileContext
**tfs
;
70 LttvTracefileStats
*tfcs
;
71 LttvCPUStats
*cpu_stats
;
75 LttvTraceset
*ts
= self
->parent
.parent
.ts
;
77 self
->stats
= lttv_attribute_find_subdir(
78 lttv_traceset_attribute(self
->parent
.parent
.ts
), LTTV_STATS
);
79 lttv_attribute_find(lttv_traceset_attribute(self
->parent
.parent
.ts
),
84 if(*(v
.v_uint
) == 1) {
85 g_assert(lttv_attribute_get_number(self
->stats
) == 0);
88 nb_trace
= lttv_traceset_number(ts
);
90 for(i
= 0 ; i
< nb_trace
; i
++) {
91 tc
= self
->parent
.parent
.traces
[i
];
92 tcs
= LTTV_TRACE_STATS(tc
);
94 tcs
->stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,
96 lttv_attribute_find(tcs
->parent
.parent
.t_a
, LTTV_STATS_USE_COUNT
,
100 if(*(v
.v_uint
) == 1) {
101 g_assert(lttv_attribute_get_number(tcs
->stats
) == 0);
104 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
105 tcs
->cpu_stats
= g_new(LttvCPUStats
, nb_cpu
);
106 for(j
= 0 ; j
< nb_cpu
; j
++) {
107 cpu_stats
= &tcs
->cpu_stats
[j
];
109 cpu_stats
->tcs
= tcs
;
110 find_event_tree(cpu_stats
, LTTV_STATS_PROCESS_UNKNOWN
,
113 LTTV_STATE_MODE_UNKNOWN
,
114 LTTV_STATE_SUBMODE_UNKNOWN
, &cpu_stats
->current_events_tree
,
115 &cpu_stats
->current_event_types_tree
);
117 nb_tracefile
= tc
->tracefiles
->len
;
118 for (j
= 0; j
< nb_tracefile
; j
++) {
119 tfs
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
120 tfcs
= LTTV_TRACEFILE_STATS(*tfs
);
121 tfcs
->cpu_stats
= &tcs
->cpu_stats
[tfcs
->parent
.cpu
];
127 static void lttv_stats_fini(LttvTracesetStats
*self
)
129 guint i
, j
, nb_trace
, nb_cpu
, nb_tracefile
;
133 LttvTraceContext
*tc
;
137 LttvTracefileContext
*tfc
;
139 LttvTracefileStats
*tfcs
;
141 LttvCPUStats
*cpu_stats
;
143 LttvAttributeValue v
;
145 lttv_attribute_find(self
->parent
.parent
.ts_a
, LTTV_STATS_USE_COUNT
,
149 if(*(v
.v_uint
) == 0) {
150 lttv_attribute_remove_by_name(self
->parent
.parent
.ts_a
, LTTV_STATS
);
154 ts
= self
->parent
.parent
.ts
;
155 nb_trace
= lttv_traceset_number(ts
);
157 for(i
= 0 ; i
< nb_trace
; i
++) {
158 tcs
= (LttvTraceStats
*)(tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]));
160 lttv_attribute_find(tcs
->parent
.parent
.t_a
, LTTV_STATS_USE_COUNT
,
165 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
, LTTV_STATS
);
168 nb_tracefile
= tc
->tracefiles
->len
;
169 for (j
= 0; j
< nb_tracefile
; j
++) {
170 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
171 tfcs
= LTTV_TRACEFILE_STATS(tfc
);
172 tfcs
->cpu_stats
= NULL
;
175 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
177 for(j
= 0 ; j
< nb_cpu
; j
++) {
178 cpu_stats
= &tcs
->cpu_stats
[j
];
179 cpu_stats
->current_events_tree
= NULL
;
180 cpu_stats
->current_event_types_tree
= NULL
;
182 g_free(tcs
->cpu_stats
);
187 void lttv_stats_reset(LttvTracesetStats
*self
)
189 lttv_stats_fini(self
);
190 lttv_stats_init(self
);
195 static void init(LttvTracesetStats
*self
, LttvTraceset
*ts
)
197 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
198 init((LttvTracesetContext
*)self
, ts
);
200 lttv_stats_init(self
);
204 static void fini(LttvTracesetStats
*self
)
206 lttv_stats_fini(self
);
208 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
209 fini((LttvTracesetContext
*)self
);
213 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
215 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE
, NULL
));
219 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
221 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE
, NULL
));
225 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
227 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE
, NULL
));
231 static void traceset_stats_instance_init (GTypeInstance
*instance
,
237 static void traceset_stats_finalize (LttvTracesetStats
*self
)
239 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
240 finalize(G_OBJECT(self
));
244 static void traceset_stats_class_init (LttvTracesetContextClass
*klass
)
246 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
248 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_stats_finalize
;
249 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
250 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
251 klass
->new_traceset_context
= new_traceset_context
;
252 klass
->new_trace_context
= new_trace_context
;
253 klass
->new_tracefile_context
= new_tracefile_context
;
257 GType
lttv_traceset_stats_get_type(void)
259 static GType type
= 0;
261 static const GTypeInfo info
= {
262 sizeof (LttvTracesetStatsClass
),
263 NULL
, /* base_init */
264 NULL
, /* base_finalize */
265 (GClassInitFunc
) traceset_stats_class_init
, /* class_init */
266 NULL
, /* class_finalize */
267 NULL
, /* class_data */
268 sizeof (LttvTracesetStats
),
270 (GInstanceInitFunc
) traceset_stats_instance_init
, /* instance_init */
271 NULL
/* Value handling */
274 type
= g_type_register_static (LTTV_TRACESET_STATE_TYPE
,
275 "LttvTracesetStatsType", &info
, 0);
281 static void trace_stats_instance_init (GTypeInstance
*instance
,
287 static void trace_stats_finalize (LttvTraceStats
*self
)
289 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE
))->
290 finalize(G_OBJECT(self
));
294 static void trace_stats_class_init (LttvTraceContextClass
*klass
)
296 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
298 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_stats_finalize
;
302 GType
lttv_trace_stats_get_type(void)
304 static GType type
= 0;
306 static const GTypeInfo info
= {
307 sizeof (LttvTraceStatsClass
),
308 NULL
, /* base_init */
309 NULL
, /* base_finalize */
310 (GClassInitFunc
) trace_stats_class_init
, /* class_init */
311 NULL
, /* class_finalize */
312 NULL
, /* class_data */
313 sizeof (LttvTraceStats
),
315 (GInstanceInitFunc
) trace_stats_instance_init
, /* instance_init */
316 NULL
/* Value handling */
319 type
= g_type_register_static (LTTV_TRACE_STATE_TYPE
,
320 "LttvTraceStatsType", &info
, 0);
326 static void tracefile_stats_instance_init (GTypeInstance
*instance
,
332 static void tracefile_stats_finalize (LttvTracefileStats
*self
)
334 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE
))->
335 finalize(G_OBJECT(self
));
339 static void tracefile_stats_class_init (LttvTracefileStatsClass
*klass
)
341 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
343 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_stats_finalize
;
347 GType
lttv_tracefile_stats_get_type(void)
349 static GType type
= 0;
351 static const GTypeInfo info
= {
352 sizeof (LttvTracefileStatsClass
),
353 NULL
, /* base_init */
354 NULL
, /* base_finalize */
355 (GClassInitFunc
) tracefile_stats_class_init
, /* class_init */
356 NULL
, /* class_finalize */
357 NULL
, /* class_data */
358 sizeof (LttvTracefileStats
),
360 (GInstanceInitFunc
) tracefile_stats_instance_init
, /* instance_init */
361 NULL
/* Value handling */
364 type
= g_type_register_static (LTTV_TRACEFILE_STATE_TYPE
,
365 "LttvTracefileStatsType", &info
, 0);
370 static void find_event_tree(LttvCPUStats
*cpu_stats
,
376 LttvAttribute
**events_tree
,
377 LttvAttribute
**event_types_tree
)
380 gchar fstring
[MAX_64_HEX_STRING_LEN
];
383 ret
= snprintf(fstring
, MAX_64_HEX_STRING_LEN
-1,
384 "0x%" PRIX64
, function
) > 0;
386 fstring
[MAX_64_HEX_STRING_LEN
-1] = '\0';
388 LttvTraceStats
*tcs
= cpu_stats
->tcs
;
389 a
= lttv_attribute_find_subdir(tcs
->stats
, LTTV_STATS_PROCESSES
);
390 a
= lttv_attribute_find_subdir(a
, pid_time
);
391 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_CPU
);
392 a
= lttv_attribute_find_subdir_unnamed(a
, cpu
);
393 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_FUNCTIONS
);
394 a
= lttv_attribute_find_subdir(a
, g_quark_from_string(fstring
));
395 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_MODE_TYPES
);
396 a
= lttv_attribute_find_subdir(a
, mode
);
397 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_SUBMODES
);
398 a
= lttv_attribute_find_subdir(a
, sub_mode
);
400 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_EVENT_TYPES
);
401 *event_types_tree
= a
;
404 static void update_event_tree(LttvCPUStats
*cpu_stats
)
406 LttvTraceStats
*tcs
= cpu_stats
->tcs
;
407 guint cpu
= cpu_stats
->cpu
;
408 LttvTraceState
*ts
= &tcs
->parent
;
409 LttvProcessState
*process
= ts
->running_process
[cpu
];
410 LttvExecutionState
*es
= process
->state
;
412 find_event_tree(cpu_stats
, process
->pid_time
,
414 process
->current_function
,
415 es
->t
, es
->n
, &(cpu_stats
->current_events_tree
),
416 &(cpu_stats
->current_event_types_tree
));
419 /* Update the trace event tree each cpu */
420 static void update_trace_event_tree(LttvTraceStats
*tcs
)
422 LttvCPUStats
*cpu_stats
;
423 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
426 /* For each cpu, update the event tree */
427 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
428 for(j
= 0; j
< nb_cpu
; j
++) {
429 cpu_stats
= &tcs
->cpu_stats
[j
];
430 update_event_tree(cpu_stats
);
434 static void mode_change(LttvTracefileStats
*tfcs
)
436 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
437 guint cpu
= tfcs
->parent
.cpu
;
438 LttvProcessState
*process
= ts
->running_process
[cpu
];
439 LttvAttributeValue cpu_time
;
443 if(process
->state
->s
== LTTV_STATE_RUN
&&
444 process
->state
->t
!= LTTV_STATE_MODE_UNKNOWN
)
445 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
446 process
->state
->change
);
448 delta
= ltt_time_zero
;
450 lttv_attribute_find(tfcs
->cpu_stats
->current_events_tree
, LTTV_STATS_CPU_TIME
,
451 LTTV_TIME
, &cpu_time
);
452 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
454 process
->state
->cum_cpu_time
= ltt_time_add(process
->state
->cum_cpu_time
,
458 /* Note : every mode_end must come with a cumulative cpu time update in the
460 static void mode_end(LttvTracefileStats
*tfcs
)
462 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
463 guint cpu
= tfcs
->parent
.cpu
;
464 LttvProcessState
*process
= ts
->running_process
[cpu
];
465 LttvAttributeValue elapsed_time
, cpu_time
, cum_cpu_time
;
469 /* FIXME put there in case of a missing update after a state modification */
470 //void *lasttree = tfcs->cpu_stats->current_events_tree;
471 //update_event_tree(tfcs);
472 //g_assert (lasttree == tfcs->cpu_stats->current_events_tree);
473 lttv_attribute_find(tfcs
->cpu_stats
->current_events_tree
, LTTV_STATS_ELAPSED_TIME
,
474 LTTV_TIME
, &elapsed_time
);
476 if(process
->state
->t
!= LTTV_STATE_MODE_UNKNOWN
) {
477 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
478 process
->state
->entry
);
480 delta
= ltt_time_zero
;
482 *(elapsed_time
.v_time
) = ltt_time_add(*(elapsed_time
.v_time
), delta
);
484 lttv_attribute_find(tfcs
->cpu_stats
->current_events_tree
, LTTV_STATS_CPU_TIME
,
485 LTTV_TIME
, &cpu_time
);
487 /* if it is a running mode, we must count its cpu time */
488 if(process
->state
->s
== LTTV_STATE_RUN
&&
489 process
->state
->t
!= LTTV_STATE_MODE_UNKNOWN
)
490 delta
= ltt_time_sub(tfcs
->parent
.parent
.timestamp
,
491 process
->state
->change
);
493 delta
= ltt_time_zero
;
495 *(cpu_time
.v_time
) = ltt_time_add(*(cpu_time
.v_time
), delta
);
496 process
->state
->cum_cpu_time
= ltt_time_add(process
->state
->cum_cpu_time
,
499 lttv_attribute_find(tfcs
->cpu_stats
->current_events_tree
, LTTV_STATS_CUMULATIVE_CPU_TIME
,
500 LTTV_TIME
, &cum_cpu_time
);
501 *(cum_cpu_time
.v_time
) = ltt_time_add(*(cum_cpu_time
.v_time
),
502 process
->state
->cum_cpu_time
);
506 static void after_mode_end(LttvTracefileStats
*tfcs
)
508 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
509 guint cpu
= tfcs
->parent
.cpu
;
510 LttvProcessState
*process
= ts
->running_process
[cpu
];
512 LttTime nested_delta
;
514 nested_delta
= process
->state
->cum_cpu_time
;
515 process
->state
->cum_cpu_time
= ltt_time_zero
; /* For after traceset hook */
517 update_event_tree(tfcs
->cpu_stats
);
519 process
->state
->cum_cpu_time
= ltt_time_add(process
->state
->cum_cpu_time
,
523 static gboolean
before_syscall_entry(void *hook_data
, void *call_data
)
525 mode_change((LttvTracefileStats
*)call_data
);
530 static gboolean
after_syscall_entry(void *hook_data
, void *call_data
)
532 update_event_tree(((LttvTracefileStats
*)call_data
)->cpu_stats
);
537 static gboolean
before_syscall_exit(void *hook_data
, void *call_data
)
539 mode_end((LttvTracefileStats
*)call_data
);
544 static gboolean
after_syscall_exit(void *hook_data
, void *call_data
)
546 after_mode_end((LttvTracefileStats
*)call_data
);
551 static gboolean
before_trap_entry(void *hook_data
, void *call_data
)
553 mode_change((LttvTracefileStats
*)call_data
);
558 static gboolean
after_trap_entry(void *hook_data
, void *call_data
)
560 update_event_tree(((LttvTracefileStats
*)call_data
)->cpu_stats
);
565 static gboolean
before_trap_exit(void *hook_data
, void *call_data
)
567 mode_end((LttvTracefileStats
*)call_data
);
572 static gboolean
after_trap_exit(void *hook_data
, void *call_data
)
574 after_mode_end((LttvTracefileStats
*)call_data
);
579 static gboolean
before_irq_entry(void *hook_data
, void *call_data
)
581 mode_change((LttvTracefileStats
*)call_data
);
585 static gboolean
after_irq_entry(void *hook_data
, void *call_data
)
587 update_event_tree(((LttvTracefileStats
*)call_data
)->cpu_stats
);
592 static gboolean
before_irq_exit(void *hook_data
, void *call_data
)
594 mode_end((LttvTracefileStats
*)call_data
);
599 static gboolean
after_irq_exit(void *hook_data
, void *call_data
)
601 after_mode_end((LttvTracefileStats
*)call_data
);
606 static gboolean
before_soft_irq_entry(void *hook_data
, void *call_data
)
608 mode_change((LttvTracefileStats
*)call_data
);
612 static gboolean
after_soft_irq_entry(void *hook_data
, void *call_data
)
614 update_event_tree(((LttvTracefileStats
*)call_data
)->cpu_stats
);
618 static gboolean
before_soft_irq_exit(void *hook_data
, void *call_data
)
620 mode_end((LttvTracefileStats
*)call_data
);
625 static gboolean
after_soft_irq_exit(void *hook_data
, void *call_data
)
627 after_mode_end((LttvTracefileStats
*)call_data
);
631 static gboolean
before_function_entry(void *hook_data
, void *call_data
)
633 mode_change((LttvTracefileStats
*)call_data
);
637 static gboolean
after_function_entry(void *hook_data
, void *call_data
)
639 update_event_tree(((LttvTracefileStats
*)call_data
)->cpu_stats
);
643 static gboolean
before_function_exit(void *hook_data
, void *call_data
)
645 mode_end((LttvTracefileStats
*)call_data
);
649 static gboolean
after_function_exit(void *hook_data
, void *call_data
)
651 after_mode_end((LttvTracefileStats
*)call_data
);
656 static gboolean
before_schedchange(void *hook_data
, void *call_data
)
658 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
660 /* compute the time for the process to schedule out */
666 static gboolean
after_schedchange(void *hook_data
, void *call_data
)
668 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
670 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
672 LttvProcessState
*process
;
674 /* get the information for the process scheduled in */
675 guint cpu
= tfcs
->parent
.cpu
;
676 process
= ts
->running_process
[cpu
];
678 find_event_tree(tfcs
->cpu_stats
, process
->pid_time
,
680 process
->current_function
,
681 process
->state
->t
, process
->state
->n
,
682 &(tfcs
->cpu_stats
->current_events_tree
),
683 &(tfcs
->cpu_stats
->current_event_types_tree
));
685 /* compute the time waiting for the process to schedule in */
691 static gboolean
process_fork(void *hook_data
, void *call_data
)
696 static gboolean
process_exit(void *hook_data
, void *call_data
)
698 update_event_tree(((LttvTracefileStats
*)call_data
)->cpu_stats
);
702 static gboolean
before_enum_process_state(void *hook_data
, void *call_data
)
705 /* Broken : adds up time in the current process doing the dump */
706 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
708 after_mode_end(tfcs
);
714 static gboolean
after_enum_process_state(void *hook_data
, void *call_data
)
716 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
717 LttvTraceStats
*tcs
= (LttvTraceStats
*)tfc
->t_context
;
718 update_trace_event_tree(tcs
);
722 static gboolean
after_statedump_end(void *hook_data
, void *call_data
)
724 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
725 LttvTraceStats
*tcs
= (LttvTraceStats
*)tfc
->t_context
;
726 update_trace_event_tree(tcs
);
730 static gboolean
process_free(void *hook_data
, void *call_data
)
735 static gboolean
every_event(void *hook_data
, void *call_data
)
737 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
739 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
741 LttvAttributeValue v
;
743 struct marker_info
*info
;
745 /* The current branch corresponds to the tracefile/process/interrupt state.
746 Statistics are added within it, to count the number of events of this
747 type occuring in this context. A quark has been pre-allocated for each
748 event type and is used as name. */
750 info
= marker_get_info_from_id(tfcs
->parent
.parent
.tf
->mdata
, e
->event_id
);
752 lttv_attribute_find(tfcs
->cpu_stats
->current_event_types_tree
,
753 info
->name
, LTTV_UINT
, &v
);
758 struct cleanup_state_struct
{
760 LttTime current_time
;
763 //static void lttv_stats_cleanup_process_state(LttvTraceState *ts,
764 // LttvProcessState *process, LttTime current_time)
765 static void lttv_stats_cleanup_process_state(gpointer key
, gpointer value
,
768 struct cleanup_state_struct
*cleanup_closure
=
769 (struct cleanup_state_struct
*)user_data
;
770 LttvTraceState
*ts
= cleanup_closure
->ts
;
771 LttvProcessState
*process
= (LttvProcessState
*)value
;
772 LttTime current_time
= cleanup_closure
->current_time
;
773 LttvTracefileStats
**tfs
= (LttvTracefileStats
**)
774 &g_array_index(ts
->parent
.tracefiles
, LttvTracefileContext
*,
776 int cleanup_empty
= 0;
777 LttTime nested_delta
= ltt_time_zero
;
779 /* FIXME : ok, this is a hack. The time is infinite here :( */
780 //LttTime save_time = (*tfs)->parent.parent.timestamp;
781 //LttTime start, end;
782 //ltt_trace_time_span_get(ts->parent.t, &start, &end);
783 //(*tfs)->parent.parent.timestamp = end;
786 if(ltt_time_compare(process
->state
->cum_cpu_time
, ltt_time_zero
) != 0) {
787 find_event_tree((*tfs
)->cpu_stats
, process
->pid_time
,
789 process
->current_function
,
790 process
->state
->t
, process
->state
->n
,
791 &((*tfs
)->cpu_stats
->current_events_tree
),
792 &((*tfs
)->cpu_stats
->current_event_types_tree
));
793 /* Call mode_end only if not at end of trace */
794 if(ltt_time_compare(current_time
, ltt_time_infinite
) != 0)
796 nested_delta
= process
->state
->cum_cpu_time
;
798 cleanup_empty
= lttv_state_pop_state_cleanup(process
,
799 (LttvTracefileState
*)*tfs
);
800 process
->state
->cum_cpu_time
= ltt_time_add(process
->state
->cum_cpu_time
,
803 } while(cleanup_empty
!= 1);
805 //(*tfs)->parent.parent.timestamp = save_time;
808 /* For each cpu, for each of their stacked states,
809 * perform sum of needed values. */
810 static void lttv_stats_cleanup_state(LttvTraceStats
*tcs
, LttTime current_time
)
812 LttvTraceState
*ts
= (LttvTraceState
*)tcs
;
813 struct cleanup_state_struct cleanup_closure
;
817 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
819 for(i
=0; i
<nb_cpus
; i
++) {
820 lttv_stats_cleanup_process_state(ts
, ts
->running_process
[i
], current_time
);
823 cleanup_closure
.ts
= ts
;
824 cleanup_closure
.current_time
= current_time
;
825 g_hash_table_foreach(ts
->processes
, lttv_stats_cleanup_process_state
,
829 void lttv_stats_sum_trace(LttvTraceStats
*self
, LttvAttribute
*ts_stats
,
830 LttTime current_time
)
832 LttvAttribute
*sum_container
= self
->stats
;
834 LttvAttributeValue value
;
836 LttvAttributeName name
;
844 int i
, j
, k
, l
, m
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
,
845 nb_event_type
, nf
, nb_functions
;
847 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
848 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
849 *submode_tree
, *event_types_tree
, *mode_events_tree
,
852 *function_mode_types_tree
,
856 main_tree
= sum_container
;
858 lttv_attribute_find(sum_container
,
861 trace_is_summed
= *(value
.v_uint
);
864 /* First cleanup the state : sum all stalled information (never ending
867 lttv_stats_cleanup_state(self
, current_time
);
869 processes_tree
= lttv_attribute_find_subdir(main_tree
,
870 LTTV_STATS_PROCESSES
);
871 nb_process
= lttv_attribute_get_number(processes_tree
);
873 for(i
= 0 ; i
< nb_process
; i
++) {
874 lttv_attribute_get(processes_tree
, i
, &name
, &value
, &is_named
);
875 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
877 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
878 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
880 for(j
= 0 ; j
< nb_cpu
; j
++) {
881 lttv_attribute_get(cpus_tree
, j
, &name
, &value
, &is_named
);
882 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
884 trace_cpu_tree
= lttv_attribute_find_subdir(main_tree
,
886 trace_cpu_tree
= lttv_attribute_find_subdir_unnamed(trace_cpu_tree
, name
);
887 cpu_functions_tree
= lttv_attribute_find_subdir(cpu_tree
,
888 LTTV_STATS_FUNCTIONS
);
889 nb_functions
= lttv_attribute_get_number(cpu_functions_tree
);
891 for(nf
=0; nf
< nb_functions
; nf
++) {
892 lttv_attribute_get(cpu_functions_tree
, nf
, &name
, &value
,
894 function_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
895 function_mode_types_tree
= lttv_attribute_find_subdir(function_tree
,
896 LTTV_STATS_MODE_TYPES
);
897 nb_mode_type
= lttv_attribute_get_number(function_mode_types_tree
);
898 for(k
= 0 ; k
< nb_mode_type
; k
++) {
899 lttv_attribute_get(function_mode_types_tree
, k
, &name
,
901 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
903 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,
904 LTTV_STATS_SUBMODES
);
905 mode_events_tree
= lttv_attribute_find_subdir(mode_tree
,
907 mode_types_tree
= lttv_attribute_find_subdir(mode_tree
,
908 LTTV_STATS_MODE_TYPES
);
910 nb_submode
= lttv_attribute_get_number(submodes_tree
);
912 for(l
= 0 ; l
< nb_submode
; l
++) {
913 lttv_attribute_get(submodes_tree
, l
, &name
, &value
,
915 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
917 event_types_tree
= lttv_attribute_find_subdir(submode_tree
,
918 LTTV_STATS_EVENT_TYPES
);
919 nb_event_type
= lttv_attribute_get_number(event_types_tree
);
922 for(m
= 0 ; m
< nb_event_type
; m
++) {
923 lttv_attribute_get(event_types_tree
, m
, &name
,
925 sum
+= *(value
.v_uint
);
927 lttv_attribute_find(submode_tree
, LTTV_STATS_EVENTS_COUNT
,
929 *(value
.v_uint
) = sum
;
931 lttv_attribute_get(submodes_tree
, l
, &name
, &value
,
933 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
934 if(!trace_is_summed
) {
935 lttv_attribute_recursive_add(mode_events_tree
, event_types_tree
);
936 lttv_attribute_recursive_add(mode_types_tree
, submode_tree
);
939 if(!trace_is_summed
) {
940 lttv_attribute_recursive_add(function_tree
, mode_types_tree
);
943 if(!trace_is_summed
) {
944 lttv_attribute_recursive_add(cpu_tree
, function_tree
);
945 lttv_attribute_recursive_add(process_tree
, function_tree
);
946 lttv_attribute_recursive_add(trace_cpu_tree
, function_tree
);
947 lttv_attribute_recursive_add(main_tree
, function_tree
);
949 lttv_attribute_recursive_add(ts_stats
, function_tree
);
956 gboolean
lttv_stats_sum_traceset_hook(void *hook_data
, void *call_data
)
958 struct sum_traceset_closure
*closure
=
959 (struct sum_traceset_closure
*)call_data
;
960 lttv_stats_sum_traceset(closure
->tss
, closure
->current_time
);
964 void lttv_stats_sum_traceset(LttvTracesetStats
*self
, LttTime current_time
)
966 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
967 LttvAttribute
*sum_container
= self
->stats
;
973 LttvAttributeValue value
;
975 lttv_attribute_find(sum_container
, LTTV_STATS_SUMMED
,
977 if(*(value
.v_uint
) != 0) return;
980 nb_trace
= lttv_traceset_number(traceset
);
982 for(i
= 0 ; i
< nb_trace
; i
++) {
983 tcs
= (LttvTraceStats
*)(self
->parent
.parent
.traces
[i
]);
984 lttv_stats_sum_trace(tcs
, self
->stats
, current_time
);
985 // lttv_attribute_recursive_add(sum_container, tcs->stats);
990 // Hook wrapper. call_data is a traceset context.
991 gboolean
lttv_stats_hook_add_event_hooks(void *hook_data
, void *call_data
)
993 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
995 lttv_stats_add_event_hooks(tss
);
1000 void lttv_stats_add_event_hooks(LttvTracesetStats
*self
)
1002 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
1004 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1008 LttvTracefileStats
*tfs
;
1010 GArray
*hooks
, *before_hooks
, *after_hooks
;
1014 LttvAttributeValue val
;
1016 nb_trace
= lttv_traceset_number(traceset
);
1017 for(i
= 0 ; i
< nb_trace
; i
++) {
1018 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
1020 /* Find the eventtype id for the following events and register the
1021 associated by id hooks. */
1023 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 12);
1025 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1027 LTT_EVENT_SYSCALL_ENTRY
,
1028 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1029 before_syscall_entry
, NULL
,
1032 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1034 LTT_EVENT_SYSCALL_EXIT
,
1036 before_syscall_exit
, NULL
,
1039 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1041 LTT_EVENT_TRAP_ENTRY
,
1042 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1043 before_trap_entry
, NULL
,
1046 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1048 LTT_EVENT_TRAP_EXIT
,
1050 before_trap_exit
, NULL
,
1053 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1055 LTT_EVENT_IRQ_ENTRY
,
1056 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1057 before_irq_entry
, NULL
,
1060 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1064 before_irq_exit
, NULL
,
1067 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1069 LTT_EVENT_SOFT_IRQ_ENTRY
,
1070 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
1071 before_soft_irq_entry
, NULL
,
1074 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1076 LTT_EVENT_SOFT_IRQ_EXIT
,
1078 before_soft_irq_exit
, NULL
,
1081 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1083 LTT_EVENT_SCHED_SCHEDULE
,
1084 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
),
1085 before_schedchange
, NULL
,
1088 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1089 LTT_CHANNEL_USERSPACE
,
1090 LTT_EVENT_FUNCTION_ENTRY
,
1091 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
1092 before_function_entry
, NULL
,
1095 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1096 LTT_CHANNEL_USERSPACE
,
1097 LTT_EVENT_FUNCTION_EXIT
,
1098 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
1099 before_function_exit
, NULL
,
1102 /* statedump-related hooks */
1103 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1104 LTT_CHANNEL_TASK_STATE
,
1105 LTT_EVENT_PROCESS_STATE
,
1106 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
),
1107 before_enum_process_state
, NULL
,
1110 before_hooks
= hooks
;
1112 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 16);
1114 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1116 LTT_EVENT_SYSCALL_ENTRY
,
1117 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1118 after_syscall_entry
, NULL
,
1121 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1123 LTT_EVENT_SYSCALL_EXIT
,
1125 after_syscall_exit
, NULL
,
1128 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1130 LTT_EVENT_TRAP_ENTRY
,
1131 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1132 after_trap_entry
, NULL
,
1135 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1137 LTT_EVENT_TRAP_EXIT
,
1139 after_trap_exit
, NULL
,
1142 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1144 LTT_EVENT_IRQ_ENTRY
,
1145 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1146 after_irq_entry
, NULL
,
1149 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1153 after_irq_exit
, NULL
,
1156 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1158 LTT_EVENT_SOFT_IRQ_ENTRY
,
1159 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
1160 after_soft_irq_entry
, NULL
,
1163 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1165 LTT_EVENT_SOFT_IRQ_EXIT
,
1167 after_soft_irq_exit
, NULL
,
1170 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1172 LTT_EVENT_SCHED_SCHEDULE
,
1173 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
),
1174 after_schedchange
, NULL
,
1177 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1179 LTT_EVENT_PROCESS_FORK
,
1180 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
),
1184 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1186 LTT_EVENT_PROCESS_EXIT
,
1187 FIELD_ARRAY(LTT_FIELD_PID
),
1191 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1193 LTT_EVENT_PROCESS_FREE
,
1194 FIELD_ARRAY(LTT_FIELD_PID
),
1198 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1199 LTT_CHANNEL_USERSPACE
,
1200 LTT_EVENT_FUNCTION_ENTRY
,
1201 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
1202 after_function_entry
, NULL
,
1205 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1206 LTT_CHANNEL_USERSPACE
,
1207 LTT_EVENT_FUNCTION_EXIT
,
1208 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
1209 after_function_exit
, NULL
,
1212 /* statedump-related hooks */
1213 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1214 LTT_CHANNEL_TASK_STATE
,
1215 LTT_EVENT_PROCESS_STATE
,
1216 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
),
1217 after_enum_process_state
, NULL
,
1220 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1221 LTT_CHANNEL_GLOBAL_STATE
,
1222 LTT_EVENT_STATEDUMP_END
,
1224 after_statedump_end
, NULL
,
1227 after_hooks
= hooks
;
1229 /* Add these hooks to each event_by_id hooks list */
1231 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
1233 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1234 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
1235 LttvTracefileContext
*, j
));
1236 lttv_hooks_add(tfs
->parent
.parent
.event
, every_event
, NULL
,
1239 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1240 th
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1241 if (th
->mdata
== tfs
->parent
.parent
.tf
->mdata
)
1243 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, th
->id
),
1246 LTTV_PRIO_STATS_BEFORE_STATE
);
1248 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1249 th
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1250 if (th
->mdata
== tfs
->parent
.parent
.tf
->mdata
)
1252 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, th
->id
),
1255 LTTV_PRIO_STATS_AFTER_STATE
);
1258 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
1259 LTTV_POINTER
, &val
);
1260 *(val
.v_pointer
) = before_hooks
;
1261 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
1262 LTTV_POINTER
, &val
);
1263 *(val
.v_pointer
) = after_hooks
;
1267 // Hook wrapper. call_data is a traceset context.
1268 gboolean
lttv_stats_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1270 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
1272 lttv_stats_remove_event_hooks(tss
);
1277 void lttv_stats_remove_event_hooks(LttvTracesetStats
*self
)
1279 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
1281 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1285 LttvTracefileStats
*tfs
;
1287 GArray
*before_hooks
, *after_hooks
;
1291 LttvAttributeValue val
;
1293 nb_trace
= lttv_traceset_number(traceset
);
1294 for(i
= 0 ; i
< nb_trace
; i
++) {
1295 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
1296 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
1297 LTTV_POINTER
, &val
);
1298 before_hooks
= *(val
.v_pointer
);
1299 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
1300 LTTV_POINTER
, &val
);
1301 after_hooks
= *(val
.v_pointer
);
1303 /* Remove these hooks from each event_by_id hooks list */
1305 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
1307 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1308 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
1309 LttvTracefileContext
*, j
));
1310 lttv_hooks_remove_data(tfs
->parent
.parent
.event
, every_event
,
1313 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1314 th
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1315 if (th
->mdata
== tfs
->parent
.parent
.tf
->mdata
)
1316 lttv_hooks_remove_data(
1317 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, th
->id
),
1321 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1322 th
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1323 if (th
->mdata
== tfs
->parent
.parent
.tf
->mdata
)
1324 lttv_hooks_remove_data(
1325 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, th
->id
),
1331 g_debug("lttv_stats_remove_event_hooks()");
1332 lttv_trace_hook_remove_all(&before_hooks
);
1333 lttv_trace_hook_remove_all(&after_hooks
);
1334 g_array_free(before_hooks
, TRUE
);
1335 g_array_free(after_hooks
, TRUE
);
1340 static void module_init()
1342 LTTV_STATS_PROCESS_UNKNOWN
= g_quark_from_string("unknown process");
1343 LTTV_STATS_PROCESSES
= g_quark_from_string("processes");
1344 LTTV_STATS_CPU
= g_quark_from_string("cpu");
1345 LTTV_STATS_MODE_TYPES
= g_quark_from_string("mode_types");
1346 LTTV_STATS_MODES
= g_quark_from_string("modes");
1347 LTTV_STATS_SUBMODES
= g_quark_from_string("submodes");
1348 LTTV_STATS_FUNCTIONS
= g_quark_from_string("functions");
1349 LTTV_STATS_EVENT_TYPES
= g_quark_from_string("event_types");
1350 LTTV_STATS_CPU_TIME
= g_quark_from_string("cpu time");
1351 LTTV_STATS_CUMULATIVE_CPU_TIME
= g_quark_from_string("cumulative cpu time (includes nested routines and modes)");
1352 LTTV_STATS_ELAPSED_TIME
= g_quark_from_string("elapsed time (includes per process waiting time)");
1353 LTTV_STATS_EVENTS
= g_quark_from_string("events");
1354 LTTV_STATS_EVENTS_COUNT
= g_quark_from_string("events count");
1355 LTTV_STATS_BEFORE_HOOKS
= g_quark_from_string("saved stats before hooks");
1356 LTTV_STATS_AFTER_HOOKS
= g_quark_from_string("saved stats after hooks");
1357 LTTV_STATS_USE_COUNT
= g_quark_from_string("stats_use_count");
1358 LTTV_STATS
= g_quark_from_string("statistics");
1359 LTTV_STATS_SUMMED
= g_quark_from_string("statistics summed");
1362 static void module_destroy()
1367 LTTV_MODULE("stats", "Compute processes statistics", \
1368 "Accumulate statistics for event types, processes and CPUs", \
1369 module_init
, module_destroy
, "state");
1371 /* Change the places where stats are called (create/read/write stats)
1373 Check for options in batchtest.c to reduce writing and see what tests are
1374 best candidates for performance analysis. Once OK, commit, move to main
1375 and run tests. Update the gui for statistics. */