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
,
51 LTTV_STATS_TRACEFILES
,
53 LTTV_STATS_BEFORE_HOOKS
,
54 LTTV_STATS_AFTER_HOOKS
;
56 static void find_event_tree(LttvTracefileStats
*tfcs
, GQuark pid_time
,
57 guint cpu
, guint64 function
,
58 GQuark mode
, GQuark sub_mode
, LttvAttribute
**events_tree
,
59 LttvAttribute
**event_types_tree
);
62 static void lttv_stats_init(LttvTracesetStats
*self
)
64 guint i
, j
, nb_trace
, nb_tracefile
;
70 LttvTracefileContext
**tfs
;
71 LttvTracefileStats
*tfcs
;
75 LttvAttribute
*tracefiles_stats
;
77 LttvTraceset
*ts
= self
->parent
.parent
.ts
;
79 self
->stats
= lttv_attribute_find_subdir(
80 lttv_traceset_attribute(self
->parent
.parent
.ts
), LTTV_STATS
);
81 lttv_attribute_find(lttv_traceset_attribute(self
->parent
.parent
.ts
),
86 if(*(v
.v_uint
) == 1) {
87 g_assert(lttv_attribute_get_number(self
->stats
) == 0);
90 nb_trace
= lttv_traceset_number(ts
);
92 for(i
= 0 ; i
< nb_trace
; i
++) {
93 tc
= self
->parent
.parent
.traces
[i
];
94 tcs
= LTTV_TRACE_STATS(tc
);
96 tcs
->stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,
98 tracefiles_stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,
99 LTTV_STATS_TRACEFILES
);
100 lttv_attribute_find(tcs
->parent
.parent
.t_a
, LTTV_STATS_USE_COUNT
,
104 if(*(v
.v_uint
) == 1) {
105 g_assert(lttv_attribute_get_number(tcs
->stats
) == 0);
108 nb_tracefile
= tc
->tracefiles
->len
;
110 for(j
= 0 ; j
< nb_tracefile
; j
++) {
111 tfs
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
112 tfcs
= LTTV_TRACEFILE_STATS(*tfs
);
113 tfcs
->stats
= lttv_attribute_find_subdir(tracefiles_stats
,
114 ltt_tracefile_long_name(tfcs
->parent
.parent
.tf
));
115 guint cpu
= tfcs
->parent
.cpu
;
116 find_event_tree(tfcs
, LTTV_STATS_PROCESS_UNKNOWN
,
119 LTTV_STATE_MODE_UNKNOWN
,
120 LTTV_STATE_SUBMODE_UNKNOWN
, &tfcs
->current_events_tree
,
121 &tfcs
->current_event_types_tree
);
127 static void lttv_stats_fini(LttvTracesetStats
*self
)
129 guint i
, j
, nb_trace
, nb_tracefile
;
133 LttvTraceContext
*tc
;
137 LttvTracefileContext
*tfc
;
139 LttvTracefileStats
*tfcs
;
141 LttvAttributeValue v
;
143 LttvAttribute
*tracefiles_stats
;
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
,
164 if(*(v
.v_uint
) == 0) {
165 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
,LTTV_STATS
);
166 tracefiles_stats
= lttv_attribute_find_subdir(tcs
->parent
.parent
.t_a
,
167 LTTV_STATS_TRACEFILES
);
168 lttv_attribute_remove_by_name(tcs
->parent
.parent
.t_a
,
169 LTTV_STATS_TRACEFILES
);
173 nb_tracefile
= tc
->tracefiles
->len
;
175 for(j
= 0 ; j
< nb_tracefile
; j
++) {
176 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
177 tfcs
= (LttvTracefileStats
*)tfc
;
179 tfcs
->current_events_tree
= NULL
;
180 tfcs
->current_event_types_tree
= NULL
;
186 void lttv_stats_reset(LttvTracesetStats
*self
)
188 lttv_stats_fini(self
);
189 lttv_stats_init(self
);
194 static void init(LttvTracesetStats
*self
, LttvTraceset
*ts
)
196 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
197 init((LttvTracesetContext
*)self
, ts
);
199 lttv_stats_init(self
);
203 static void fini(LttvTracesetStats
*self
)
205 lttv_stats_fini(self
);
207 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
208 fini((LttvTracesetContext
*)self
);
212 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
214 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE
, NULL
));
218 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
220 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE
, NULL
));
224 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
226 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE
, NULL
));
230 static void traceset_stats_instance_init (GTypeInstance
*instance
,
236 static void traceset_stats_finalize (LttvTracesetStats
*self
)
238 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE
))->
239 finalize(G_OBJECT(self
));
243 static void traceset_stats_class_init (LttvTracesetContextClass
*klass
)
245 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
247 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_stats_finalize
;
248 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
249 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
250 klass
->new_traceset_context
= new_traceset_context
;
251 klass
->new_trace_context
= new_trace_context
;
252 klass
->new_tracefile_context
= new_tracefile_context
;
256 GType
lttv_traceset_stats_get_type(void)
258 static GType type
= 0;
260 static const GTypeInfo info
= {
261 sizeof (LttvTracesetStatsClass
),
262 NULL
, /* base_init */
263 NULL
, /* base_finalize */
264 (GClassInitFunc
) traceset_stats_class_init
, /* class_init */
265 NULL
, /* class_finalize */
266 NULL
, /* class_data */
267 sizeof (LttvTracesetStats
),
269 (GInstanceInitFunc
) traceset_stats_instance_init
, /* instance_init */
270 NULL
/* Value handling */
273 type
= g_type_register_static (LTTV_TRACESET_STATE_TYPE
,
274 "LttvTracesetStatsType", &info
, 0);
280 static void trace_stats_instance_init (GTypeInstance
*instance
,
286 static void trace_stats_finalize (LttvTraceStats
*self
)
288 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE
))->
289 finalize(G_OBJECT(self
));
293 static void trace_stats_class_init (LttvTraceContextClass
*klass
)
295 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
297 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_stats_finalize
;
301 GType
lttv_trace_stats_get_type(void)
303 static GType type
= 0;
305 static const GTypeInfo info
= {
306 sizeof (LttvTraceStatsClass
),
307 NULL
, /* base_init */
308 NULL
, /* base_finalize */
309 (GClassInitFunc
) trace_stats_class_init
, /* class_init */
310 NULL
, /* class_finalize */
311 NULL
, /* class_data */
312 sizeof (LttvTraceStats
),
314 (GInstanceInitFunc
) trace_stats_instance_init
, /* instance_init */
315 NULL
/* Value handling */
318 type
= g_type_register_static (LTTV_TRACE_STATE_TYPE
,
319 "LttvTraceStatsType", &info
, 0);
325 static void tracefile_stats_instance_init (GTypeInstance
*instance
,
331 static void tracefile_stats_finalize (LttvTracefileStats
*self
)
333 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE
))->
334 finalize(G_OBJECT(self
));
338 static void tracefile_stats_class_init (LttvTracefileStatsClass
*klass
)
340 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
342 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_stats_finalize
;
346 GType
lttv_tracefile_stats_get_type(void)
348 static GType type
= 0;
350 static const GTypeInfo info
= {
351 sizeof (LttvTracefileStatsClass
),
352 NULL
, /* base_init */
353 NULL
, /* base_finalize */
354 (GClassInitFunc
) tracefile_stats_class_init
, /* class_init */
355 NULL
, /* class_finalize */
356 NULL
, /* class_data */
357 sizeof (LttvTracefileStats
),
359 (GInstanceInitFunc
) tracefile_stats_instance_init
, /* instance_init */
360 NULL
/* Value handling */
363 type
= g_type_register_static (LTTV_TRACEFILE_STATE_TYPE
,
364 "LttvTracefileStatsType", &info
, 0);
369 static void find_event_tree(LttvTracefileStats
*tfcs
,
375 LttvAttribute
**events_tree
,
376 LttvAttribute
**event_types_tree
)
379 gchar fstring
[MAX_64_HEX_STRING_LEN
];
382 ret
= snprintf(fstring
, MAX_64_HEX_STRING_LEN
-1,
383 "0x%" PRIX64
, function
) > 0;
385 fstring
[MAX_64_HEX_STRING_LEN
-1] = '\0';
387 LttvTraceStats
*tcs
= (LttvTraceStats
*)tfcs
->parent
.parent
.t_context
;
388 a
= lttv_attribute_find_subdir(tcs
->stats
, LTTV_STATS_PROCESSES
);
389 a
= lttv_attribute_find_subdir(a
, pid_time
);
390 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_CPU
);
391 a
= lttv_attribute_find_subdir_unnamed(a
, cpu
);
392 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_FUNCTIONS
);
393 a
= lttv_attribute_find_subdir(a
, g_quark_from_string(fstring
));
394 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_MODE_TYPES
);
395 a
= lttv_attribute_find_subdir(a
, mode
);
396 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_SUBMODES
);
397 a
= lttv_attribute_find_subdir(a
, sub_mode
);
399 a
= lttv_attribute_find_subdir(a
, LTTV_STATS_EVENT_TYPES
);
400 *event_types_tree
= a
;
403 static void update_event_tree(LttvTracefileStats
*tfcs
)
405 guint cpu
= tfcs
->parent
.cpu
;
406 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
407 LttvProcessState
*process
= ts
->running_process
[cpu
];
408 LttvExecutionState
*es
= process
->state
;
410 find_event_tree(tfcs
, process
->pid_time
,
412 process
->current_function
,
413 es
->t
, es
->n
, &(tfcs
->current_events_tree
),
414 &(tfcs
->current_event_types_tree
));
418 /* Update the trace event tree for the specified cpu */
419 static void update_trace_event_tree(LttvTraceStats
*tcs
)
421 LttvTracefileStats
*tfcs
;
422 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
423 guint j
, nb_tracefile
;
425 /* For each tracefile, update the event tree */
426 nb_tracefile
= tc
->tracefiles
->len
;
427 for(j
= 0; j
< nb_tracefile
; j
++) {
428 tfcs
= LTTV_TRACEFILE_STATS(g_array_index(tc
->tracefiles
,
429 LttvTracefileContext
*, j
));
430 update_event_tree(tfcs
);
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
->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->current_events_tree;
471 //update_event_tree(tfcs);
472 //g_assert (lasttree == tfcs->current_events_tree);
473 lttv_attribute_find(tfcs
->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
->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
->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
);
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
);
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
);
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
);
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
);
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
);
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 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
662 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
664 guint pid_in
, pid_out
;
668 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
669 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
670 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
672 /* compute the time for the process to schedule out */
678 static gboolean
after_schedchange(void *hook_data
, void *call_data
)
680 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
682 LttvTraceState
*ts
= (LttvTraceState
*)tfcs
->parent
.parent
.t_context
;
684 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
686 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
688 guint pid_in
, pid_out
;
692 LttvProcessState
*process
;
694 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
695 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
696 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
698 /* get the information for the process scheduled in */
699 guint cpu
= tfcs
->parent
.cpu
;
700 process
= ts
->running_process
[cpu
];
702 find_event_tree(tfcs
, process
->pid_time
,
704 process
->current_function
,
705 process
->state
->t
, process
->state
->n
, &(tfcs
->current_events_tree
),
706 &(tfcs
->current_event_types_tree
));
708 /* compute the time waiting for the process to schedule in */
714 static gboolean
process_fork(void *hook_data
, void *call_data
)
719 static gboolean
process_exit(void *hook_data
, void *call_data
)
721 update_event_tree((LttvTracefileStats
*)call_data
);
725 static gboolean
before_enum_process_state(void *hook_data
, void *call_data
)
728 /* Broken : adds up time in the current process doing the dump */
729 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
731 after_mode_end(tfcs
);
737 static gboolean
after_enum_process_state(void *hook_data
, void *call_data
)
739 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
740 LttvTraceStats
*tcs
= (LttvTraceStats
*)tfc
->t_context
;
741 update_trace_event_tree(tcs
);
745 static gboolean
after_statedump_end(void *hook_data
, void *call_data
)
747 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
748 LttvTraceStats
*tcs
= (LttvTraceStats
*)tfc
->t_context
;
749 update_trace_event_tree(tcs
);
753 static gboolean
process_free(void *hook_data
, void *call_data
)
758 static gboolean
every_event(void *hook_data
, void *call_data
)
760 LttvTracefileStats
*tfcs
= (LttvTracefileStats
*)call_data
;
762 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.parent
.tf
);
764 LttvAttributeValue v
;
766 struct marker_info
*info
;
768 /* The current branch corresponds to the tracefile/process/interrupt state.
769 Statistics are added within it, to count the number of events of this
770 type occuring in this context. A quark has been pre-allocated for each
771 event type and is used as name. */
773 info
= marker_get_info_from_id(tfcs
->parent
.parent
.tf
->mdata
, e
->event_id
);
775 lttv_attribute_find(tfcs
->current_event_types_tree
,
776 info
->name
, LTTV_UINT
, &v
);
781 struct cleanup_state_struct
{
783 LttTime current_time
;
786 //static void lttv_stats_cleanup_process_state(LttvTraceState *ts,
787 // LttvProcessState *process, LttTime current_time)
788 static void lttv_stats_cleanup_process_state(gpointer key
, gpointer value
,
791 struct cleanup_state_struct
*cleanup_closure
=
792 (struct cleanup_state_struct
*)user_data
;
793 LttvTraceState
*ts
= cleanup_closure
->ts
;
794 LttvProcessState
*process
= (LttvProcessState
*)value
;
795 LttTime current_time
= cleanup_closure
->current_time
;
796 LttvTracefileStats
**tfs
= (LttvTracefileStats
**)
797 &g_array_index(ts
->parent
.tracefiles
, LttvTracefileContext
*,
799 int cleanup_empty
= 0;
800 LttTime nested_delta
= ltt_time_zero
;
802 /* FIXME : ok, this is a hack. The time is infinite here :( */
803 //LttTime save_time = (*tfs)->parent.parent.timestamp;
804 //LttTime start, end;
805 //ltt_trace_time_span_get(ts->parent.t, &start, &end);
806 //(*tfs)->parent.parent.timestamp = end;
809 if(ltt_time_compare(process
->state
->cum_cpu_time
, ltt_time_zero
) != 0) {
810 find_event_tree(*tfs
, process
->pid_time
,
812 process
->current_function
,
813 process
->state
->t
, process
->state
->n
, &((*tfs
)->
814 current_events_tree
),
815 &((*tfs
)->current_event_types_tree
));
816 /* Call mode_end only if not at end of trace */
817 if(ltt_time_compare(current_time
, ltt_time_infinite
) != 0)
819 nested_delta
= process
->state
->cum_cpu_time
;
821 cleanup_empty
= lttv_state_pop_state_cleanup(process
,
822 (LttvTracefileState
*)*tfs
);
823 process
->state
->cum_cpu_time
= ltt_time_add(process
->state
->cum_cpu_time
,
826 } while(cleanup_empty
!= 1);
828 //(*tfs)->parent.parent.timestamp = save_time;
831 /* For each cpu, for each of their stacked states,
832 * perform sum of needed values. */
833 static void lttv_stats_cleanup_state(LttvTraceStats
*tcs
, LttTime current_time
)
835 LttvTraceState
*ts
= (LttvTraceState
*)tcs
;
836 struct cleanup_state_struct cleanup_closure
;
840 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
842 for(i
=0; i
<nb_cpus
; i
++) {
843 lttv_stats_cleanup_process_state(ts
, ts
->running_process
[i
], current_time
);
846 cleanup_closure
.ts
= ts
;
847 cleanup_closure
.current_time
= current_time
;
848 g_hash_table_foreach(ts
->processes
, lttv_stats_cleanup_process_state
,
852 void lttv_stats_sum_trace(LttvTraceStats
*self
, LttvAttribute
*ts_stats
,
853 LttTime current_time
)
855 LttvAttribute
*sum_container
= self
->stats
;
857 LttvAttributeType type
;
859 LttvAttributeValue value
;
861 LttvAttributeName name
;
869 int i
, j
, k
, l
, m
, nb_process
, nb_cpu
, nb_mode_type
, nb_submode
,
870 nb_event_type
, nf
, nb_functions
;
872 LttvAttribute
*main_tree
, *processes_tree
, *process_tree
, *cpus_tree
,
873 *cpu_tree
, *mode_tree
, *mode_types_tree
, *submodes_tree
,
874 *submode_tree
, *event_types_tree
, *mode_events_tree
,
877 *function_mode_types_tree
,
881 main_tree
= sum_container
;
883 lttv_attribute_find(sum_container
,
886 trace_is_summed
= *(value
.v_uint
);
889 /* First cleanup the state : sum all stalled information (never ending
892 lttv_stats_cleanup_state(self
, current_time
);
894 processes_tree
= lttv_attribute_find_subdir(main_tree
,
895 LTTV_STATS_PROCESSES
);
896 nb_process
= lttv_attribute_get_number(processes_tree
);
898 for(i
= 0 ; i
< nb_process
; i
++) {
899 type
= lttv_attribute_get(processes_tree
, i
, &name
, &value
, &is_named
);
900 process_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
902 cpus_tree
= lttv_attribute_find_subdir(process_tree
, LTTV_STATS_CPU
);
903 nb_cpu
= lttv_attribute_get_number(cpus_tree
);
905 for(j
= 0 ; j
< nb_cpu
; j
++) {
906 type
= lttv_attribute_get(cpus_tree
, j
, &name
, &value
, &is_named
);
907 cpu_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
909 trace_cpu_tree
= lttv_attribute_find_subdir(main_tree
,
911 trace_cpu_tree
= lttv_attribute_find_subdir_unnamed(trace_cpu_tree
, name
);
912 cpu_functions_tree
= lttv_attribute_find_subdir(cpu_tree
,
913 LTTV_STATS_FUNCTIONS
);
914 nb_functions
= lttv_attribute_get_number(cpu_functions_tree
);
916 for(nf
=0; nf
< nb_functions
; nf
++) {
917 type
= lttv_attribute_get(cpu_functions_tree
, nf
, &name
, &value
,
919 function_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
920 function_mode_types_tree
= lttv_attribute_find_subdir(function_tree
,
921 LTTV_STATS_MODE_TYPES
);
922 nb_mode_type
= lttv_attribute_get_number(function_mode_types_tree
);
923 for(k
= 0 ; k
< nb_mode_type
; k
++) {
924 type
= lttv_attribute_get(function_mode_types_tree
, k
, &name
,
926 mode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
928 submodes_tree
= lttv_attribute_find_subdir(mode_tree
,
929 LTTV_STATS_SUBMODES
);
930 mode_events_tree
= lttv_attribute_find_subdir(mode_tree
,
932 mode_types_tree
= lttv_attribute_find_subdir(mode_tree
,
933 LTTV_STATS_MODE_TYPES
);
935 nb_submode
= lttv_attribute_get_number(submodes_tree
);
937 for(l
= 0 ; l
< nb_submode
; l
++) {
938 type
= lttv_attribute_get(submodes_tree
, l
, &name
, &value
,
940 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
942 event_types_tree
= lttv_attribute_find_subdir(submode_tree
,
943 LTTV_STATS_EVENT_TYPES
);
944 nb_event_type
= lttv_attribute_get_number(event_types_tree
);
947 for(m
= 0 ; m
< nb_event_type
; m
++) {
948 type
= lttv_attribute_get(event_types_tree
, m
, &name
,
950 sum
+= *(value
.v_uint
);
952 lttv_attribute_find(submode_tree
, LTTV_STATS_EVENTS_COUNT
,
954 *(value
.v_uint
) = sum
;
956 type
= lttv_attribute_get(submodes_tree
, l
, &name
, &value
,
958 submode_tree
= LTTV_ATTRIBUTE(*(value
.v_gobject
));
959 if(!trace_is_summed
) {
960 lttv_attribute_recursive_add(mode_events_tree
, event_types_tree
);
961 lttv_attribute_recursive_add(mode_types_tree
, submode_tree
);
964 if(!trace_is_summed
) {
965 lttv_attribute_recursive_add(function_tree
, mode_types_tree
);
968 if(!trace_is_summed
) {
969 lttv_attribute_recursive_add(cpu_tree
, function_tree
);
970 lttv_attribute_recursive_add(process_tree
, function_tree
);
971 lttv_attribute_recursive_add(trace_cpu_tree
, function_tree
);
972 lttv_attribute_recursive_add(main_tree
, function_tree
);
974 lttv_attribute_recursive_add(ts_stats
, function_tree
);
981 gboolean
lttv_stats_sum_traceset_hook(void *hook_data
, void *call_data
)
983 struct sum_traceset_closure
*closure
=
984 (struct sum_traceset_closure
*)call_data
;
985 lttv_stats_sum_traceset(closure
->tss
, closure
->current_time
);
989 void lttv_stats_sum_traceset(LttvTracesetStats
*self
, LttTime current_time
)
991 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
992 LttvAttribute
*sum_container
= self
->stats
;
998 LttvAttributeValue value
;
1000 lttv_attribute_find(sum_container
, LTTV_STATS_SUMMED
,
1002 if(*(value
.v_uint
) != 0) return;
1003 *(value
.v_uint
) = 1;
1005 nb_trace
= lttv_traceset_number(traceset
);
1007 for(i
= 0 ; i
< nb_trace
; i
++) {
1008 tcs
= (LttvTraceStats
*)(self
->parent
.parent
.traces
[i
]);
1009 lttv_stats_sum_trace(tcs
, self
->stats
, current_time
);
1010 // lttv_attribute_recursive_add(sum_container, tcs->stats);
1015 // Hook wrapper. call_data is a traceset context.
1016 gboolean
lttv_stats_hook_add_event_hooks(void *hook_data
, void *call_data
)
1018 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
1020 lttv_stats_add_event_hooks(tss
);
1025 void lttv_stats_add_event_hooks(LttvTracesetStats
*self
)
1027 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
1029 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1033 LttvTracefileStats
*tfs
;
1035 GArray
*hooks
, *before_hooks
, *after_hooks
;
1039 LttvAttributeValue val
;
1041 nb_trace
= lttv_traceset_number(traceset
);
1042 for(i
= 0 ; i
< nb_trace
; i
++) {
1043 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
1045 /* Find the eventtype id for the following events and register the
1046 associated by id hooks. */
1048 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 12);
1050 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1052 LTT_EVENT_SYSCALL_ENTRY
,
1053 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1054 before_syscall_entry
, NULL
,
1057 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1059 LTT_EVENT_SYSCALL_EXIT
,
1061 before_syscall_exit
, NULL
,
1064 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1066 LTT_EVENT_TRAP_ENTRY
,
1067 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1068 before_trap_entry
, NULL
,
1071 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1073 LTT_EVENT_TRAP_EXIT
,
1075 before_trap_exit
, NULL
,
1078 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1080 LTT_EVENT_IRQ_ENTRY
,
1081 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1082 before_irq_entry
, NULL
,
1085 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1089 before_irq_exit
, NULL
,
1092 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1094 LTT_EVENT_SOFT_IRQ_ENTRY
,
1095 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
1096 before_soft_irq_entry
, NULL
,
1099 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1101 LTT_EVENT_SOFT_IRQ_EXIT
,
1103 before_soft_irq_exit
, NULL
,
1106 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1108 LTT_EVENT_SCHED_SCHEDULE
,
1109 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
),
1110 before_schedchange
, NULL
,
1113 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1114 LTT_CHANNEL_USERSPACE
,
1115 LTT_EVENT_FUNCTION_ENTRY
,
1116 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
1117 before_function_entry
, NULL
,
1120 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1121 LTT_CHANNEL_USERSPACE
,
1122 LTT_EVENT_FUNCTION_EXIT
,
1123 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
1124 before_function_exit
, NULL
,
1127 /* statedump-related hooks */
1128 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1129 LTT_CHANNEL_TASK_STATE
,
1130 LTT_EVENT_PROCESS_STATE
,
1131 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
),
1132 before_enum_process_state
, NULL
,
1135 before_hooks
= hooks
;
1137 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 16);
1139 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1141 LTT_EVENT_SYSCALL_ENTRY
,
1142 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1143 after_syscall_entry
, NULL
,
1146 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1148 LTT_EVENT_SYSCALL_EXIT
,
1150 after_syscall_exit
, NULL
,
1153 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1155 LTT_EVENT_TRAP_ENTRY
,
1156 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1157 after_trap_entry
, NULL
,
1160 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1162 LTT_EVENT_TRAP_EXIT
,
1164 after_trap_exit
, NULL
,
1167 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1169 LTT_EVENT_IRQ_ENTRY
,
1170 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1171 after_irq_entry
, NULL
,
1174 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1178 after_irq_exit
, NULL
,
1181 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1183 LTT_EVENT_SOFT_IRQ_ENTRY
,
1184 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
1185 after_soft_irq_entry
, NULL
,
1188 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1190 LTT_EVENT_SOFT_IRQ_EXIT
,
1192 after_soft_irq_exit
, NULL
,
1195 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1197 LTT_EVENT_SCHED_SCHEDULE
,
1198 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
),
1199 after_schedchange
, NULL
,
1202 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1204 LTT_EVENT_PROCESS_FORK
,
1205 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
),
1209 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1211 LTT_EVENT_PROCESS_EXIT
,
1212 FIELD_ARRAY(LTT_FIELD_PID
),
1216 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1218 LTT_EVENT_PROCESS_FREE
,
1219 FIELD_ARRAY(LTT_FIELD_PID
),
1223 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1224 LTT_CHANNEL_USERSPACE
,
1225 LTT_EVENT_FUNCTION_ENTRY
,
1226 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
1227 after_function_entry
, NULL
,
1230 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1231 LTT_CHANNEL_USERSPACE
,
1232 LTT_EVENT_FUNCTION_EXIT
,
1233 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
1234 after_function_exit
, NULL
,
1237 /* statedump-related hooks */
1238 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1239 LTT_CHANNEL_TASK_STATE
,
1240 LTT_EVENT_PROCESS_STATE
,
1241 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
),
1242 after_enum_process_state
, NULL
,
1245 lttv_trace_find_hook(ts
->parent
.parent
.t
,
1246 LTT_CHANNEL_GLOBAL_STATE
,
1247 LTT_EVENT_STATEDUMP_END
,
1249 after_statedump_end
, NULL
,
1252 after_hooks
= hooks
;
1254 /* Add these hooks to each event_by_id hooks list */
1256 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
1258 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1259 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
1260 LttvTracefileContext
*, j
));
1261 lttv_hooks_add(tfs
->parent
.parent
.event
, every_event
, NULL
,
1264 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1265 th
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1266 if (th
->mdata
== tfs
->parent
.parent
.tf
->mdata
)
1268 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, th
->id
),
1271 LTTV_PRIO_STATS_BEFORE_STATE
);
1273 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1274 th
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1275 if (th
->mdata
== tfs
->parent
.parent
.tf
->mdata
)
1277 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, th
->id
),
1280 LTTV_PRIO_STATS_AFTER_STATE
);
1283 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
1284 LTTV_POINTER
, &val
);
1285 *(val
.v_pointer
) = before_hooks
;
1286 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
1287 LTTV_POINTER
, &val
);
1288 *(val
.v_pointer
) = after_hooks
;
1292 // Hook wrapper. call_data is a traceset context.
1293 gboolean
lttv_stats_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1295 LttvTracesetStats
*tss
= (LttvTracesetStats
*)call_data
;
1297 lttv_stats_remove_event_hooks(tss
);
1302 void lttv_stats_remove_event_hooks(LttvTracesetStats
*self
)
1304 LttvTraceset
*traceset
= self
->parent
.parent
.ts
;
1306 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1310 LttvTracefileStats
*tfs
;
1312 GArray
*before_hooks
, *after_hooks
;
1316 LttvAttributeValue val
;
1318 nb_trace
= lttv_traceset_number(traceset
);
1319 for(i
= 0 ; i
< nb_trace
; i
++) {
1320 ts
= (LttvTraceStats
*)self
->parent
.parent
.traces
[i
];
1321 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_BEFORE_HOOKS
,
1322 LTTV_POINTER
, &val
);
1323 before_hooks
= *(val
.v_pointer
);
1324 lttv_attribute_find(self
->parent
.parent
.a
, LTTV_STATS_AFTER_HOOKS
,
1325 LTTV_POINTER
, &val
);
1326 after_hooks
= *(val
.v_pointer
);
1328 /* Remove these hooks from each event_by_id hooks list */
1330 nb_tracefile
= ts
->parent
.parent
.tracefiles
->len
;
1332 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1333 tfs
= LTTV_TRACEFILE_STATS(g_array_index(ts
->parent
.parent
.tracefiles
,
1334 LttvTracefileContext
*, j
));
1335 lttv_hooks_remove_data(tfs
->parent
.parent
.event
, every_event
,
1338 for(k
= 0 ; k
< before_hooks
->len
; k
++) {
1339 th
= &g_array_index(before_hooks
, LttvTraceHook
, k
);
1340 if (th
->mdata
== tfs
->parent
.parent
.tf
->mdata
)
1341 lttv_hooks_remove_data(
1342 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, th
->id
),
1346 for(k
= 0 ; k
< after_hooks
->len
; k
++) {
1347 th
= &g_array_index(after_hooks
, LttvTraceHook
, k
);
1348 if (th
->mdata
== tfs
->parent
.parent
.tf
->mdata
)
1349 lttv_hooks_remove_data(
1350 lttv_hooks_by_id_find(tfs
->parent
.parent
.event_by_id
, th
->id
),
1356 g_debug("lttv_stats_remove_event_hooks()");
1357 lttv_trace_hook_remove_all(&before_hooks
);
1358 lttv_trace_hook_remove_all(&after_hooks
);
1359 g_array_free(before_hooks
, TRUE
);
1360 g_array_free(after_hooks
, TRUE
);
1365 static void module_init()
1367 LTTV_STATS_PROCESS_UNKNOWN
= g_quark_from_string("unknown process");
1368 LTTV_STATS_PROCESSES
= g_quark_from_string("processes");
1369 LTTV_STATS_CPU
= g_quark_from_string("cpu");
1370 LTTV_STATS_MODE_TYPES
= g_quark_from_string("mode_types");
1371 LTTV_STATS_MODES
= g_quark_from_string("modes");
1372 LTTV_STATS_SUBMODES
= g_quark_from_string("submodes");
1373 LTTV_STATS_FUNCTIONS
= g_quark_from_string("functions");
1374 LTTV_STATS_EVENT_TYPES
= g_quark_from_string("event_types");
1375 LTTV_STATS_CPU_TIME
= g_quark_from_string("cpu time");
1376 LTTV_STATS_CUMULATIVE_CPU_TIME
= g_quark_from_string("cumulative cpu time (includes nested routines and modes)");
1377 LTTV_STATS_ELAPSED_TIME
= g_quark_from_string("elapsed time (includes per process waiting time)");
1378 LTTV_STATS_EVENTS
= g_quark_from_string("events");
1379 LTTV_STATS_EVENTS_COUNT
= g_quark_from_string("events count");
1380 LTTV_STATS_BEFORE_HOOKS
= g_quark_from_string("saved stats before hooks");
1381 LTTV_STATS_AFTER_HOOKS
= g_quark_from_string("saved stats after hooks");
1382 LTTV_STATS_USE_COUNT
= g_quark_from_string("stats_use_count");
1383 LTTV_STATS
= g_quark_from_string("statistics");
1384 LTTV_STATS_TRACEFILES
= g_quark_from_string("tracefiles statistics");
1385 LTTV_STATS_SUMMED
= g_quark_from_string("statistics summed");
1388 static void module_destroy()
1393 LTTV_MODULE("stats", "Compute processes statistics", \
1394 "Accumulate statistics for event types, processes and CPUs", \
1395 module_init
, module_destroy
, "state");
1397 /* Change the places where stats are called (create/read/write stats)
1399 Check for options in batchtest.c to reduce writing and see what tests are
1400 best candidates for performance analysis. Once OK, commit, move to main
1401 and run tests. Update the gui for statistics. */