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