mega fix for states : per cpu and _not_ per tracefile state. We have many tracefiles...
[lttv.git] / ltt / branches / poly / lttv / lttv / tracecontext.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 <string.h>
24 #include <lttv/tracecontext.h>
25 #include <ltt/event.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/type.h>
29 #include <errno.h>
30
31
32
33
34 gint compare_tracefile(gconstpointer a, gconstpointer b)
35 {
36 gint comparison = 0;
37
38 const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
39 const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
40
41 if(likely(trace_a != trace_b)) {
42 comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
43 if(unlikely(comparison == 0)) {
44 if(trace_a->index < trace_b->index) comparison = -1;
45 else if(trace_a->index > trace_b->index) comparison = 1;
46 else if(trace_a->t_context->index < trace_b->t_context->index)
47 comparison = -1;
48 else if(trace_a->t_context->index > trace_b->t_context->index)
49 comparison = 1;
50 }
51 }
52 return comparison;
53 }
54
55 struct _LttvTracesetContextPosition {
56 GArray *ep; /* Array of LttEventPosition */
57 GArray *tfc; /* Array of corresponding
58 TracefileContext* */
59 LttTime timestamp; /* Current time at the saved position */
60 /* If ltt_time_infinite : no position is
61 * set, else, a position is set (may be end
62 * of trace, with ep->len == 0) */
63 };
64
65 void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
66 {
67 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
68 }
69
70
71 void lttv_context_fini(LttvTracesetContext *self)
72 {
73 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
74 }
75
76
77 LttvTracesetContext *
78 lttv_context_new_traceset_context(LttvTracesetContext *self)
79 {
80 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
81 }
82
83
84
85
86 LttvTraceContext *
87 lttv_context_new_trace_context(LttvTracesetContext *self)
88 {
89 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
90 }
91
92
93 LttvTracefileContext *
94 lttv_context_new_tracefile_context(LttvTracesetContext *self)
95 {
96 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
97 }
98
99 /****************************************************************************
100 * lttv_traceset_context_compute_time_span
101 *
102 * Keep the time span is sync with on the fly addition and removal of traces
103 * in a trace set. It must be called each time a trace is added/removed from
104 * the traceset. It could be more efficient to call it only once a bunch
105 * of traces are loaded, but the calculation is not long, so it's not
106 * critical.
107 *
108 * Author : Xang Xiu Yang
109 ***************************************************************************/
110 static void lttv_traceset_context_compute_time_span(
111 LttvTracesetContext *self,
112 TimeInterval *time_span)
113 {
114 LttvTraceset * traceset = self->ts;
115 int numTraces = lttv_traceset_number(traceset);
116 int i;
117 LttTime s, e;
118 LttvTraceContext *tc;
119 LttTrace * trace;
120
121 time_span->start_time.tv_sec = 0;
122 time_span->start_time.tv_nsec = 0;
123 time_span->end_time.tv_sec = 0;
124 time_span->end_time.tv_nsec = 0;
125
126 for(i=0; i<numTraces;i++){
127 tc = self->traces[i];
128 trace = tc->t;
129
130 ltt_trace_time_span_get(trace, &s, &e);
131
132 if(i==0){
133 time_span->start_time = s;
134 time_span->end_time = e;
135 }else{
136 if(s.tv_sec < time_span->start_time.tv_sec
137 || (s.tv_sec == time_span->start_time.tv_sec
138 && s.tv_nsec < time_span->start_time.tv_nsec))
139 time_span->start_time = s;
140 if(e.tv_sec > time_span->end_time.tv_sec
141 || (e.tv_sec == time_span->end_time.tv_sec
142 && e.tv_nsec > time_span->end_time.tv_nsec))
143 time_span->end_time = e;
144 }
145 }
146 }
147
148 static void init_tracefile_context(LttTracefile *tracefile,
149 LttvTraceContext *tc)
150 {
151 LttvTracefileContext *tfc;
152 LttvTracesetContext *tsc = tc->ts_context;
153
154 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(tsc)->new_tracefile_context(tsc);
155
156 tfc->index = tc->tracefiles->len;
157 tc->tracefiles = g_array_append_val(tc->tracefiles, tfc);
158
159 tfc->tf = tracefile;
160
161 tfc->t_context = tc;
162 tfc->event = lttv_hooks_new();
163 tfc->event_by_id = lttv_hooks_by_id_new();
164 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
165 }
166
167
168 static void
169 init(LttvTracesetContext *self, LttvTraceset *ts)
170 {
171 guint i, nb_trace;
172
173 LttvTraceContext *tc;
174
175 GData **tracefiles_groups;
176
177 struct compute_tracefile_group_args args;
178
179 nb_trace = lttv_traceset_number(ts);
180 self->ts = ts;
181 self->traces = g_new(LttvTraceContext *, nb_trace);
182 self->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
183 self->ts_a = lttv_traceset_attribute(ts);
184 self->sync_position = lttv_traceset_context_position_new();
185 for(i = 0 ; i < nb_trace ; i++) {
186 tc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
187 self->traces[i] = tc;
188
189 tc->ts_context = self;
190 tc->index = i;
191 tc->vt = lttv_traceset_get(ts, i);
192 tc->t = lttv_trace(tc->vt);
193 tc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
194 tc->t_a = lttv_trace_attribute(tc->vt);
195 tc->tracefiles = g_array_sized_new(FALSE, TRUE,
196 sizeof(LttvTracefileContext*), 10);
197
198 tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t);
199 if(tracefiles_groups != NULL) {
200 args.func = (ForEachTraceFileFunc)init_tracefile_context;
201 args.func_args = tc;
202
203 g_datalist_foreach(tracefiles_groups,
204 (GDataForeachFunc)compute_tracefile_group,
205 &args);
206 }
207
208 #if 0
209 nb_control = ltt_trace_control_tracefile_number(tc->t);
210 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
211 nb_tracefile = nb_control + nb_per_cpu;
212 tc->tracefiles = g_new(LttvTracefileContext *, nb_tracefile);
213
214 for(j = 0 ; j < nb_tracefile ; j++) {
215 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
216 tc->tracefiles[j] = tfc;
217 tfc->index = j;
218
219 if(j < nb_control) {
220 tfc->control = TRUE;
221 tfc->tf = ltt_trace_control_tracefile_get(tc->t, j);
222 }
223 else {
224 tfc->control = FALSE;
225 tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
226 }
227
228 tfc->t_context = tc;
229 tfc->e = ltt_event_new();
230 tfc->event = lttv_hooks_new();
231 tfc->event_by_id = lttv_hooks_by_id_new();
232 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
233 }
234 #endif //0
235
236 }
237 self->pqueue = g_tree_new(compare_tracefile);
238 lttv_process_traceset_seek_time(self, ltt_time_zero);
239 lttv_traceset_context_compute_time_span(self, &self->time_span);
240
241 }
242
243
244 void fini(LttvTracesetContext *self)
245 {
246 guint i, j, nb_trace, nb_tracefile;
247
248 LttvTraceContext *tc;
249
250 LttvTracefileContext **tfc;
251
252 LttvTraceset *ts = self->ts;
253
254 g_tree_destroy(self->pqueue);
255 g_object_unref(self->a);
256 lttv_traceset_context_position_destroy(self->sync_position);
257
258 nb_trace = lttv_traceset_number(ts);
259
260 for(i = 0 ; i < nb_trace ; i++) {
261 tc = self->traces[i];
262
263 g_object_unref(tc->a);
264
265 nb_tracefile = tc->tracefiles->len;
266
267 for(j = 0 ; j < nb_tracefile ; j++) {
268 tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, j);
269 lttv_hooks_destroy((*tfc)->event);
270 lttv_hooks_by_id_destroy((*tfc)->event_by_id);
271 g_object_unref((*tfc)->a);
272 g_object_unref(*tfc);
273 }
274 g_array_free(tc->tracefiles, TRUE);
275 g_object_unref(tc);
276 }
277 g_free(self->traces);
278 }
279
280
281 void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
282 LttvHooks *before_traceset,
283 LttvHooks *before_trace,
284 LttvHooks *before_tracefile,
285 LttvHooks *event,
286 LttvHooksById *event_by_id)
287 {
288 LttvTraceset *ts = self->ts;
289
290 guint i, nb_trace;
291
292 LttvTraceContext *tc;
293
294 lttv_hooks_call(before_traceset, self);
295
296 nb_trace = lttv_traceset_number(ts);
297
298 for(i = 0 ; i < nb_trace ; i++) {
299 tc = self->traces[i];
300 lttv_trace_context_add_hooks(tc,
301 before_trace,
302 before_tracefile,
303 event,
304 event_by_id);
305 }
306 }
307
308
309 void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
310 LttvHooks *after_traceset,
311 LttvHooks *after_trace,
312 LttvHooks *after_tracefile,
313 LttvHooks *event,
314 LttvHooksById *event_by_id)
315 {
316
317 LttvTraceset *ts = self->ts;
318
319 guint i, nb_trace;
320
321 LttvTraceContext *tc;
322
323 nb_trace = lttv_traceset_number(ts);
324
325 for(i = 0 ; i < nb_trace ; i++) {
326 tc = self->traces[i];
327 lttv_trace_context_remove_hooks(tc,
328 after_trace,
329 after_tracefile,
330 event,
331 event_by_id);
332 }
333
334 lttv_hooks_call(after_traceset, self);
335
336
337 }
338
339 void lttv_trace_context_add_hooks(LttvTraceContext *self,
340 LttvHooks *before_trace,
341 LttvHooks *before_tracefile,
342 LttvHooks *event,
343 LttvHooksById *event_by_id)
344 {
345 guint i, nb_tracefile;
346
347 LttvTracefileContext **tfc;
348
349 lttv_hooks_call(before_trace, self);
350
351 nb_tracefile = self->tracefiles->len;
352
353 for(i = 0 ; i < nb_tracefile ; i++) {
354 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
355 lttv_tracefile_context_add_hooks(*tfc,
356 before_tracefile,
357 event,
358 event_by_id);
359 }
360 }
361
362
363
364 void lttv_trace_context_remove_hooks(LttvTraceContext *self,
365 LttvHooks *after_trace,
366 LttvHooks *after_tracefile,
367 LttvHooks *event,
368 LttvHooksById *event_by_id)
369 {
370 guint i, nb_tracefile;
371
372 LttvTracefileContext **tfc;
373
374 nb_tracefile = self->tracefiles->len;
375
376 for(i = 0 ; i < nb_tracefile ; i++) {
377 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
378 lttv_tracefile_context_remove_hooks(*tfc,
379 after_tracefile,
380 event,
381 event_by_id);
382 }
383
384 lttv_hooks_call(after_trace, self);
385 }
386
387 void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
388 LttvHooks *before_tracefile,
389 LttvHooks *event,
390 LttvHooksById *event_by_id)
391 {
392 guint i, index;
393
394 LttvHooks *hook;
395
396 lttv_hooks_call(before_tracefile, self);
397 lttv_hooks_add_list(self->event, event);
398 if(event_by_id != NULL) {
399 for(i = 0; i < event_by_id->array->len; i++) {
400 index = g_array_index(event_by_id->array, guint, i);
401 hook = lttv_hooks_by_id_find(self->event_by_id, index);
402 lttv_hooks_add_list(hook, lttv_hooks_by_id_get(event_by_id, index));
403 }
404 }
405 }
406
407 void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
408 LttvHooks *after_tracefile,
409 LttvHooks *event,
410 LttvHooksById *event_by_id)
411 {
412 guint i, index;
413
414 LttvHooks *hook;
415
416 lttv_hooks_remove_list(self->event, event);
417 if(event_by_id != NULL) {
418 for(i = 0; i < event_by_id->array->len; i++) {
419 index = g_array_index(event_by_id->array, guint, i);
420 hook = lttv_hooks_by_id_get(self->event_by_id, index);
421 if(hook != NULL)
422 lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, index));
423 }
424 }
425
426 lttv_hooks_call(after_tracefile, self);
427 }
428
429
430
431 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext *tfc,
432 unsigned i,
433 LttvHooks *event_by_id)
434 {
435 LttvHooks * h;
436 h = lttv_hooks_by_id_find(tfc->event_by_id, i);
437 lttv_hooks_add_list(h, event_by_id);
438 }
439
440 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext *tfc,
441 unsigned i)
442 {
443 lttv_hooks_by_id_remove(tfc->event_by_id, i);
444 }
445
446 static LttvTracesetContext *
447 new_traceset_context(LttvTracesetContext *self)
448 {
449 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
450 }
451
452
453 static LttvTraceContext *
454 new_trace_context(LttvTracesetContext *self)
455 {
456 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
457 }
458
459
460 static LttvTracefileContext *
461 new_tracefile_context(LttvTracesetContext *self)
462 {
463 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
464 }
465
466
467 static void
468 traceset_context_instance_init (GTypeInstance *instance, gpointer g_class)
469 {
470 /* Be careful of anything which would not work well with shallow copies */
471 }
472
473
474 static void
475 traceset_context_finalize (LttvTracesetContext *self)
476 {
477 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE)))
478 ->finalize(G_OBJECT(self));
479 }
480
481
482 static void
483 traceset_context_class_init (LttvTracesetContextClass *klass)
484 {
485 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
486
487 gobject_class->finalize = (void (*)(GObject *self))traceset_context_finalize;
488 klass->init = init;
489 klass->fini = fini;
490 klass->new_traceset_context = new_traceset_context;
491 klass->new_trace_context = new_trace_context;
492 klass->new_tracefile_context = new_tracefile_context;
493 }
494
495
496 GType
497 lttv_traceset_context_get_type(void)
498 {
499 static GType type = 0;
500 if (type == 0) {
501 static const GTypeInfo info = {
502 sizeof (LttvTracesetContextClass),
503 NULL, /* base_init */
504 NULL, /* base_finalize */
505 (GClassInitFunc) traceset_context_class_init, /* class_init */
506 NULL, /* class_finalize */
507 NULL, /* class_data */
508 sizeof (LttvTracesetContext),
509 0, /* n_preallocs */
510 (GInstanceInitFunc) traceset_context_instance_init, /* instance_init */
511 NULL /* Value handling */
512 };
513
514 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType",
515 &info, 0);
516 }
517 return type;
518 }
519
520
521 static void
522 trace_context_instance_init (GTypeInstance *instance, gpointer g_class)
523 {
524 /* Be careful of anything which would not work well with shallow copies */
525 }
526
527
528 static void
529 trace_context_finalize (LttvTraceContext *self)
530 {
531 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))->
532 finalize(G_OBJECT(self));
533 }
534
535
536 static void
537 trace_context_class_init (LttvTraceContextClass *klass)
538 {
539 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
540
541 gobject_class->finalize = (void (*)(GObject *self)) trace_context_finalize;
542 }
543
544
545 GType
546 lttv_trace_context_get_type(void)
547 {
548 static GType type = 0;
549 if (type == 0) {
550 static const GTypeInfo info = {
551 sizeof (LttvTraceContextClass),
552 NULL, /* base_init */
553 NULL, /* base_finalize */
554 (GClassInitFunc) trace_context_class_init, /* class_init */
555 NULL, /* class_finalize */
556 NULL, /* class_data */
557 sizeof (LttvTraceContext),
558 0, /* n_preallocs */
559 (GInstanceInitFunc) trace_context_instance_init, /* instance_init */
560 NULL /* Value handling */
561 };
562
563 type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType",
564 &info, 0);
565 }
566 return type;
567 }
568
569
570 static void
571 tracefile_context_instance_init (GTypeInstance *instance, gpointer g_class)
572 {
573 /* Be careful of anything which would not work well with shallow copies */
574 }
575
576
577 static void
578 tracefile_context_finalize (LttvTracefileContext *self)
579 {
580 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE)))
581 ->finalize(G_OBJECT(self));
582 }
583
584
585 static void
586 tracefile_context_class_init (LttvTracefileContextClass *klass)
587 {
588 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
589
590 gobject_class->finalize = (void (*)(GObject *self))tracefile_context_finalize;
591 }
592
593
594 GType
595 lttv_tracefile_context_get_type(void)
596 {
597 static GType type = 0;
598 if (type == 0) {
599 static const GTypeInfo info = {
600 sizeof (LttvTracefileContextClass),
601 NULL, /* base_init */
602 NULL, /* base_finalize */
603 (GClassInitFunc) tracefile_context_class_init, /* class_init */
604 NULL, /* class_finalize */
605 NULL, /* class_data */
606 sizeof (LttvTracefileContext),
607 0, /* n_preallocs */
608 (GInstanceInitFunc) tracefile_context_instance_init, /* instance_init */
609 NULL /* Value handling */
610 };
611
612 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType",
613 &info, 0);
614 }
615 return type;
616 }
617
618
619
620 static gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
621 g_assert(key == value);
622 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
623 return TRUE;
624 }
625
626 #ifdef DEBUG
627 // Test to see if pqueue is traversed in the right order.
628 static LttTime test_time;
629
630 static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) {
631
632 LttvTracefileContext *tfc = (LttvTracefileContext *)key;
633
634 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
635 g_quark_to_string(ltt_tracefile_name(tfc->tf)),
636 tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec,
637 tfc->index, tfc->t_context->index);
638
639 if(user_data != NULL) {
640 if(((LttvTracefileContext *)user_data) == (LttvTracefileContext *)value) {
641 g_assert(compare_tracefile(user_data, value) == 0);
642 } else
643 g_assert(compare_tracefile(user_data, value) != 0);
644 }
645 g_assert(ltt_time_compare(test_time, tfc->timestamp) <= 0);
646 test_time.tv_sec = tfc->timestamp.tv_sec;
647 test_time.tv_nsec = tfc->timestamp.tv_nsec;
648
649
650 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
651 return FALSE;
652 }
653 #endif //DEBUG
654
655
656
657 void lttv_process_traceset_begin(LttvTracesetContext *self,
658 LttvHooks *before_traceset,
659 LttvHooks *before_trace,
660 LttvHooks *before_tracefile,
661 LttvHooks *event,
662 LttvHooksById *event_by_id)
663 {
664
665 /* simply add hooks in context. _before hooks are called by add_hooks. */
666 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
667 lttv_traceset_context_add_hooks(self,
668 before_traceset,
669 before_trace,
670 before_tracefile,
671 event,
672 event_by_id);
673
674 }
675
676 enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
677
678 /* Note : a _middle must be preceded from a _seek or another middle */
679 guint lttv_process_traceset_middle(LttvTracesetContext *self,
680 LttTime end,
681 guint nb_events,
682 const LttvTracesetContextPosition *end_position)
683 {
684 GTree *pqueue = self->pqueue;
685
686 guint fac_id, ev_id, id;
687
688 LttvTracefileContext *tfc;
689
690 LttEvent *e;
691
692 unsigned count = 0;
693
694 guint read_ret;
695
696 enum read_state last_read_state = LAST_NONE;
697
698 gboolean last_ret = FALSE; /* return value of the last hook list called */
699
700 /* Get the next event from the pqueue, call its hooks,
701 reinsert in the pqueue the following event from the same tracefile
702 unless the tracefile is finished or the event is later than the
703 end time. */
704
705 while(TRUE) {
706 tfc = NULL;
707 g_tree_foreach(pqueue, get_first, &tfc);
708 /* End of traceset : tfc is NULL */
709 if(unlikely(tfc == NULL))
710 {
711 return count;
712 }
713
714 /* Have we reached :
715 * - the maximum number of events specified?
716 * - the end position ?
717 * - the end time ?
718 * then the read is finished. We leave the queue in the same state and
719 * break the loop.
720 */
721
722 if(unlikely(last_ret == TRUE ||
723 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
724 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
725 end_position) == 0)||
726 ltt_time_compare(end, tfc->timestamp) <= 0))
727 {
728 return count;
729 }
730
731 /* Get the tracefile with an event for the smallest time found. If two
732 or more tracefiles have events for the same time, hope that lookup
733 and remove are consistent. */
734
735 #ifdef DEBUG
736 test_time.tv_sec = 0;
737 test_time.tv_nsec = 0;
738 g_debug("test tree before remove");
739 g_tree_foreach(pqueue, test_tree, tfc);
740 #endif //DEBUG
741 g_tree_remove(pqueue, tfc);
742
743 #ifdef DEBUG
744 test_time.tv_sec = 0;
745 test_time.tv_nsec = 0;
746 g_debug("test tree after remove");
747 g_tree_foreach(pqueue, test_tree, tfc);
748 #endif //DEBUG
749
750 e = ltt_tracefile_get_event(tfc->tf);
751
752 if(last_read_state != LAST_EMPTY) {
753 /* Only call hooks if the last read has given an event or if we are at the
754 * first pass (not if last read returned end of tracefile) */
755 count++;
756
757 fac_id = ltt_event_facility_id(e);
758 ev_id = ltt_event_eventtype_id(e);
759 id = GET_HOOK_ID(fac_id, ev_id);
760 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
761 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
762 }
763
764 read_ret = ltt_tracefile_read(tfc->tf);
765
766 if(likely(!read_ret)) {
767 //g_debug("An event is ready");
768 tfc->timestamp = ltt_event_time(e);
769 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
770 g_tree_insert(pqueue, tfc, tfc);
771 #ifdef DEBUG
772 test_time.tv_sec = 0;
773 test_time.tv_nsec = 0;
774 g_debug("test tree after event ready");
775 g_tree_foreach(pqueue, test_tree, NULL);
776 #endif //DEBUG
777
778 last_read_state = LAST_OK;
779 } else {
780 tfc->timestamp = ltt_time_infinite;
781
782 if(read_ret == ERANGE) {
783 last_read_state = LAST_EMPTY;
784 g_debug("End of trace");
785 } else
786 g_error("Error happened in lttv_process_traceset_middle");
787 }
788 }
789 }
790
791
792 void lttv_process_traceset_end(LttvTracesetContext *self,
793 LttvHooks *after_traceset,
794 LttvHooks *after_trace,
795 LttvHooks *after_tracefile,
796 LttvHooks *event,
797 LttvHooksById *event_by_id)
798 {
799 /* Remove hooks from context. _after hooks are called by remove_hooks. */
800 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
801 lttv_traceset_context_remove_hooks(self,
802 after_traceset,
803 after_trace,
804 after_tracefile,
805 event,
806 event_by_id);
807 }
808
809 /* Subtile modification :
810 * if tracefile has no event at or after the time requested, it is not put in
811 * the queue, as the next read would fail.
812 *
813 * Don't forget to empty the traceset pqueue before calling this.
814 */
815 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
816 {
817 guint i, nb_tracefile;
818
819 gint ret;
820
821 LttvTracefileContext **tfc;
822
823 nb_tracefile = self->tracefiles->len;
824
825 GTree *pqueue = self->ts_context->pqueue;
826
827 for(i = 0 ; i < nb_tracefile ; i++) {
828 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
829
830 //g_tree_remove(pqueue, *tfc);
831
832 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
833 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
834
835 if(ret == 0) { /* not ERANGE especially */
836 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
837 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
838 g_tree_insert(pqueue, (*tfc), (*tfc));
839 } else {
840 (*tfc)->timestamp = ltt_time_infinite;
841 }
842 }
843 #ifdef DEBUG
844 test_time.tv_sec = 0;
845 test_time.tv_nsec = 0;
846 g_debug("test tree after seek_time");
847 g_tree_foreach(pqueue, test_tree, NULL);
848 #endif //DEBUG
849
850
851
852 }
853
854
855 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
856 {
857 guint i, nb_trace;
858
859 LttvTraceContext *tc;
860
861 g_tree_destroy(self->pqueue);
862 self->pqueue = g_tree_new(compare_tracefile);
863
864 nb_trace = lttv_traceset_number(self->ts);
865 for(i = 0 ; i < nb_trace ; i++) {
866 tc = self->traces[i];
867 lttv_process_trace_seek_time(tc, start);
868 }
869 }
870
871
872 gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
873 const LttvTracesetContextPosition *pos)
874 {
875 guint i;
876
877 /* If a position is set, seek the traceset to this position */
878 if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
879 g_tree_destroy(self->pqueue);
880 self->pqueue = g_tree_new(compare_tracefile);
881
882 for(i=0;i<pos->ep->len; i++) {
883 LttEventPosition **ep = &g_array_index(pos->ep, LttEventPosition*, i);
884 LttvTracefileContext **tfc =
885 &g_array_index(pos->tfc, LttvTracefileContext*, i);
886 if(*ep != NULL) {
887 if(ltt_tracefile_seek_position((*tfc)->tf, *ep) != 0)
888 return 1;
889 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
890 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
891 g_tree_insert(self->pqueue, (*tfc), (*tfc));
892 } else {
893 (*tfc)->timestamp = ltt_time_infinite;
894 }
895 }
896 }
897 #ifdef DEBUG
898 test_time.tv_sec = 0;
899 test_time.tv_nsec = 0;
900 g_debug("test tree after seek_position");
901 g_tree_foreach(self->pqueue, test_tree, NULL);
902 #endif //DEBUG
903
904
905
906 return 0;
907 }
908
909
910
911 static LttField *
912 find_field(LttEventType *et, const GQuark field)
913 {
914 LttType *t;
915
916 LttField *f;
917
918 guint i, nb;
919
920 GQuark name;
921
922 /* Field is unset */
923 if(field == 0) return NULL;
924
925 f = ltt_eventtype_field(et);
926 t = ltt_eventtype_type(et);
927 g_assert(ltt_type_class(t) == LTT_STRUCT);
928 nb = ltt_type_member_number(t);
929 for(i = 0 ; i < nb ; i++) {
930 ltt_type_member_type(t, i, &name);
931 if(name == field) break;
932 }
933 g_assert(i < nb);
934 return ltt_field_member(f, i);
935 }
936
937 LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
938 guint facility_id)
939 {
940 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
941 }
942
943 /* Get the first facility corresponding to the name. As the types must be
944 * compatible, it is relevant to use the field name and sizes of the first
945 * facility to create data structures and assume the data will be compatible
946 * thorough the trace */
947 LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
948 {
949 g_assert(th->fac_list->len > 0);
950 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
951 }
952
953
954 /* Returns 0 on success, -1 if fails. */
955 gint
956 lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
957 GQuark field1, GQuark field2, GQuark field3, LttvHook h, gpointer hook_data,
958 LttvTraceHook *th)
959 {
960 LttFacility *f;
961
962 LttEventType *et, *first_et;
963
964 GArray *facilities;
965
966 guint i, fac_id, ev_id;
967
968 LttvTraceHookByFacility *thf, *first_thf;
969
970 facilities = ltt_trace_facility_get_by_name(t, facility);
971
972 if(unlikely(facilities == NULL)) goto facility_error;
973
974 th->fac_index = g_array_sized_new(FALSE, TRUE,
975 sizeof(LttvTraceHookByFacility),
976 NUM_FACILITIES);
977 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
978
979 th->fac_list = g_array_sized_new(FALSE, TRUE,
980 sizeof(LttvTraceHookByFacility*),
981 facilities->len);
982 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
983
984 fac_id = g_array_index(facilities, guint, 0);
985 f = ltt_trace_get_facility_by_num(t, fac_id);
986
987 et = ltt_facility_eventtype_get_by_name(f, event);
988 if(unlikely(et == NULL)) goto event_error;
989
990 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
991 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf;
992
993 ev_id = ltt_eventtype_id(et);
994
995 thf->h = h;
996 thf->id = GET_HOOK_ID(fac_id, ev_id);
997 thf->f1 = find_field(et, field1);
998 thf->f2 = find_field(et, field2);
999 thf->f3 = find_field(et, field3);
1000 thf->hook_data = hook_data;
1001
1002 first_thf = thf;
1003 first_et = et;
1004
1005 /* Check for type compatibility too */
1006 for(i=1;i<facilities->len;i++) {
1007 fac_id = g_array_index(facilities, guint, i);
1008 f = ltt_trace_get_facility_by_num(t, fac_id);
1009
1010 et = ltt_facility_eventtype_get_by_name(f, ltt_eventtype_name(et));
1011 if(unlikely(et == NULL)) goto event_error;
1012
1013 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1014 g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf;
1015 ev_id = ltt_eventtype_id(et);
1016 thf->h = h;
1017 thf->id = GET_HOOK_ID(fac_id, ev_id);
1018 thf->f1 = find_field(et, field1);
1019 if(check_fields_compatibility(first_et, et,
1020 first_thf->f1, thf->f1))
1021 goto type_error;
1022
1023 thf->f2 = find_field(et, field2);
1024 if(check_fields_compatibility(first_et, et,
1025 first_thf->f2, thf->f2))
1026 goto type_error;
1027
1028 thf->f3 = find_field(et, field3);
1029 if(check_fields_compatibility(first_et, et,
1030 first_thf->f3, thf->f3))
1031 goto type_error;
1032 thf->hook_data = hook_data;
1033 }
1034
1035 return 0;
1036
1037 type_error:
1038 goto free;
1039 event_error:
1040 g_error("Event type %s does not exist",
1041 g_quark_to_string(ltt_eventtype_name(et)));
1042 goto free;
1043 facility_error:
1044 g_error("No %s facility", g_quark_to_string(facility));
1045 goto free;
1046 free:
1047 g_array_free(th->fac_index, TRUE);
1048 g_array_free(th->fac_list, TRUE);
1049 th->fac_index = NULL;
1050 th->fac_list = NULL;
1051 return -1;
1052 }
1053
1054 void lttv_trace_hook_destroy(LttvTraceHook *th)
1055 {
1056 g_array_free(th->fac_index, TRUE);
1057 g_array_free(th->fac_list, TRUE);
1058 }
1059
1060
1061 LttvTracesetContextPosition *lttv_traceset_context_position_new()
1062 {
1063 LttvTracesetContextPosition *pos = g_new(LttvTracesetContextPosition,1);
1064 pos->ep = g_array_sized_new(FALSE, TRUE, sizeof(LttEventPosition*),
1065 10);
1066 pos->tfc = g_array_sized_new(FALSE, TRUE, sizeof(LttvTracefileContext*),
1067 10);
1068 pos->timestamp = ltt_time_infinite;
1069 return pos;
1070 }
1071
1072 /* Save all positions, the ones with infinite time will have NULL
1073 * ep. */
1074 void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1075 LttvTracesetContextPosition *pos)
1076 {
1077 guint i;
1078 guint num_traces = lttv_traceset_number(self->ts);
1079
1080 for(i=0; i<num_traces;i++) {
1081 GArray * tracefiles = self->traces[i]->tracefiles;
1082 guint j;
1083 guint num_tracefiles = tracefiles->len;
1084
1085 for(j=0;j<num_tracefiles;j++) {
1086 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1087 LttvTracefileContext*, j);
1088
1089 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1090 LttEventPosition *ep;
1091
1092 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1093 ep = ltt_event_position_new();
1094 ltt_event_position(event, ep);
1095 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1096 pos->timestamp = (*tfc)->timestamp;
1097 } else {
1098 ep = NULL;
1099 }
1100 g_array_append_val(pos->tfc, *tfc);
1101 g_array_append_val(pos->ep, ep);
1102 }
1103
1104 }
1105 }
1106
1107 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1108 {
1109 int i;
1110 LttEventPosition **ep;
1111
1112 for(i=0;i<pos->ep->len;i++) {
1113 ep = &g_array_index(pos->ep, LttEventPosition*, i);
1114 if(*ep != NULL)
1115 g_free(*ep);
1116 }
1117 g_array_free(pos->ep, TRUE);
1118 g_array_free(pos->tfc, TRUE);
1119 g_free(pos);
1120 }
1121
1122 void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1123 const LttvTracesetContextPosition *src)
1124 {
1125 int i;
1126 LttEventPosition **src_ep, **dest_ep;
1127
1128 g_array_set_size(dest->ep, src->ep->len);
1129 g_array_set_size(dest->tfc, src->tfc->len);
1130
1131 for(i=0;i<src->ep->len;i++) {
1132 src_ep = &g_array_index(src->ep, LttEventPosition*, i);
1133 dest_ep = &g_array_index(dest->ep, LttEventPosition*, i);
1134 if(*src_ep != NULL) {
1135 *dest_ep = ltt_event_position_new();
1136 ltt_event_position_copy(
1137 *dest_ep,
1138 *src_ep);
1139 } else
1140 *dest_ep = NULL;
1141 }
1142 for(i=0;i<src->tfc->len;i++) {
1143 g_array_index(dest->tfc, LttvTracefileContext*, i) =
1144 g_array_index(src->tfc, LttvTracefileContext*, i);
1145 }
1146 dest->timestamp = src->timestamp;
1147 }
1148
1149 gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1150 const LttvTracesetContextPosition *pos)
1151 {
1152 int i;
1153 int ret = 0;
1154
1155 if(pos->ep->len == 0) {
1156 if(lttv_traceset_number(self->ts) == 0) return 0;
1157 else return 1;
1158 }
1159 if(lttv_traceset_number(self->ts) == 0)
1160 return -1;
1161
1162 for(i=0;i<pos->ep->len;i++) {
1163 LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i);
1164 LttvTracefileContext *tfc =
1165 g_array_index(pos->tfc, LttvTracefileContext*, i);
1166
1167 if(ep == NULL) {
1168 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0) {
1169 ret = -1;
1170 }
1171 } else {
1172 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) == 0) {
1173 ret = 1;
1174 } else {
1175 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
1176
1177 ret = ltt_event_position_compare((LttEventPosition*)event,
1178 ep);
1179 }
1180 }
1181 if(ret != 0) return ret;
1182
1183 }
1184 return 0;
1185 }
1186
1187
1188 gint lttv_traceset_context_pos_pos_compare(
1189 const LttvTracesetContextPosition *pos1,
1190 const LttvTracesetContextPosition *pos2)
1191 {
1192 int i, j;
1193 int ret;
1194
1195 if(pos1->ep->len == 0) {
1196 if(pos2->ep->len == 0) return 0;
1197 else return 1;
1198 }
1199 if(pos2->ep->len == 0)
1200 return -1;
1201
1202 for(i=0;i<pos1->ep->len;i++) {
1203 LttEventPosition *ep1 = g_array_index(pos1->ep, LttEventPosition*, i);
1204 LttvTracefileContext *tfc1 = g_array_index(pos1->tfc,
1205 LttvTracefileContext*, i);
1206
1207 if(ep1 != NULL) {
1208 for(j=0;j<pos2->ep->len;j++) {
1209 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1210 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1211 LttvTracefileContext*, j);
1212 if(tfc1 == tfc2) {
1213 if(ep2 != NULL)
1214 ret = ltt_event_position_compare(ep1, ep2);
1215 else
1216 ret = -1;
1217
1218 if(ret != 0) return ret;
1219 }
1220 }
1221 } else {
1222 for(j=0;j<pos2->ep->len;j++) {
1223 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1224 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1225 LttvTracefileContext*, j);
1226 if(tfc1 == tfc2) {
1227 if(ep2 != NULL) ret = 1;
1228 }
1229 }
1230 }
1231 }
1232 return 0;
1233 }
1234
1235
1236 LttTime lttv_traceset_context_position_get_time(
1237 const LttvTracesetContextPosition *pos)
1238 {
1239 return pos->timestamp;
1240 }
1241
1242
1243 LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1244 {
1245 GTree *pqueue = self->pqueue;
1246 LttvTracefileContext *tfc = NULL;
1247
1248 g_tree_foreach(pqueue, get_first, &tfc);
1249
1250 return tfc;
1251 }
1252
1253 /* lttv_process_traceset_synchronize_tracefiles
1254 *
1255 * Use the sync_position field of the trace set context to synchronize each
1256 * tracefile with the previously saved position.
1257 *
1258 * If no previous position has been saved, it simply does nothing.
1259 */
1260 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1261 {
1262 g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
1263 }
1264
1265
1266
1267
1268 void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1269 {
1270 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1271 }
1272
This page took 0.057396 seconds and 4 git commands to generate.