do not include obsolete facility.h and type.h
[lttv.git] / ltt / branches / poly / lttv / lttv / stats.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
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;
7 *
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.
12 *
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,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #include <lttv/module.h>
25 #include <lttv/stats.h>
26 #include <lttv/lttv.h>
27 #include <lttv/attribute.h>
28 #include <ltt/trace.h>
29 #include <ltt/event.h>
30
31 #define BUF_SIZE 256
32 #define MAX_64_HEX_STRING_LEN 19
33
34 GQuark
35 LTTV_STATS_PROCESS_UNKNOWN,
36 LTTV_STATS_PROCESSES,
37 LTTV_STATS_CPU,
38 LTTV_STATS_MODE_TYPES,
39 LTTV_STATS_MODES,
40 LTTV_STATS_SUBMODES,
41 LTTV_STATS_FUNCTIONS,
42 LTTV_STATS_EVENT_TYPES,
43 LTTV_STATS_CPU_TIME,
44 LTTV_STATS_CUMULATIVE_CPU_TIME,
45 LTTV_STATS_ELAPSED_TIME,
46 LTTV_STATS_EVENTS,
47 LTTV_STATS_EVENTS_COUNT,
48 LTTV_STATS_USE_COUNT,
49 LTTV_STATS,
50 LTTV_STATS_TRACEFILES,
51 LTTV_STATS_SUMMED,
52 LTTV_STATS_BEFORE_HOOKS,
53 LTTV_STATS_AFTER_HOOKS;
54
55 static void
56 find_event_tree(LttvTracefileStats *tfcs, GQuark pid_time, guint cpu,
57 guint64 function,
58 GQuark mode, GQuark sub_mode, LttvAttribute **events_tree,
59 LttvAttribute **event_types_tree);
60
61
62 static void lttv_stats_init(LttvTracesetStats *self)
63 {
64 guint i, j, nb_trace, nb_tracefile;
65
66 LttvTraceContext *tc;
67
68 LttvTraceStats *tcs;
69
70 LttvTracefileContext *tfc;
71
72 LttvTracefileContext **tfs;
73 LttvTracefileStats *tfcs;
74
75 LttTime timestamp = {0,0};
76
77 LttvAttributeValue v;
78
79 LttvAttribute
80 *stats_tree,
81 *tracefiles_stats;
82
83 LttvTraceset *ts = self->parent.parent.ts;
84
85 self->stats = lttv_attribute_find_subdir(
86 lttv_traceset_attribute(self->parent.parent.ts),
87 LTTV_STATS);
88 lttv_attribute_find(lttv_traceset_attribute(self->parent.parent.ts),
89 LTTV_STATS_USE_COUNT,
90 LTTV_UINT, &v);
91
92 (*(v.v_uint))++;
93 if(*(v.v_uint) == 1) {
94 g_assert(lttv_attribute_get_number(self->stats) == 0);
95 }
96
97 nb_trace = lttv_traceset_number(ts);
98
99 for(i = 0 ; i < nb_trace ; i++) {
100 tc = self->parent.parent.traces[i];
101 tcs = LTTV_TRACE_STATS(tc);
102
103 tcs->stats = lttv_attribute_find_subdir(tcs->parent.parent.t_a,LTTV_STATS);
104 tracefiles_stats = lttv_attribute_find_subdir(tcs->parent.parent.t_a,
105 LTTV_STATS_TRACEFILES);
106 lttv_attribute_find(tcs->parent.parent.t_a, LTTV_STATS_USE_COUNT,
107 LTTV_UINT, &v);
108
109 (*(v.v_uint))++;
110 if(*(v.v_uint) == 1) {
111 g_assert(lttv_attribute_get_number(tcs->stats) == 0);
112 }
113
114 nb_tracefile = tc->tracefiles->len;
115
116 for(j = 0 ; j < nb_tracefile ; j++) {
117 tfs = &g_array_index(tc->tracefiles,
118 LttvTracefileContext*, j);
119 tfcs = LTTV_TRACEFILE_STATS(*tfs);
120 tfcs->stats = lttv_attribute_find_subdir(tracefiles_stats,
121 ltt_tracefile_long_name(tfcs->parent.parent.tf));
122 guint cpu = tfcs->parent.cpu;
123 find_event_tree(tfcs, LTTV_STATS_PROCESS_UNKNOWN,
124 cpu,
125 0x0ULL,
126 LTTV_STATE_MODE_UNKNOWN,
127 LTTV_STATE_SUBMODE_UNKNOWN, &tfcs->current_events_tree,
128 &tfcs->current_event_types_tree);
129 }
130 }
131
132 }
133
134 static void lttv_stats_fini(LttvTracesetStats *self)
135 {
136 guint i, j, nb_trace, nb_tracefile;
137
138 LttvTraceset *ts;
139
140 LttvTraceContext *tc;
141
142 LttvTraceStats *tcs;
143
144 LttvTracefileContext *tfc;
145
146 LttvTracefileStats *tfcs;
147
148 LttTime timestamp = {0,0};
149
150 LttvAttributeValue v;
151
152 LttvAttribute *tracefiles_stats;
153
154 lttv_attribute_find(self->parent.parent.ts_a, LTTV_STATS_USE_COUNT,
155 LTTV_UINT, &v);
156 (*(v.v_uint))--;
157
158 if(*(v.v_uint) == 0) {
159 lttv_attribute_remove_by_name(self->parent.parent.ts_a, LTTV_STATS);
160 }
161 self->stats = NULL;
162
163 ts = self->parent.parent.ts;
164 nb_trace = lttv_traceset_number(ts);
165
166 for(i = 0 ; i < nb_trace ; i++) {
167 tcs = (LttvTraceStats *)(tc = (LTTV_TRACESET_CONTEXT(self)->traces[i]));
168
169 lttv_attribute_find(tcs->parent.parent.t_a, LTTV_STATS_USE_COUNT,
170 LTTV_UINT, &v);
171 (*(v.v_uint))--;
172
173 if(*(v.v_uint) == 0) {
174 lttv_attribute_remove_by_name(tcs->parent.parent.t_a,LTTV_STATS);
175 tracefiles_stats = lttv_attribute_find_subdir(tcs->parent.parent.t_a,
176 LTTV_STATS_TRACEFILES);
177 lttv_attribute_remove_by_name(tcs->parent.parent.t_a,
178 LTTV_STATS_TRACEFILES);
179 }
180 tcs->stats = NULL;
181
182 nb_tracefile = tc->tracefiles->len;
183
184 for(j = 0 ; j < nb_tracefile ; j++) {
185 tfc = g_array_index(tc->tracefiles,
186 LttvTracefileContext*, j);
187 tfcs = (LttvTracefileStats *)tfc;
188 tfcs->stats = NULL;
189 tfcs->current_events_tree = NULL;
190 tfcs->current_event_types_tree = NULL;
191 }
192 }
193 }
194
195
196 void lttv_stats_reset(LttvTracesetStats *self)
197 {
198 lttv_stats_fini(self);
199 lttv_stats_init(self);
200 }
201
202
203
204 static void
205 init(LttvTracesetStats *self, LttvTraceset *ts)
206 {
207 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))->
208 init((LttvTracesetContext *)self, ts);
209
210 lttv_stats_init(self);
211 }
212
213
214 static void
215 fini(LttvTracesetStats *self)
216 {
217 lttv_stats_fini(self);
218
219 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))->
220 fini((LttvTracesetContext *)self);
221 }
222
223
224 static LttvTracesetContext *
225 new_traceset_context(LttvTracesetContext *self)
226 {
227 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATS_TYPE, NULL));
228 }
229
230
231 static LttvTraceContext *
232 new_trace_context(LttvTracesetContext *self)
233 {
234 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATS_TYPE, NULL));
235 }
236
237
238 static LttvTracefileContext *
239 new_tracefile_context(LttvTracesetContext *self)
240 {
241 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATS_TYPE, NULL));
242 }
243
244
245 static void
246 traceset_stats_instance_init (GTypeInstance *instance, gpointer g_class)
247 {
248 }
249
250
251 static void
252 traceset_stats_finalize (LttvTracesetStats *self)
253 {
254 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_STATE_TYPE))->
255 finalize(G_OBJECT(self));
256 }
257
258
259 static void
260 traceset_stats_class_init (LttvTracesetContextClass *klass)
261 {
262 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
263
264 gobject_class->finalize = (void (*)(GObject *self)) traceset_stats_finalize;
265 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
266 klass->fini = (void (*)(LttvTracesetContext *self))fini;
267 klass->new_traceset_context = new_traceset_context;
268 klass->new_trace_context = new_trace_context;
269 klass->new_tracefile_context = new_tracefile_context;
270 }
271
272
273 GType
274 lttv_traceset_stats_get_type(void)
275 {
276 static GType type = 0;
277 if (type == 0) {
278 static const GTypeInfo info = {
279 sizeof (LttvTracesetStatsClass),
280 NULL, /* base_init */
281 NULL, /* base_finalize */
282 (GClassInitFunc) traceset_stats_class_init, /* class_init */
283 NULL, /* class_finalize */
284 NULL, /* class_data */
285 sizeof (LttvTracesetStats),
286 0, /* n_preallocs */
287 (GInstanceInitFunc) traceset_stats_instance_init, /* instance_init */
288 NULL /* Value handling */
289 };
290
291 type = g_type_register_static (LTTV_TRACESET_STATE_TYPE,
292 "LttvTracesetStatsType",
293 &info, 0);
294 }
295 return type;
296 }
297
298
299 static void
300 trace_stats_instance_init (GTypeInstance *instance, gpointer g_class)
301 {
302 }
303
304
305 static void
306 trace_stats_finalize (LttvTraceStats *self)
307 {
308 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_STATE_TYPE))->
309 finalize(G_OBJECT(self));
310 }
311
312
313 static void
314 trace_stats_class_init (LttvTraceContextClass *klass)
315 {
316 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
317
318 gobject_class->finalize = (void (*)(GObject *self)) trace_stats_finalize;
319 }
320
321
322 GType
323 lttv_trace_stats_get_type(void)
324 {
325 static GType type = 0;
326 if (type == 0) {
327 static const GTypeInfo info = {
328 sizeof (LttvTraceStatsClass),
329 NULL, /* base_init */
330 NULL, /* base_finalize */
331 (GClassInitFunc) trace_stats_class_init, /* class_init */
332 NULL, /* class_finalize */
333 NULL, /* class_data */
334 sizeof (LttvTraceStats),
335 0, /* n_preallocs */
336 (GInstanceInitFunc) trace_stats_instance_init, /* instance_init */
337 NULL /* Value handling */
338 };
339
340 type = g_type_register_static (LTTV_TRACE_STATE_TYPE,
341 "LttvTraceStatsType", &info, 0);
342 }
343 return type;
344 }
345
346
347 static void
348 tracefile_stats_instance_init (GTypeInstance *instance, gpointer g_class)
349 {
350 }
351
352
353 static void
354 tracefile_stats_finalize (LttvTracefileStats *self)
355 {
356 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_STATE_TYPE))->
357 finalize(G_OBJECT(self));
358 }
359
360
361 static void
362 tracefile_stats_class_init (LttvTracefileStatsClass *klass)
363 {
364 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
365
366 gobject_class->finalize = (void (*)(GObject *self)) tracefile_stats_finalize;
367 }
368
369
370 GType
371 lttv_tracefile_stats_get_type(void)
372 {
373 static GType type = 0;
374 if (type == 0) {
375 static const GTypeInfo info = {
376 sizeof (LttvTracefileStatsClass),
377 NULL, /* base_init */
378 NULL, /* base_finalize */
379 (GClassInitFunc) tracefile_stats_class_init, /* class_init */
380 NULL, /* class_finalize */
381 NULL, /* class_data */
382 sizeof (LttvTracefileStats),
383 0, /* n_preallocs */
384 (GInstanceInitFunc) tracefile_stats_instance_init, /* instance_init */
385 NULL /* Value handling */
386 };
387
388 type = g_type_register_static (LTTV_TRACEFILE_STATE_TYPE,
389 "LttvTracefileStatsType", &info, 0);
390 }
391 return type;
392 }
393
394 static void
395 find_event_tree(LttvTracefileStats *tfcs,
396 GQuark pid_time,
397 guint cpu,
398 guint64 function,
399 GQuark mode,
400 GQuark sub_mode,
401 LttvAttribute **events_tree,
402 LttvAttribute **event_types_tree)
403 {
404 LttvAttribute *a, *prev_a;
405 gchar fstring[MAX_64_HEX_STRING_LEN];
406 gint ret;
407
408 ret = snprintf(fstring, MAX_64_HEX_STRING_LEN-1,
409 "0x%llX", function) > 0;
410 g_assert(ret > 0);
411 fstring[MAX_64_HEX_STRING_LEN-1] = '\0';
412
413 LttvTraceStats *tcs = (LttvTraceStats*)tfcs->parent.parent.t_context;
414 a = lttv_attribute_find_subdir(tcs->stats, LTTV_STATS_PROCESSES);
415 a = lttv_attribute_find_subdir(a, pid_time);
416 a = lttv_attribute_find_subdir(a, LTTV_STATS_CPU);
417 a = lttv_attribute_find_subdir_unnamed(a, cpu);
418 a = lttv_attribute_find_subdir(a, LTTV_STATS_FUNCTIONS);
419 a = lttv_attribute_find_subdir(a, g_quark_from_string(fstring));
420 a = lttv_attribute_find_subdir(a, LTTV_STATS_MODE_TYPES);
421 a = lttv_attribute_find_subdir(a, mode);
422 a = lttv_attribute_find_subdir(a, LTTV_STATS_SUBMODES);
423 a = lttv_attribute_find_subdir(a, sub_mode);
424 *events_tree = a;
425 a = lttv_attribute_find_subdir(a, LTTV_STATS_EVENT_TYPES);
426 *event_types_tree = a;
427 }
428
429 static void update_event_tree(LttvTracefileStats *tfcs)
430 {
431 guint cpu = tfcs->parent.cpu;
432 LttvTraceState *ts = (LttvTraceState *)tfcs->parent.parent.t_context;
433 LttvProcessState *process = ts->running_process[cpu];
434 LttvExecutionState *es = process->state;
435
436 find_event_tree(tfcs, process->pid_time,
437 cpu,
438 process->current_function,
439 es->t, es->n, &(tfcs->current_events_tree),
440 &(tfcs->current_event_types_tree));
441 }
442
443
444 /* Update the trace event tree for the specified cpu */
445 static void update_trace_event_tree(LttvTraceStats *tcs)
446 {
447 LttvTracefileStats *tfcs;
448 LttvTraceContext *tc = (LttvTraceContext*)tcs;
449 guint j, nb_tracefile;
450
451 /* For each tracefile, update the event tree */
452 nb_tracefile = tc->tracefiles->len;
453 for(j = 0; j < nb_tracefile; j++) {
454 tfcs = LTTV_TRACEFILE_STATS(g_array_index(tc->tracefiles,
455 LttvTracefileContext*, j));
456 update_event_tree(tfcs);
457 }
458 }
459
460 static void mode_change(LttvTracefileStats *tfcs)
461 {
462 LttvTraceState *ts = (LttvTraceState *)tfcs->parent.parent.t_context;
463 guint cpu = tfcs->parent.cpu;
464 LttvProcessState *process = ts->running_process[cpu];
465 LttvAttributeValue cpu_time, cum_cpu_time;
466
467 LttTime delta;
468
469 if(process->state->s == LTTV_STATE_RUN &&
470 process->state->t != LTTV_STATE_MODE_UNKNOWN)
471 delta = ltt_time_sub(tfcs->parent.parent.timestamp,
472 process->state->change);
473 else
474 delta = ltt_time_zero;
475
476 lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CPU_TIME,
477 LTTV_TIME, &cpu_time);
478 *(cpu_time.v_time) = ltt_time_add(*(cpu_time.v_time), delta);
479
480 process->state->cum_cpu_time = ltt_time_add(process->state->cum_cpu_time,
481 delta);
482 }
483
484 /* Note : every mode_end must come with a cumulative cpu time update in the
485 * after hook. */
486 static void mode_end(LttvTracefileStats *tfcs)
487 {
488 LttvTraceState *ts = (LttvTraceState *)tfcs->parent.parent.t_context;
489 guint cpu = tfcs->parent.cpu;
490 LttvProcessState *process = ts->running_process[cpu];
491 LttvAttributeValue elapsed_time, cpu_time, cum_cpu_time;
492
493 LttTime delta;
494
495 /* FIXME put there in case of a missing update after a state modification */
496 //void *lasttree = tfcs->current_events_tree;
497 //update_event_tree(tfcs);
498 //g_assert (lasttree == tfcs->current_events_tree);
499 lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_ELAPSED_TIME,
500 LTTV_TIME, &elapsed_time);
501
502 if(process->state->t != LTTV_STATE_MODE_UNKNOWN) {
503 delta = ltt_time_sub(tfcs->parent.parent.timestamp,
504 process->state->entry);
505 } else
506 delta = ltt_time_zero;
507
508 *(elapsed_time.v_time) = ltt_time_add(*(elapsed_time.v_time), delta);
509
510 lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CPU_TIME,
511 LTTV_TIME, &cpu_time);
512
513 /* if it is a running mode, we must count its cpu time */
514 if(process->state->s == LTTV_STATE_RUN &&
515 process->state->t != LTTV_STATE_MODE_UNKNOWN)
516 delta = ltt_time_sub(tfcs->parent.parent.timestamp,
517 process->state->change);
518 else
519 delta = ltt_time_zero;
520
521 *(cpu_time.v_time) = ltt_time_add(*(cpu_time.v_time), delta);
522 process->state->cum_cpu_time = ltt_time_add(process->state->cum_cpu_time,
523 delta);
524
525 lttv_attribute_find(tfcs->current_events_tree, LTTV_STATS_CUMULATIVE_CPU_TIME,
526 LTTV_TIME, &cum_cpu_time);
527 *(cum_cpu_time.v_time) = ltt_time_add(*(cum_cpu_time.v_time),
528 process->state->cum_cpu_time);
529 }
530
531
532 static void after_mode_end(LttvTracefileStats *tfcs)
533 {
534 LttvTraceState *ts = (LttvTraceState *)tfcs->parent.parent.t_context;
535 guint cpu = tfcs->parent.cpu;
536 LttvProcessState *process = ts->running_process[cpu];
537 LttvAttributeValue cum_cpu_time;
538
539 LttTime nested_delta;
540
541 nested_delta = process->state->cum_cpu_time;
542 process->state->cum_cpu_time = ltt_time_zero; /* For after traceset hook */
543
544 update_event_tree(tfcs);
545
546 process->state->cum_cpu_time = ltt_time_add(process->state->cum_cpu_time,
547 nested_delta);
548 }
549
550 static gboolean before_syscall_entry(void *hook_data, void *call_data)
551 {
552 mode_change((LttvTracefileStats *)call_data);
553 return FALSE;
554 }
555
556
557 static gboolean after_syscall_entry(void *hook_data, void *call_data)
558 {
559 update_event_tree((LttvTracefileStats *)call_data);
560 return FALSE;
561 }
562
563
564 static gboolean before_syscall_exit(void *hook_data, void *call_data)
565 {
566 mode_end((LttvTracefileStats *)call_data);
567 return FALSE;
568 }
569
570
571 static gboolean after_syscall_exit(void *hook_data, void *call_data)
572 {
573 after_mode_end((LttvTracefileStats *)call_data);
574 return FALSE;
575 }
576
577
578 static gboolean before_trap_entry(void *hook_data, void *call_data)
579 {
580 mode_change((LttvTracefileStats *)call_data);
581 return FALSE;
582 }
583
584
585 static gboolean after_trap_entry(void *hook_data, void *call_data)
586 {
587 update_event_tree((LttvTracefileStats *)call_data);
588 return FALSE;
589 }
590
591
592 static gboolean before_trap_exit(void *hook_data, void *call_data)
593 {
594 mode_end((LttvTracefileStats *)call_data);
595 return FALSE;
596 }
597
598
599 static gboolean after_trap_exit(void *hook_data, void *call_data)
600 {
601 after_mode_end((LttvTracefileStats *)call_data);
602 return FALSE;
603 }
604
605
606 static gboolean before_irq_entry(void *hook_data, void *call_data)
607 {
608 mode_change((LttvTracefileStats *)call_data);
609 return FALSE;
610 }
611
612 static gboolean after_irq_entry(void *hook_data, void *call_data)
613 {
614 update_event_tree((LttvTracefileStats *)call_data);
615 return FALSE;
616 }
617
618
619 static gboolean before_irq_exit(void *hook_data, void *call_data)
620 {
621 mode_end((LttvTracefileStats *)call_data);
622 return FALSE;
623 }
624
625
626 static gboolean after_irq_exit(void *hook_data, void *call_data)
627 {
628 after_mode_end((LttvTracefileStats *)call_data);
629 return FALSE;
630 }
631
632
633 static gboolean before_soft_irq_entry(void *hook_data, void *call_data)
634 {
635 mode_change((LttvTracefileStats *)call_data);
636 return FALSE;
637 }
638
639 static gboolean after_soft_irq_entry(void *hook_data, void *call_data)
640 {
641 update_event_tree((LttvTracefileStats *)call_data);
642 return FALSE;
643 }
644
645 static gboolean before_soft_irq_exit(void *hook_data, void *call_data)
646 {
647 mode_end((LttvTracefileStats *)call_data);
648 return FALSE;
649 }
650
651
652 static gboolean after_soft_irq_exit(void *hook_data, void *call_data)
653 {
654 after_mode_end((LttvTracefileStats *)call_data);
655 return FALSE;
656 }
657
658 static gboolean before_function_entry(void *hook_data, void *call_data)
659 {
660 mode_change((LttvTracefileStats *)call_data);
661 return FALSE;
662 }
663
664 static gboolean after_function_entry(void *hook_data, void *call_data)
665 {
666 update_event_tree((LttvTracefileStats *)call_data);
667 return FALSE;
668 }
669
670 static gboolean before_function_exit(void *hook_data, void *call_data)
671 {
672 mode_end((LttvTracefileStats *)call_data);
673 return FALSE;
674 }
675
676 static gboolean after_function_exit(void *hook_data, void *call_data)
677 {
678 after_mode_end((LttvTracefileStats *)call_data);
679 return FALSE;
680 }
681
682
683 static gboolean before_schedchange(void *hook_data, void *call_data)
684 {
685 LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data;
686
687 LttvTraceState *ts = (LttvTraceState*)tfcs->parent.parent.t_context;
688
689 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.parent.tf);
690
691 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
692
693 guint pid_in, pid_out;
694
695 gint64 state_out;
696
697 pid_out = ltt_event_get_unsigned(e, thf->f1);
698 pid_in = ltt_event_get_unsigned(e, thf->f2);
699 state_out = ltt_event_get_long_int(e, thf->f3);
700
701 /* compute the time for the process to schedule out */
702 mode_change(tfcs);
703
704 return FALSE;
705 }
706
707 static gboolean after_schedchange(void *hook_data, void *call_data)
708 {
709 LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data;
710
711 LttvTraceState *ts = (LttvTraceState*)tfcs->parent.parent.t_context;
712
713 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.parent.tf);
714
715 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
716
717 guint pid_in, pid_out;
718
719 gint64 state_out;
720
721 LttvProcessState *process;
722
723 pid_out = ltt_event_get_unsigned(e, thf->f1);
724 pid_in = ltt_event_get_unsigned(e, thf->f2);
725 state_out = ltt_event_get_long_int(e, thf->f3);
726
727 /* get the information for the process scheduled in */
728 guint cpu = tfcs->parent.cpu;
729 process = ts->running_process[cpu];
730
731 find_event_tree(tfcs, process->pid_time,
732 cpu,
733 process->current_function,
734 process->state->t, process->state->n, &(tfcs->current_events_tree),
735 &(tfcs->current_event_types_tree));
736
737 /* compute the time waiting for the process to schedule in */
738 mode_change(tfcs);
739
740 return FALSE;
741 }
742
743 static gboolean process_fork(void *hook_data, void *call_data)
744 {
745 return FALSE;
746 }
747
748 static gboolean process_exit(void *hook_data, void *call_data)
749 {
750 update_event_tree((LttvTracefileStats *)call_data);
751 return FALSE;
752 }
753
754 static gboolean before_enum_process_state(void *hook_data, void *call_data)
755 {
756 #if 0
757 /* Broken : adds up time in the current process doing the dump */
758 LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data;
759 mode_end(tfcs);
760 after_mode_end(tfcs);
761 mode_change(tfcs);
762 #endif //0
763 return FALSE;
764 }
765
766 static gboolean after_enum_process_state(void *hook_data, void *call_data)
767 {
768 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
769 LttvTraceStats *tcs = (LttvTraceStats*)tfc->t_context;
770 update_trace_event_tree(tcs);
771 return FALSE;
772 }
773
774 static gboolean after_statedump_end(void *hook_data, void *call_data)
775 {
776 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
777 LttvTraceStats *tcs = (LttvTraceStats*)tfc->t_context;
778 update_trace_event_tree(tcs);
779 return FALSE;
780 }
781
782 static gboolean process_free(void *hook_data, void *call_data)
783 {
784 return FALSE;
785 }
786
787 static gboolean every_event(void *hook_data, void *call_data)
788 {
789 LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data;
790
791 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.parent.tf);
792
793 LttvAttributeValue v;
794
795 /* The current branch corresponds to the tracefile/process/interrupt state.
796 Statistics are added within it, to count the number of events of this
797 type occuring in this context. A quark has been pre-allocated for each
798 event type and is used as name. */
799
800 lttv_attribute_find(tfcs->current_event_types_tree,
801 ltt_eventtype_name(ltt_event_eventtype(e)),
802 LTTV_UINT, &v);
803 (*(v.v_uint))++;
804 return FALSE;
805 }
806
807 struct cleanup_state_struct {
808 LttvTraceState *ts;
809 LttTime current_time;
810 };
811
812 //static void lttv_stats_cleanup_process_state(LttvTraceState *ts,
813 // LttvProcessState *process, LttTime current_time)
814 static void lttv_stats_cleanup_process_state(gpointer key, gpointer value,
815 gpointer user_data)
816 {
817 struct cleanup_state_struct *cleanup_closure =
818 (struct cleanup_state_struct *)user_data;
819 LttvTraceState *ts = cleanup_closure->ts;
820 LttvTraceStats *tcs = (LttvTraceStats *)ts;
821 LttvProcessState *process = (LttvProcessState *)value;
822 LttvTracesetContext *tsc = ts->parent.ts_context;
823 LttTime current_time = cleanup_closure->current_time;
824 int i;
825 LttvTracefileStats **tfs = (LttvTracefileStats **)
826 &g_array_index(ts->parent.tracefiles, LttvTracefileContext*,
827 process->cpu);
828 int cleanup_empty = 0;
829 LttTime nested_delta = ltt_time_zero;
830
831 /* FIXME : ok, this is a hack. The time is infinite here :( */
832 //LttTime save_time = (*tfs)->parent.parent.timestamp;
833 //LttTime start, end;
834 //ltt_trace_time_span_get(ts->parent.t, &start, &end);
835 //(*tfs)->parent.parent.timestamp = end;
836
837 do {
838 if(ltt_time_compare(process->state->cum_cpu_time, ltt_time_zero) != 0) {
839 find_event_tree(*tfs, process->pid_time,
840 process->cpu,
841 process->current_function,
842 process->state->t, process->state->n, &((*tfs)->current_events_tree),
843 &((*tfs)->current_event_types_tree));
844 /* Call mode_end only if not at end of trace */
845 if(ltt_time_compare(current_time, ltt_time_infinite) != 0)
846 mode_end(*tfs);
847 nested_delta = process->state->cum_cpu_time;
848 }
849 cleanup_empty = lttv_state_pop_state_cleanup(process,
850 (LttvTracefileState *)*tfs);
851 process->state->cum_cpu_time = ltt_time_add(process->state->cum_cpu_time,
852 nested_delta);
853
854 } while(cleanup_empty != 1);
855
856 //(*tfs)->parent.parent.timestamp = save_time;
857 }
858
859 /* For each cpu, for each of their stacked states,
860 * perform sum of needed values. */
861 static void lttv_stats_cleanup_state(LttvTraceStats *tcs, LttTime current_time)
862 {
863 LttvTraceState *ts = (LttvTraceState *)tcs;
864 struct cleanup_state_struct cleanup_closure;
865 #if 0
866 guint nb_cpus, i;
867
868 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
869
870 for(i=0; i<nb_cpus; i++) {
871 lttv_stats_cleanup_process_state(ts, ts->running_process[i], current_time);
872 }
873 #endif //0
874 cleanup_closure.ts = tcs;
875 cleanup_closure.current_time = current_time;
876 g_hash_table_foreach(ts->processes, lttv_stats_cleanup_process_state,
877 &cleanup_closure);
878 }
879
880 void
881 lttv_stats_sum_trace(LttvTraceStats *self, LttvAttribute *ts_stats,
882 LttTime current_time)
883 {
884 LttvAttribute *sum_container = self->stats;
885
886 LttvAttributeType type;
887
888 LttvAttributeValue value;
889
890 LttvAttributeName name;
891
892 gboolean is_named;
893
894 unsigned sum;
895
896 int trace_is_summed;
897
898 int i, j, k, l, m, nb_process, nb_cpu, nb_mode_type, nb_submode,
899 nb_event_type, nf, nb_functions;
900
901 LttvAttribute *main_tree, *processes_tree, *process_tree, *cpus_tree,
902 *cpu_tree, *mode_tree, *mode_types_tree, *submodes_tree,
903 *submode_tree, *event_types_tree, *mode_events_tree,
904 *cpu_functions_tree,
905 *function_tree,
906 *function_mode_types_tree,
907 *trace_cpu_tree;
908
909
910 main_tree = sum_container;
911
912 lttv_attribute_find(sum_container,
913 LTTV_STATS_SUMMED,
914 LTTV_UINT, &value);
915 trace_is_summed = *(value.v_uint);
916 *(value.v_uint) = 1;
917
918 /* First cleanup the state : sum all stalled information (never ending
919 * states). */
920 if(!trace_is_summed)
921 lttv_stats_cleanup_state(self, current_time);
922
923 processes_tree = lttv_attribute_find_subdir(main_tree,
924 LTTV_STATS_PROCESSES);
925 nb_process = lttv_attribute_get_number(processes_tree);
926
927 for(i = 0 ; i < nb_process ; i++) {
928 type = lttv_attribute_get(processes_tree, i, &name, &value, &is_named);
929 process_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
930
931 cpus_tree = lttv_attribute_find_subdir(process_tree, LTTV_STATS_CPU);
932 nb_cpu = lttv_attribute_get_number(cpus_tree);
933
934 for(j = 0 ; j < nb_cpu ; j++) {
935 type = lttv_attribute_get(cpus_tree, j, &name, &value, &is_named);
936 cpu_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
937
938 trace_cpu_tree = lttv_attribute_find_subdir(main_tree, LTTV_STATS_CPU);
939 trace_cpu_tree = lttv_attribute_find_subdir_unnamed(trace_cpu_tree, name);
940 cpu_functions_tree = lttv_attribute_find_subdir(cpu_tree,
941 LTTV_STATS_FUNCTIONS);
942 nb_functions = lttv_attribute_get_number(cpu_functions_tree);
943
944 for(nf=0; nf < nb_functions; nf++) {
945 type = lttv_attribute_get(cpu_functions_tree, nf, &name, &value,
946 &is_named);
947 function_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
948 function_mode_types_tree = lttv_attribute_find_subdir(function_tree,
949 LTTV_STATS_MODE_TYPES);
950 nb_mode_type = lttv_attribute_get_number(function_mode_types_tree);
951 for(k = 0 ; k < nb_mode_type ; k++) {
952 type = lttv_attribute_get(function_mode_types_tree, k, &name, &value,
953 &is_named);
954 mode_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
955
956 submodes_tree = lttv_attribute_find_subdir(mode_tree,
957 LTTV_STATS_SUBMODES);
958 mode_events_tree = lttv_attribute_find_subdir(mode_tree,
959 LTTV_STATS_EVENTS);
960 mode_types_tree = lttv_attribute_find_subdir(mode_tree,
961 LTTV_STATS_MODE_TYPES);
962
963 nb_submode = lttv_attribute_get_number(submodes_tree);
964
965 for(l = 0 ; l < nb_submode ; l++) {
966 type = lttv_attribute_get(submodes_tree, l, &name, &value,
967 &is_named);
968 submode_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
969
970 event_types_tree = lttv_attribute_find_subdir(submode_tree,
971 LTTV_STATS_EVENT_TYPES);
972 nb_event_type = lttv_attribute_get_number(event_types_tree);
973
974 sum = 0;
975 for(m = 0 ; m < nb_event_type ; m++) {
976 type = lttv_attribute_get(event_types_tree, m, &name, &value,
977 &is_named);
978 sum += *(value.v_uint);
979 }
980 lttv_attribute_find(submode_tree, LTTV_STATS_EVENTS_COUNT,
981 LTTV_UINT, &value);
982 *(value.v_uint) = sum;
983
984 type = lttv_attribute_get(submodes_tree, l, &name, &value,
985 &is_named);
986 submode_tree = LTTV_ATTRIBUTE(*(value.v_gobject));
987 if(!trace_is_summed) {
988 lttv_attribute_recursive_add(mode_events_tree, event_types_tree);
989 lttv_attribute_recursive_add(mode_types_tree, submode_tree);
990 }
991 }
992 if(!trace_is_summed) {
993 lttv_attribute_recursive_add(function_tree, mode_types_tree);
994 }
995 }
996 if(!trace_is_summed) {
997 lttv_attribute_recursive_add(cpu_tree, function_tree);
998 lttv_attribute_recursive_add(process_tree, function_tree);
999 lttv_attribute_recursive_add(trace_cpu_tree, function_tree);
1000 lttv_attribute_recursive_add(main_tree, function_tree);
1001 }
1002 lttv_attribute_recursive_add(ts_stats, function_tree);
1003 }
1004 }
1005 }
1006 }
1007
1008
1009 gboolean lttv_stats_sum_traceset_hook(void *hook_data, void *call_data)
1010 {
1011 struct sum_traceset_closure *closure =
1012 (struct sum_traceset_closure *)call_data;
1013 lttv_stats_sum_traceset(closure->tss, closure->current_time);
1014 return 0;
1015 }
1016
1017 void
1018 lttv_stats_sum_traceset(LttvTracesetStats *self, LttTime current_time)
1019 {
1020 LttvTraceset *traceset = self->parent.parent.ts;
1021 LttvAttribute *sum_container = self->stats;
1022
1023 LttvTraceStats *tcs;
1024
1025 int i, nb_trace;
1026
1027 LttvAttribute *main_tree;
1028
1029 LttvAttributeValue value;
1030
1031 lttv_attribute_find(sum_container, LTTV_STATS_SUMMED,
1032 LTTV_UINT, &value);
1033 if(*(value.v_uint) != 0) return;
1034 *(value.v_uint) = 1;
1035
1036 nb_trace = lttv_traceset_number(traceset);
1037
1038 for(i = 0 ; i < nb_trace ; i++) {
1039 tcs = (LttvTraceStats *)(self->parent.parent.traces[i]);
1040 lttv_stats_sum_trace(tcs, self->stats, current_time);
1041 // lttv_attribute_recursive_add(sum_container, tcs->stats);
1042 }
1043 }
1044
1045
1046 // Hook wrapper. call_data is a traceset context.
1047 gboolean lttv_stats_hook_add_event_hooks(void *hook_data, void *call_data)
1048 {
1049 LttvTracesetStats *tss = (LttvTracesetStats*)call_data;
1050
1051 lttv_stats_add_event_hooks(tss);
1052
1053 return 0;
1054 }
1055
1056 void lttv_stats_add_event_hooks(LttvTracesetStats *self)
1057 {
1058 LttvTraceset *traceset = self->parent.parent.ts;
1059
1060 guint i, j, k, l, nb_trace, nb_tracefile;
1061
1062 LttvTraceStats *ts;
1063
1064 LttvTracefileStats *tfs;
1065
1066 GArray *hooks, *before_hooks, *after_hooks;
1067
1068 LttvTraceHook *hook;
1069
1070 LttvTraceHookByFacility *thf;
1071
1072 LttvAttributeValue val;
1073
1074 gint ret;
1075 gint hn;
1076
1077 nb_trace = lttv_traceset_number(traceset);
1078 for(i = 0 ; i < nb_trace ; i++) {
1079 ts = (LttvTraceStats *)self->parent.parent.traces[i];
1080
1081 /* Find the eventtype id for the following events and register the
1082 associated by id hooks. */
1083
1084 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 12);
1085 g_array_set_size(hooks, 12);
1086 hn=0;
1087
1088 ret = lttv_trace_find_hook(ts->parent.parent.t,
1089 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1090 LTT_FIELD_SYSCALL_ID, 0, 0,
1091 before_syscall_entry, NULL,
1092 &g_array_index(hooks, LttvTraceHook, hn++));
1093 if(ret) hn--;
1094
1095 ret = lttv_trace_find_hook(ts->parent.parent.t,
1096 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1097 0, 0, 0,
1098 before_syscall_exit, NULL,
1099 &g_array_index(hooks, LttvTraceHook, hn++));
1100 if(ret) hn--;
1101
1102 ret = lttv_trace_find_hook(ts->parent.parent.t,
1103 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_ENTRY,
1104 LTT_FIELD_TRAP_ID, 0, 0,
1105 before_trap_entry, NULL,
1106 &g_array_index(hooks, LttvTraceHook, hn++));
1107 if(ret) hn--;
1108
1109 ret = lttv_trace_find_hook(ts->parent.parent.t,
1110 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_EXIT,
1111 0, 0, 0,
1112 before_trap_exit, NULL,
1113 &g_array_index(hooks, LttvTraceHook, hn++));
1114 if(ret) hn--;
1115
1116 ret = lttv_trace_find_hook(ts->parent.parent.t,
1117 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1118 LTT_FIELD_IRQ_ID, 0, 0,
1119 before_irq_entry, NULL,
1120 &g_array_index(hooks, LttvTraceHook, hn++));
1121 if(ret) hn--;
1122
1123 ret = lttv_trace_find_hook(ts->parent.parent.t,
1124 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1125 0, 0, 0,
1126 before_irq_exit, NULL,
1127 &g_array_index(hooks, LttvTraceHook, hn++));
1128 if(ret) hn--;
1129
1130 ret = lttv_trace_find_hook(ts->parent.parent.t,
1131 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1132 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1133 before_soft_irq_entry, NULL,
1134 &g_array_index(hooks, LttvTraceHook, hn++));
1135 if(ret) hn--;
1136
1137 ret = lttv_trace_find_hook(ts->parent.parent.t,
1138 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1139 0, 0, 0,
1140 before_soft_irq_exit, NULL,
1141 &g_array_index(hooks, LttvTraceHook, hn++));
1142 if(ret) hn--;
1143
1144 ret = lttv_trace_find_hook(ts->parent.parent.t,
1145 LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE,
1146 LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE,
1147 before_schedchange, NULL,
1148 &g_array_index(hooks, LttvTraceHook, hn++));
1149 if(ret) hn--;
1150
1151 ret = lttv_trace_find_hook(ts->parent.parent.t,
1152 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
1153 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1154 before_function_entry, NULL,
1155 &g_array_index(hooks, LttvTraceHook, hn++));
1156 if(ret) hn--;
1157
1158 ret = lttv_trace_find_hook(ts->parent.parent.t,
1159 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
1160 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1161 before_function_exit, NULL,
1162 &g_array_index(hooks, LttvTraceHook, hn++));
1163 if(ret) hn--;
1164
1165 /* statedump-related hooks */
1166 ret = lttv_trace_find_hook(ts->parent.parent.t,
1167 LTT_FACILITY_LIST, LTT_EVENT_PROCESS_STATE,
1168 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
1169 before_enum_process_state, NULL,
1170 &g_array_index(hooks, LttvTraceHook, hn++));
1171 if(ret) hn--;
1172
1173 g_array_set_size(hooks, hn);
1174
1175 before_hooks = hooks;
1176
1177 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 16);
1178 g_array_set_size(hooks, 16);
1179 hn=0;
1180
1181 ret = lttv_trace_find_hook(ts->parent.parent.t,
1182 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1183 LTT_FIELD_SYSCALL_ID, 0, 0,
1184 after_syscall_entry, NULL,
1185 &g_array_index(hooks, LttvTraceHook, hn++));
1186 if(ret) hn--;
1187
1188 ret = lttv_trace_find_hook(ts->parent.parent.t,
1189 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1190 0, 0, 0,
1191 after_syscall_exit, NULL,
1192 &g_array_index(hooks, LttvTraceHook, hn++));
1193 if(ret) hn--;
1194
1195 ret = lttv_trace_find_hook(ts->parent.parent.t,
1196 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_ENTRY,
1197 LTT_FIELD_TRAP_ID, 0, 0,
1198 after_trap_entry, NULL,
1199 &g_array_index(hooks, LttvTraceHook, hn++));
1200 if(ret) hn--;
1201
1202 ret = lttv_trace_find_hook(ts->parent.parent.t,
1203 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_EXIT,
1204 0, 0, 0,
1205 after_trap_exit, NULL,
1206 &g_array_index(hooks, LttvTraceHook, hn++));
1207 if(ret) hn--;
1208
1209 ret = lttv_trace_find_hook(ts->parent.parent.t,
1210 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1211 LTT_FIELD_IRQ_ID, 0, 0,
1212 after_irq_entry, NULL,
1213 &g_array_index(hooks, LttvTraceHook, hn++));
1214 if(ret) hn--;
1215
1216 ret = lttv_trace_find_hook(ts->parent.parent.t,
1217 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1218 0, 0, 0,
1219 after_irq_exit, NULL,
1220 &g_array_index(hooks, LttvTraceHook, hn++));
1221 if(ret) hn--;
1222
1223 ret = lttv_trace_find_hook(ts->parent.parent.t,
1224 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1225 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1226 after_irq_entry, NULL,
1227 &g_array_index(hooks, LttvTraceHook, hn++));
1228 if(ret) hn--;
1229
1230 ret = lttv_trace_find_hook(ts->parent.parent.t,
1231 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1232 0, 0, 0,
1233 after_soft_irq_exit, NULL,
1234 &g_array_index(hooks, LttvTraceHook, hn++));
1235 if(ret) hn--;
1236
1237 ret = lttv_trace_find_hook(ts->parent.parent.t,
1238 LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE,
1239 LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE,
1240 after_schedchange, NULL,
1241 &g_array_index(hooks, LttvTraceHook, hn++));
1242 if(ret) hn--;
1243
1244 ret = lttv_trace_find_hook(ts->parent.parent.t,
1245 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FORK,
1246 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1247 process_fork, NULL,
1248 &g_array_index(hooks, LttvTraceHook, hn++));
1249 if(ret) hn--;
1250
1251 ret = lttv_trace_find_hook(ts->parent.parent.t,
1252 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_EXIT,
1253 LTT_FIELD_PID, 0, 0,
1254 process_exit, NULL,
1255 &g_array_index(hooks, LttvTraceHook, hn++));
1256 if(ret) hn--;
1257
1258 ret = lttv_trace_find_hook(ts->parent.parent.t,
1259 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FREE,
1260 LTT_FIELD_PID, 0, 0,
1261 process_free, NULL,
1262 &g_array_index(hooks, LttvTraceHook, hn++));
1263 if(ret) hn--;
1264
1265 ret = lttv_trace_find_hook(ts->parent.parent.t,
1266 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
1267 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1268 after_function_entry, NULL,
1269 &g_array_index(hooks, LttvTraceHook, hn++));
1270 if(ret) hn--;
1271
1272 ret = lttv_trace_find_hook(ts->parent.parent.t,
1273 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
1274 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1275 after_function_exit, NULL,
1276 &g_array_index(hooks, LttvTraceHook, hn++));
1277 if(ret) hn--;
1278
1279 /* statedump-related hooks */
1280 ret = lttv_trace_find_hook(ts->parent.parent.t,
1281 LTT_FACILITY_LIST, LTT_EVENT_PROCESS_STATE,
1282 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
1283 after_enum_process_state, NULL,
1284 &g_array_index(hooks, LttvTraceHook, hn++));
1285 if(ret) hn--;
1286
1287 ret = lttv_trace_find_hook(ts->parent.parent.t,
1288 LTT_FACILITY_LIST, LTT_EVENT_STATEDUMP_END,
1289 0, 0, 0,
1290 after_statedump_end, NULL,
1291 &g_array_index(hooks, LttvTraceHook, hn++));
1292 if(ret) hn--;
1293
1294 g_array_set_size(hooks, hn);
1295
1296 after_hooks = hooks;
1297
1298 /* Add these hooks to each event_by_id hooks list */
1299
1300 nb_tracefile = ts->parent.parent.tracefiles->len;
1301
1302 for(j = 0 ; j < nb_tracefile ; j++) {
1303 tfs = LTTV_TRACEFILE_STATS(g_array_index(ts->parent.parent.tracefiles,
1304 LttvTracefileContext*, j));
1305 lttv_hooks_add(tfs->parent.parent.event, every_event, NULL,
1306 LTTV_PRIO_DEFAULT);
1307
1308 for(k = 0 ; k < before_hooks->len ; k++) {
1309 hook = &g_array_index(before_hooks, LttvTraceHook, k);
1310 for(l = 0; l<hook->fac_list->len;l++) {
1311 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1312 lttv_hooks_add(
1313 lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
1314 thf->h,
1315 thf,
1316 LTTV_PRIO_STATS_BEFORE_STATE);
1317 }
1318 }
1319 for(k = 0 ; k < after_hooks->len ; k++) {
1320 hook = &g_array_index(after_hooks, LttvTraceHook, k);
1321 for(l = 0; l<hook->fac_list->len;l++) {
1322 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1323 lttv_hooks_add(
1324 lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
1325 thf->h,
1326 thf,
1327 LTTV_PRIO_STATS_AFTER_STATE);
1328 }
1329 }
1330 }
1331 lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS,
1332 LTTV_POINTER, &val);
1333 *(val.v_pointer) = before_hooks;
1334 lttv_attribute_find(self->parent.parent.a, LTTV_STATS_AFTER_HOOKS,
1335 LTTV_POINTER, &val);
1336 *(val.v_pointer) = after_hooks;
1337 }
1338 }
1339
1340 // Hook wrapper. call_data is a traceset context.
1341 gboolean lttv_stats_hook_remove_event_hooks(void *hook_data, void *call_data)
1342 {
1343 LttvTracesetStats *tss = (LttvTracesetStats*)call_data;
1344
1345 lttv_stats_remove_event_hooks(tss);
1346
1347 return 0;
1348 }
1349
1350 void lttv_stats_remove_event_hooks(LttvTracesetStats *self)
1351 {
1352 LttvTraceset *traceset = self->parent.parent.ts;
1353
1354 guint i, j, k, l, nb_trace, nb_tracefile;
1355
1356 LttvTraceStats *ts;
1357
1358 LttvTracefileStats *tfs;
1359
1360 void *hook_data;
1361
1362 GArray *before_hooks, *after_hooks;
1363
1364 LttvTraceHook *hook;
1365
1366 LttvTraceHookByFacility *thf;
1367
1368 LttvAttributeValue val;
1369
1370 nb_trace = lttv_traceset_number(traceset);
1371 for(i = 0 ; i < nb_trace ; i++) {
1372 ts = (LttvTraceStats*)self->parent.parent.traces[i];
1373 lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS,
1374 LTTV_POINTER, &val);
1375 before_hooks = *(val.v_pointer);
1376 lttv_attribute_find(self->parent.parent.a, LTTV_STATS_AFTER_HOOKS,
1377 LTTV_POINTER, &val);
1378 after_hooks = *(val.v_pointer);
1379
1380 /* Remove these hooks from each event_by_id hooks list */
1381
1382 nb_tracefile = ts->parent.parent.tracefiles->len;
1383
1384 for(j = 0 ; j < nb_tracefile ; j++) {
1385 tfs = LTTV_TRACEFILE_STATS(g_array_index(ts->parent.parent.tracefiles,
1386 LttvTracefileContext*, j));
1387 lttv_hooks_remove_data(tfs->parent.parent.event, every_event,
1388 NULL);
1389
1390 for(k = 0 ; k < before_hooks->len ; k++) {
1391 hook = &g_array_index(before_hooks, LttvTraceHook, k);
1392 for(l = 0 ; l < hook->fac_list->len ; l++) {
1393 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1394 lttv_hooks_remove_data(
1395 lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
1396 thf->h,
1397 thf);
1398 }
1399 }
1400 for(k = 0 ; k < after_hooks->len ; k++) {
1401 hook = &g_array_index(after_hooks, LttvTraceHook, k);
1402 for(l = 0 ; l < hook->fac_list->len ; l++) {
1403 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1404 lttv_hooks_remove_data(
1405 lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
1406 thf->h,
1407 thf);
1408 }
1409 }
1410 }
1411 g_debug("lttv_stats_remove_event_hooks()");
1412 g_array_free(before_hooks, TRUE);
1413 g_array_free(after_hooks, TRUE);
1414 }
1415 }
1416
1417
1418 static void module_init()
1419 {
1420 LTTV_STATS_PROCESS_UNKNOWN = g_quark_from_string("unknown process");
1421 LTTV_STATS_PROCESSES = g_quark_from_string("processes");
1422 LTTV_STATS_CPU = g_quark_from_string("cpu");
1423 LTTV_STATS_MODE_TYPES = g_quark_from_string("mode_types");
1424 LTTV_STATS_MODES = g_quark_from_string("modes");
1425 LTTV_STATS_SUBMODES = g_quark_from_string("submodes");
1426 LTTV_STATS_FUNCTIONS = g_quark_from_string("functions");
1427 LTTV_STATS_EVENT_TYPES = g_quark_from_string("event_types");
1428 LTTV_STATS_CPU_TIME = g_quark_from_string("cpu time");
1429 LTTV_STATS_CUMULATIVE_CPU_TIME = g_quark_from_string("cumulative cpu time (includes nested routines and modes)");
1430 LTTV_STATS_ELAPSED_TIME = g_quark_from_string("elapsed time (includes per process waiting time)");
1431 LTTV_STATS_EVENTS = g_quark_from_string("events");
1432 LTTV_STATS_EVENTS_COUNT = g_quark_from_string("events count");
1433 LTTV_STATS_BEFORE_HOOKS = g_quark_from_string("saved stats before hooks");
1434 LTTV_STATS_AFTER_HOOKS = g_quark_from_string("saved stats after hooks");
1435 LTTV_STATS_USE_COUNT = g_quark_from_string("stats_use_count");
1436 LTTV_STATS = g_quark_from_string("statistics");
1437 LTTV_STATS_TRACEFILES = g_quark_from_string("tracefiles statistics");
1438 LTTV_STATS_SUMMED = g_quark_from_string("statistics summed");
1439 }
1440
1441 static void module_destroy()
1442 {
1443 }
1444
1445
1446 LTTV_MODULE("stats", "Compute processes statistics", \
1447 "Accumulate statistics for event types, processes and CPUs", \
1448 module_init, module_destroy, "state");
1449
1450 /* Change the places where stats are called (create/read/write stats)
1451
1452 Check for options in batchtest.c to reduce writing and see what tests are
1453 best candidates for performance analysis. Once OK, commit, move to main
1454 and run tests. Update the gui for statistics. */
This page took 0.075086 seconds and 4 git commands to generate.