Add a module to compute various statistics
[lttv.git] / ltt / branches / poly / lttv / processTrace.c
1
2 #include <lttv/processTrace.h>
3 #include <ltt/event.h>
4 #include <ltt/facility.h>
5
6 void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
7 {
8 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
9 }
10
11
12 void lttv_context_fini(LttvTracesetContext *self)
13 {
14 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
15 }
16
17
18 LttvTracesetContext *
19 lttv_context_new_traceset_context(LttvTracesetContext *self)
20 {
21 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
22 }
23
24
25
26
27 LttvTraceContext *
28 lttv_context_new_trace_context(LttvTracesetContext *self)
29 {
30 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
31 }
32
33
34 LttvTracefileContext *
35 lttv_context_new_tracefile_context(LttvTracesetContext *self)
36 {
37 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
38 }
39
40
41 static void
42 init(LttvTracesetContext *self, LttvTraceset *ts)
43 {
44 guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile;
45
46 LttvTraceContext *tc;
47
48 LttvTracefileContext *tfc;
49
50 nb_trace = lttv_traceset_number(ts);
51 self->ts = ts;
52 self->traces = g_new(LttvTraceContext *, nb_trace);
53 self->before = lttv_hooks_new();
54 self->after = lttv_hooks_new();
55 self->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
56 for(i = 0 ; i < nb_trace ; i++) {
57 tc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
58 self->traces[i] = tc;
59
60 tc->ts_context = self;
61 tc->index = i;
62 tc->t = lttv_traceset_get(ts, i);
63 tc->check = lttv_hooks_new();
64 tc->before = lttv_hooks_new();
65 tc->after = lttv_hooks_new();
66 tc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
67 nb_control = ltt_trace_control_tracefile_number(tc->t);
68 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
69 nb_tracefile = nb_control + nb_per_cpu;
70 tc->control_tracefiles = g_new(LttvTracefileContext *, nb_control);
71 tc->per_cpu_tracefiles = g_new(LttvTracefileContext *, nb_per_cpu);
72
73 for(j = 0 ; j < nb_tracefile ; j++) {
74 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
75 if(j < nb_control) {
76 tc->control_tracefiles[j] = tfc;
77 tfc->control = TRUE;
78 tfc->index = j;
79 tfc->tf = ltt_trace_control_tracefile_get(tc->t, j);
80 }
81 else {
82 tc->per_cpu_tracefiles[j - nb_control] = tfc;
83 tfc->control = FALSE;
84 tfc->index = j - nb_control;
85 tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
86 }
87 tfc->t_context = tc;
88 tfc->check = lttv_hooks_new();
89 tfc->before = lttv_hooks_new();
90 tfc->after = lttv_hooks_new();
91 tfc->check_event = lttv_hooks_new();
92 tfc->before_event = lttv_hooks_new();
93 tfc->before_event_by_id = lttv_hooks_by_id_new();
94 tfc->after_event = lttv_hooks_new();
95 tfc->after_event_by_id = lttv_hooks_by_id_new();
96 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
97 }
98 }
99 }
100
101
102 void fini(LttvTracesetContext *self)
103 {
104 guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile;
105
106 LttvTraceContext *tc;
107
108 LttvTracefileContext *tfc;
109
110 LttvTraceset *ts = self->ts;
111
112 lttv_hooks_destroy(self->before);
113 lttv_hooks_destroy(self->after);
114 g_object_unref(self->a);
115
116 nb_trace = lttv_traceset_number(ts);
117
118 for(i = 0 ; i < nb_trace ; i++) {
119 tc = self->traces[i];
120
121 lttv_hooks_destroy(tc->check);
122 lttv_hooks_destroy(tc->before);
123 lttv_hooks_destroy(tc->after);
124 g_object_unref(tc->a);
125
126 nb_control = ltt_trace_control_tracefile_number(tc->t);
127 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
128 nb_tracefile = nb_control + nb_per_cpu;
129
130 for(j = 0 ; j < nb_tracefile ; j++) {
131 if(j < nb_control) tfc = tc->control_tracefiles[j];
132 else tfc = tc->per_cpu_tracefiles[j - nb_control];
133
134 lttv_hooks_destroy(tfc->check);
135 lttv_hooks_destroy(tfc->before);
136 lttv_hooks_destroy(tfc->after);
137 lttv_hooks_destroy(tfc->check_event);
138 lttv_hooks_destroy(tfc->before_event);
139 lttv_hooks_by_id_destroy(tfc->before_event_by_id);
140 lttv_hooks_destroy(tfc->after_event);
141 lttv_hooks_by_id_destroy(tfc->after_event_by_id);
142 g_object_unref(tfc->a);
143 g_object_unref(tfc);
144 }
145 g_free(tc->control_tracefiles);
146 g_free(tc->per_cpu_tracefiles);
147 g_object_unref(tc);
148 }
149 g_free(self->traces);
150 }
151
152
153 void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
154 LttvHooks *before_traceset,
155 LttvHooks *after_traceset,
156 LttvHooks *check_trace,
157 LttvHooks *before_trace,
158 LttvHooks *after_trace,
159 LttvHooks *check_tracefile,
160 LttvHooks *before_tracefile,
161 LttvHooks *after_tracefile,
162 LttvHooks *check_event,
163 LttvHooks *before_event,
164 LttvHooks *after_event)
165 {
166 LttvTraceset *ts = self->ts;
167
168 guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile;
169
170 LttvTraceContext *tc;
171
172 LttvTracefileContext *tfc;
173
174 void *hook_data;
175
176 lttv_hooks_add_list(self->before, before_traceset);
177 lttv_hooks_add_list(self->after, after_traceset);
178 nb_trace = lttv_traceset_number(ts);
179
180 for(i = 0 ; i < nb_trace ; i++) {
181 tc = self->traces[i];
182 lttv_hooks_add_list(tc->check, check_trace);
183 lttv_hooks_add_list(tc->before, before_trace);
184 lttv_hooks_add_list(tc->after, after_trace);
185 nb_control = ltt_trace_control_tracefile_number(tc->t);
186 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
187 nb_tracefile = nb_control + nb_per_cpu;
188
189 for(j = 0 ; j < nb_tracefile ; j++) {
190 if(j < nb_control) {
191 tfc = tc->control_tracefiles[j];
192 }
193 else {
194 tfc = tc->per_cpu_tracefiles[j-nb_control];
195 }
196 lttv_hooks_add_list(tfc->check, check_tracefile);
197 lttv_hooks_add_list(tfc->before, before_tracefile);
198 lttv_hooks_add_list(tfc->after, after_tracefile);
199 lttv_hooks_add_list(tfc->check_event, check_event);
200 lttv_hooks_add_list(tfc->before_event, before_event);
201 lttv_hooks_add_list(tfc->after_event, after_event);
202 }
203 }
204 }
205
206
207 void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
208 LttvHooks *before_traceset,
209 LttvHooks *after_traceset,
210 LttvHooks *check_trace,
211 LttvHooks *before_trace,
212 LttvHooks *after_trace,
213 LttvHooks *check_tracefile,
214 LttvHooks *before_tracefile,
215 LttvHooks *after_tracefile,
216 LttvHooks *check_event,
217 LttvHooks *before_event,
218 LttvHooks *after_event)
219 {
220 LttvTraceset *ts = self->ts;
221
222 guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile;
223
224 LttvTraceContext *tc;
225
226 LttvTracefileContext *tfc;
227
228 void *hook_data;
229
230 lttv_hooks_remove_list(self->before, before_traceset);
231 lttv_hooks_remove_list(self->after, after_traceset);
232 nb_trace = lttv_traceset_number(ts);
233
234 for(i = 0 ; i < nb_trace ; i++) {
235 tc = self->traces[i];
236 lttv_hooks_remove_list(tc->check, check_trace);
237 lttv_hooks_remove_list(tc->before, before_trace);
238 lttv_hooks_remove_list(tc->after, after_trace);
239 nb_control = ltt_trace_control_tracefile_number(tc->t);
240 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
241 nb_tracefile = nb_control + nb_per_cpu;
242
243 for(j = 0 ; j < nb_tracefile ; j++) {
244 if(j < nb_control) {
245 tfc = tc->control_tracefiles[j];
246 }
247 else {
248 tfc = tc->per_cpu_tracefiles[j-nb_control];
249 }
250 lttv_hooks_remove_list(tfc->check, check_tracefile);
251 lttv_hooks_remove_list(tfc->before, before_tracefile);
252 lttv_hooks_remove_list(tfc->after, after_tracefile);
253 lttv_hooks_remove_list(tfc->check_event, check_event);
254 lttv_hooks_remove_list(tfc->before_event, before_event);
255 lttv_hooks_remove_list(tfc->after_event, after_event);
256 }
257 }
258 }
259
260
261 static LttvTracesetContext *
262 new_traceset_context(LttvTracesetContext *self)
263 {
264 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
265 }
266
267
268 static LttvTraceContext *
269 new_trace_context(LttvTracesetContext *self)
270 {
271 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
272 }
273
274
275 static LttvTracefileContext *
276 new_tracefile_context(LttvTracesetContext *self)
277 {
278 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
279 }
280
281
282 static void
283 traceset_context_instance_init (GTypeInstance *instance, gpointer g_class)
284 {
285 /* Be careful of anything which would not work well with shallow copies */
286 }
287
288
289 static void
290 traceset_context_finalize (LttvTracesetContext *self)
291 {
292 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE)))
293 ->finalize(G_OBJECT(self));
294 }
295
296
297 static void
298 traceset_context_class_init (LttvTracesetContextClass *klass)
299 {
300 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
301
302 gobject_class->finalize = (void (*)(GObject *self))traceset_context_finalize;
303 klass->init = init;
304 klass->fini = fini;
305 klass->new_traceset_context = new_traceset_context;
306 klass->new_trace_context = new_trace_context;
307 klass->new_tracefile_context = new_tracefile_context;
308 }
309
310
311 GType
312 lttv_traceset_context_get_type(void)
313 {
314 static GType type = 0;
315 if (type == 0) {
316 static const GTypeInfo info = {
317 sizeof (LttvTracesetContextClass),
318 NULL, /* base_init */
319 NULL, /* base_finalize */
320 (GClassInitFunc) traceset_context_class_init, /* class_init */
321 NULL, /* class_finalize */
322 NULL, /* class_data */
323 sizeof (LttvTracesetContext),
324 0, /* n_preallocs */
325 (GInstanceInitFunc) traceset_context_instance_init /* instance_init */
326 };
327
328 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType",
329 &info, 0);
330 }
331 return type;
332 }
333
334
335 static void
336 trace_context_instance_init (GTypeInstance *instance, gpointer g_class)
337 {
338 /* Be careful of anything which would not work well with shallow copies */
339 }
340
341
342 static void
343 trace_context_finalize (LttvTraceContext *self)
344 {
345 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))->
346 finalize(G_OBJECT(self));
347 }
348
349
350 static void
351 trace_context_class_init (LttvTraceContextClass *klass)
352 {
353 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
354
355 gobject_class->finalize = (void (*)(GObject *self)) trace_context_finalize;
356 }
357
358
359 GType
360 lttv_trace_context_get_type(void)
361 {
362 static GType type = 0;
363 if (type == 0) {
364 static const GTypeInfo info = {
365 sizeof (LttvTraceContextClass),
366 NULL, /* base_init */
367 NULL, /* base_finalize */
368 (GClassInitFunc) trace_context_class_init, /* class_init */
369 NULL, /* class_finalize */
370 NULL, /* class_data */
371 sizeof (LttvTraceContext),
372 0, /* n_preallocs */
373 (GInstanceInitFunc) trace_context_instance_init /* instance_init */
374 };
375
376 type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType",
377 &info, 0);
378 }
379 return type;
380 }
381
382
383 static void
384 tracefile_context_instance_init (GTypeInstance *instance, gpointer g_class)
385 {
386 /* Be careful of anything which would not work well with shallow copies */
387 }
388
389
390 static void
391 tracefile_context_finalize (LttvTracefileContext *self)
392 {
393 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE)))
394 ->finalize(G_OBJECT(self));
395 }
396
397
398 static void
399 tracefile_context_class_init (LttvTracefileContextClass *klass)
400 {
401 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
402
403 gobject_class->finalize = (void (*)(GObject *self))tracefile_context_finalize;
404 }
405
406
407 GType
408 lttv_tracefile_context_get_type(void)
409 {
410 static GType type = 0;
411 if (type == 0) {
412 static const GTypeInfo info = {
413 sizeof (LttvTracefileContextClass),
414 NULL, /* base_init */
415 NULL, /* base_finalize */
416 (GClassInitFunc) tracefile_context_class_init, /* class_init */
417 NULL, /* class_finalize */
418 NULL, /* class_data */
419 sizeof (LttvTracefileContext),
420 0, /* n_preallocs */
421 (GInstanceInitFunc) tracefile_context_instance_init /* instance_init */
422 };
423
424 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType",
425 &info, 0);
426 }
427 return type;
428 }
429
430
431 gint compare_tracefile(gconstpointer a, gconstpointer b)
432 {
433 if(((LttvTime *)a)->tv_sec > ((LttvTime *)b)->tv_sec) return 1;
434 if(((LttvTime *)a)->tv_sec < ((LttvTime *)b)->tv_sec) return -1;
435 if(((LttvTime *)a)->tv_nsec > ((LttvTime *)b)->tv_nsec) return 1;
436 if(((LttvTime *)a)->tv_nsec < ((LttvTime *)b)->tv_nsec) return -1;
437 return 0;
438 }
439
440
441 gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
442 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
443 return TRUE;
444 }
445
446
447 void lttv_process_trace(LttTime start, LttTime end, LttvTraceset *traceset,
448 LttvTracesetContext *context, unsigned maxNumEvents)
449 {
450 GPtrArray *traces = g_ptr_array_new();
451
452 GPtrArray *tracefiles = g_ptr_array_new();
453
454 GTree *pqueue = g_tree_new(compare_tracefile);
455
456 guint i, j, nbi, nbj, id, nb_control, nb_cpu;
457
458 LttTrace *trace;
459
460 LttvTraceContext *tc;
461
462 LttTracefile *tracefile;
463
464 LttvTracefileContext *tfc;
465
466 LttEvent *event;
467 unsigned count = 0;
468 LttTime preTimestamp;
469
470 /* Call all before_traceset, before_trace, and before_tracefile hooks.
471 For all qualifying tracefiles, seek to the start time, create a context,
472 read one event and insert in the pqueue based on the event time. */
473
474 lttv_hooks_call(context->before, context);
475 nbi = lttv_traceset_number(traceset);
476 // nbi = ltt_trace_set_number(traceset);
477
478 for(i = 0 ; i < nbi ; i++) {
479 tc = context->traces[i];
480 trace = tc->t;
481
482 if(!lttv_hooks_call_check(tc->check, tc)) {
483 g_ptr_array_add(traces, tc);
484 lttv_hooks_call(tc->before, tc);
485 nb_control = ltt_trace_control_tracefile_number(trace);
486 nb_cpu = ltt_trace_per_cpu_tracefile_number(trace);
487 nbj = nb_control + nb_cpu;
488
489 for(j = 0 ; j < nbj ; j++) {
490 if(j < nb_control) {
491 tfc = tc->control_tracefiles[j];
492 }
493 else {
494 tfc = tc->per_cpu_tracefiles[j - nb_control];
495 }
496
497 tracefile = tfc->tf;
498
499 if(!lttv_hooks_call_check(tfc->check, tfc)) {
500 g_ptr_array_add(tracefiles, tfc);
501 lttv_hooks_call(tfc->before, tfc);
502
503 ltt_tracefile_seek_time(tracefile, start);
504 event = ltt_tracefile_read(tracefile);
505 tfc->e = event;
506
507 if(event != NULL) {
508 tfc->timestamp = ltt_event_time(event);
509 g_tree_insert(pqueue, &(tfc->timestamp), tfc);
510 }
511 }
512 }
513 }
514 }
515
516 /* Get the next event from the pqueue, call its hooks,
517 reinsert in the pqueue the following event from the same tracefile
518 unless the tracefile is finished or the event is later than the
519 start time. */
520
521 while(TRUE) {
522 tfc = NULL;
523 g_tree_foreach(pqueue, get_first, &tfc);
524 if(tfc == NULL) break;
525
526 /* Get the tracefile with an event for the smallest time found. If two
527 or more tracefiles have events for the same time, hope that lookup
528 and remove are consistent. */
529
530 count++;
531 if(count > maxNumEvents){
532 if(tfc->timestamp.tv_sec == preTimestamp.tv_sec &&
533 tfc->timestamp.tv_nsec == preTimestamp.tv_nsec) {
534 count--;
535 }else{
536 while(TRUE){
537 tfc = NULL;
538 g_tree_foreach(pqueue, get_first, &tfc);
539 if(tfc == NULL) break;
540 g_tree_remove(pqueue, &(tfc->timestamp));
541 }
542 break;
543 }
544 }
545 preTimestamp = tfc->timestamp;
546
547 tfc = g_tree_lookup(pqueue, &(tfc->timestamp));
548 g_tree_remove(pqueue, &(tfc->timestamp));
549
550 if(!lttv_hooks_call(tfc->check_event, tfc)) {
551 id = ltt_event_eventtype_id(tfc->e);
552 lttv_hooks_call(tfc->before_event, tfc);
553 lttv_hooks_call(lttv_hooks_by_id_get(tfc->before_event_by_id, id), tfc);
554 lttv_hooks_call(tfc->after_event, tfc);
555 lttv_hooks_call(lttv_hooks_by_id_get(tfc->after_event_by_id, id), tfc);
556 }
557
558 event = ltt_tracefile_read(tfc->tf);
559 if(event != NULL) {
560 tfc->e = event;
561 tfc->timestamp = ltt_event_time(event);
562 if(tfc->timestamp.tv_sec < end.tv_sec ||
563 (tfc->timestamp.tv_sec == end.tv_sec && tfc->timestamp.tv_nsec <= end.tv_nsec))
564 g_tree_insert(pqueue, &(tfc->timestamp), tfc);
565 }
566 }
567
568 /* Call all the after_tracefile, after_trace and after_traceset hooks. */
569
570 for(i = 0, j = 0 ; i < traces->len ; i++) {
571 tc = traces->pdata[i];
572 while(j < tracefiles->len) {
573 tfc = tracefiles->pdata[j];
574
575 if(tfc->t_context == tc) {
576 lttv_hooks_call(tfc->after, tfc);
577 j++;
578 }
579 else break;
580 }
581 lttv_hooks_call(tc->after, tc);
582 }
583
584 g_assert(j == tracefiles->len);
585 lttv_hooks_call(context->after, context);
586
587 /* Free the traces, tracefiles and pqueue */
588
589 g_ptr_array_free(tracefiles, TRUE);
590 g_ptr_array_free(traces, TRUE);
591 g_tree_destroy(pqueue);
592 }
593
594 static LttField *
595 find_field(LttEventType *et, const char *field)
596 {
597 LttType *t;
598
599 LttField *f;
600
601 guint i, nb;
602
603 char *name;
604
605 if(field == NULL) return NULL;
606
607 f = ltt_eventtype_field(et);
608 t = ltt_eventtype_type(et);
609 g_assert(ltt_type_class(t) == LTT_STRUCT);
610 nb = ltt_type_member_number(t);
611 for(i = 0 ; i < nb ; i++) {
612 ltt_type_member_type(t, i, &name);
613 if(strcmp(name, field) == 0) break;
614 }
615 g_assert(i < nb);
616 return ltt_field_member(f, i);
617 }
618
619
620 void
621 lttv_trace_find_hook(LttTrace *t, char *facility, char *event_type,
622 char *field1, char *field2, char *field3, LttvHook h, LttvTraceHook *th)
623 {
624 LttFacility *f;
625
626 LttEventType *et;
627
628 guint nb, pos, i;
629
630 char *name;
631
632 nb = ltt_trace_facility_find(t, facility, &pos);
633 if(nb < 1) g_error("No %s facility", facility);
634 f = ltt_trace_facility_get(t, pos);
635 et = ltt_facility_eventtype_get_by_name(f, event_type);
636 if(et == NULL) g_error("Event %s does not exist", event_type);
637
638 th->h = h;
639 th->id = ltt_eventtype_id(et);
640 th->f1 = find_field(et, field1);
641 th->f2 = find_field(et, field2);
642 th->f3 = find_field(et, field3);
643 }
644
645
This page took 0.042164 seconds and 4 git commands to generate.