Basic babeltrace integration
[lttv.git] / 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/lttv.h>
25 #include <lttv/tracecontext.h>
26 #include <ltt/event.h>
27 #include <ltt/trace.h>
28 #include <lttv/filter.h>
29 #include <errno.h>
30 #include <ltt/time.h>
31
32 #include <babeltrace/context.h>
33 #include <babeltrace/iterator.h>
34
35 #include <babeltrace/ctf/events.h>
36 #include <babeltrace/ctf/iterator.h>
37
38 gint compare_tracefile(gconstpointer a, gconstpointer b)
39 {
40 gint comparison = 0;
41
42 const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
43 const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
44
45 if(likely(trace_a != trace_b)) {
46 comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
47 if(unlikely(comparison == 0)) {
48 if(trace_a->index < trace_b->index) comparison = -1;
49 else if(trace_a->index > trace_b->index) comparison = 1;
50 else if(trace_a->t_context->index < trace_b->t_context->index)
51 comparison = -1;
52 else if(trace_a->t_context->index > trace_b->t_context->index)
53 comparison = 1;
54 }
55 }
56 return comparison;
57 }
58
59 typedef struct _LttvTracefileContextPosition {
60 LttEventPosition *event;
61 LttvTracefileContext *tfc;
62 gboolean used; /* Tells if the tfc is at end of traceset position */
63 } LttvTracefileContextPosition;
64
65
66 struct _LttvTracesetContextPosition {
67 GArray *tfcp; /* Array of LttvTracefileContextPosition */
68 LttTime timestamp; /* Current time at the saved position */
69 /* If ltt_time_infinite : no position is
70 * set, else, a position is set (may be end
71 * of trace, with ep->len == 0) */
72 };
73
74 void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
75 {
76 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
77 }
78
79
80 void lttv_context_fini(LttvTracesetContext *self)
81 {
82 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
83 }
84
85
86 LttvTracesetContext *
87 lttv_context_new_traceset_context(LttvTracesetContext *self)
88 {
89 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
90 }
91
92
93
94
95 LttvTraceContext *
96 lttv_context_new_trace_context(LttvTracesetContext *self)
97 {
98 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
99 }
100
101
102 LttvTracefileContext *
103 lttv_context_new_tracefile_context(LttvTracesetContext *self)
104 {
105 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
106 }
107
108 /****************************************************************************
109 * lttv_traceset_context_compute_time_span
110 *
111 * Keep the time span in sync with on the fly addition and removal of traces
112 * in a trace set. It must be called each time a trace is added/removed from
113 * the traceset. It could be more efficient to call it only once a bunch
114 * of traces are loaded, but the calculation is not long, so it's not
115 * critical.
116 *
117 * Author : Xang Xiu Yang
118 ***************************************************************************/
119 void lttv_traceset_context_compute_time_span(LttvTracesetContext *self,
120 TimeInterval *time_span)
121 {
122 LttvTraceset * traceset = self->ts;
123 int numTraces = lttv_traceset_number(traceset);
124 int i;
125 LttTime s, e;
126 LttvTraceContext *tc;
127 LttTrace * trace;
128
129 time_span->start_time.tv_sec = 0;
130 time_span->start_time.tv_nsec = 0;
131 time_span->end_time.tv_sec = 0;
132 time_span->end_time.tv_nsec = 0;
133
134 for(i=0; i<numTraces;i++){
135 tc = self->traces[i];
136 trace = tc->t;
137
138 ltt_trace_time_span_get(trace, &s, &e);
139 tc->time_span.start_time = s;
140 tc->time_span.end_time = e;
141
142 if(i==0){
143 time_span->start_time = s;
144 time_span->end_time = e;
145 } else {
146 if(s.tv_sec < time_span->start_time.tv_sec
147 || (s.tv_sec == time_span->start_time.tv_sec
148 && s.tv_nsec < time_span->start_time.tv_nsec))
149 time_span->start_time = s;
150 if(e.tv_sec > time_span->end_time.tv_sec
151 || (e.tv_sec == time_span->end_time.tv_sec
152 && e.tv_nsec > time_span->end_time.tv_nsec))
153 time_span->end_time = e;
154 }
155 }
156 }
157
158 static void init_tracefile_context(LttTracefile *tracefile,
159 LttvTraceContext *tc)
160 {
161 LttvTracefileContext *tfc;
162 LttvTracesetContext *tsc = tc->ts_context;
163
164 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(tsc)->new_tracefile_context(tsc);
165
166 tfc->index = tc->tracefiles->len;
167 tc->tracefiles = g_array_append_val(tc->tracefiles, tfc);
168
169 tfc->tf = tracefile;
170
171 tfc->t_context = tc;
172 tfc->event = lttv_hooks_new();
173 tfc->event_by_id = lttv_hooks_by_id_new();
174 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
175 tfc->target_pid = -1;
176 }
177
178
179 static void
180 init(LttvTracesetContext *self, LttvTraceset *ts)
181 {
182 guint i, nb_trace;
183
184 LttvTraceContext *tc;
185
186 GData **tracefiles_groups;
187
188 struct compute_tracefile_group_args args;
189
190 struct bt_iter_pos begin_pos;
191
192 nb_trace = lttv_traceset_number(ts);
193 self->ts = ts;
194 self->traces = g_new(LttvTraceContext *, nb_trace);
195 self->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
196 self->ts_a = lttv_traceset_attribute(ts);
197
198 begin_pos.type = BT_SEEK_BEGIN;
199
200 self->iter = bt_ctf_iter_create(lttv_traceset_get_context(ts),
201 &begin_pos,
202 NULL);
203 self->event_hooks = lttv_hooks_new();
204 #ifdef BABEL_CLEANUP
205 for(i = 0 ; i < nb_trace ; i++) {
206 tc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
207 self->traces[i] = tc;
208
209 tc->ts_context = self;
210 tc->index = i;
211 tc->vt = lttv_traceset_get(ts, i);
212 tc->t = lttv_trace(tc->vt);
213 tc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
214 tc->t_a = lttv_trace_attribute(tc->vt);
215 tc->tracefiles = g_array_sized_new(FALSE, TRUE,
216 sizeof(LttvTracefileContext*), 10);
217
218 tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t);
219 if(tracefiles_groups != NULL) {
220 args.func = (ForEachTraceFileFunc)init_tracefile_context;
221 args.func_args = tc;
222
223 g_datalist_foreach(tracefiles_groups,
224 (GDataForeachFunc)compute_tracefile_group,
225 &args);
226 }
227
228
229 }
230 #endif
231 self->sync_position = lttv_traceset_context_position_new(self);
232 self->pqueue = g_tree_new(compare_tracefile);
233 lttv_process_traceset_seek_time(self, ltt_time_zero);
234 lttv_traceset_context_compute_time_span(self, &self->time_span);
235
236 }
237
238
239 void fini(LttvTracesetContext *self)
240 {
241 guint i, j, nb_trace, nb_tracefile;
242
243 LttvTraceContext *tc;
244
245 LttvTracefileContext **tfc;
246
247 LttvTraceset *ts = self->ts;
248
249 g_tree_destroy(self->pqueue);
250 g_object_unref(self->a);
251 lttv_traceset_context_position_destroy(self->sync_position);
252
253 nb_trace = lttv_traceset_number(ts);
254
255 for(i = 0 ; i < nb_trace ; i++) {
256 tc = self->traces[i];
257
258 g_object_unref(tc->a);
259
260 nb_tracefile = tc->tracefiles->len;
261
262 for(j = 0 ; j < nb_tracefile ; j++) {
263 tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, j);
264 lttv_hooks_destroy((*tfc)->event);
265 lttv_hooks_by_id_destroy((*tfc)->event_by_id);
266 g_object_unref((*tfc)->a);
267 g_object_unref(*tfc);
268 }
269 g_array_free(tc->tracefiles, TRUE);
270 g_object_unref(tc);
271 }
272 g_free(self->traces);
273 }
274
275
276 void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
277 LttvHooks *before_traceset,
278 LttvHooks *before_trace,
279 LttvHooks *before_tracefile,
280 LttvHooks *event,
281 LttvHooksByIdChannelArray *event_by_id_channel)
282 {
283 LttvTraceset *ts = self->ts;
284
285 guint i, nb_trace;
286
287 LttvTraceContext *tc;
288
289 lttv_hooks_call(before_traceset, self);
290
291 lttv_hooks_add_list(self->event_hooks, event);
292
293 nb_trace = lttv_traceset_number(ts);
294
295 for(i = 0 ; i < nb_trace ; i++) {
296 tc = self->traces[i];
297 lttv_trace_context_add_hooks(tc,
298 before_trace,
299 before_tracefile,
300 event,
301 event_by_id_channel);
302 }
303 }
304
305
306 void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
307 LttvHooks *after_traceset,
308 LttvHooks *after_trace,
309 LttvHooks *after_tracefile,
310 LttvHooks *event,
311 LttvHooksByIdChannelArray *event_by_id_channel)
312 {
313
314 LttvTraceset *ts = self->ts;
315
316 guint i, nb_trace;
317
318 LttvTraceContext *tc;
319
320 nb_trace = lttv_traceset_number(ts);
321
322 for(i = 0 ; i < nb_trace ; i++) {
323 tc = self->traces[i];
324 lttv_trace_context_remove_hooks(tc,
325 after_trace,
326 after_tracefile,
327 event,
328 event_by_id_channel);
329 }
330
331 lttv_hooks_call(after_traceset, self);
332
333
334 }
335
336 void lttv_trace_context_add_hooks(LttvTraceContext *self,
337 LttvHooks *before_trace,
338 LttvHooks *before_tracefile,
339 LttvHooks *event,
340 LttvHooksByIdChannelArray *event_by_id_channel)
341 {
342 guint i, j, nb_tracefile;
343 LttvTracefileContext **tfc;
344 LttTracefile *tf;
345
346 lttv_hooks_call(before_trace, self);
347
348 nb_tracefile = self->tracefiles->len;
349
350 for(i = 0 ; i < nb_tracefile ; i++) {
351 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
352 tf = (*tfc)->tf;
353 lttv_tracefile_context_add_hooks(*tfc,
354 before_tracefile,
355 event,
356 NULL);
357 if (event_by_id_channel) {
358 for(j = 0; j < event_by_id_channel->array->len; j++) {
359 LttvHooksByIdChannel *hooks =
360 &g_array_index(event_by_id_channel->array,
361 LttvHooksByIdChannel, j);
362 if (tf->name == hooks->channel)
363 lttv_tracefile_context_add_hooks(*tfc,
364 NULL,
365 NULL,
366 hooks->hooks_by_id);
367 }
368 }
369 }
370 }
371
372
373
374 void lttv_trace_context_remove_hooks(LttvTraceContext *self,
375 LttvHooks *after_trace,
376 LttvHooks *after_tracefile,
377 LttvHooks *event,
378 LttvHooksByIdChannelArray *event_by_id_channel)
379 {
380 guint i, j, nb_tracefile;
381 LttvTracefileContext **tfc;
382 LttTracefile *tf;
383
384 nb_tracefile = self->tracefiles->len;
385
386 for(i = 0 ; i < nb_tracefile ; i++) {
387 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
388 tf = (*tfc)->tf;
389 if (event_by_id_channel) {
390 for(j = 0; j < event_by_id_channel->array->len; j++) {
391 LttvHooksByIdChannel *hooks =
392 &g_array_index(event_by_id_channel->array,
393 LttvHooksByIdChannel, j);
394 if (tf->name == hooks->channel)
395 lttv_tracefile_context_remove_hooks(*tfc,
396 NULL,
397 NULL,
398 hooks->hooks_by_id);
399 }
400 }
401 lttv_tracefile_context_remove_hooks(*tfc,
402 after_tracefile,
403 event,
404 NULL);
405
406 }
407
408 lttv_hooks_call(after_trace, self);
409 }
410
411 void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
412 LttvHooks *before_tracefile,
413 LttvHooks *event,
414 LttvHooksById *event_by_id)
415 {
416 guint i, index;
417 LttvHooks *hook;
418
419 lttv_hooks_call(before_tracefile, self);
420 lttv_hooks_add_list(self->event, event);
421 if(event_by_id != NULL) {
422 for(i = 0; i < event_by_id->array->len; i++) {
423 index = g_array_index(event_by_id->array, guint, i);
424 hook = lttv_hooks_by_id_find(self->event_by_id, index);
425 lttv_hooks_add_list(hook, lttv_hooks_by_id_get(event_by_id, index));
426 }
427 }
428 }
429
430 void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
431 LttvHooks *after_tracefile,
432 LttvHooks *event,
433 LttvHooksById *event_by_id)
434 {
435 guint i, index;
436
437 LttvHooks *hook;
438
439 lttv_hooks_remove_list(self->event, event);
440 if(event_by_id != NULL) {
441 for(i = 0; i < event_by_id->array->len; i++) {
442 index = g_array_index(event_by_id->array, guint, i);
443 hook = lttv_hooks_by_id_get(self->event_by_id, index);
444 if(hook != NULL)
445 lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, index));
446 }
447 }
448
449 lttv_hooks_call(after_tracefile, self);
450 }
451
452 static LttvTracesetContext *new_traceset_context(LttvTracesetContext *self)
453 {
454 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
455 }
456
457
458 static LttvTraceContext *new_trace_context(LttvTracesetContext *self)
459 {
460 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
461 }
462
463
464 static LttvTracefileContext *new_tracefile_context(LttvTracesetContext *self)
465 {
466 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
467 }
468
469
470 static void traceset_context_instance_init(GTypeInstance *instance,
471 gpointer g_class)
472 {
473 /* Be careful of anything which would not work well with shallow copies */
474 }
475
476
477 static void traceset_context_finalize(LttvTracesetContext *self)
478 {
479 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE)))
480 ->finalize(G_OBJECT(self));
481 }
482
483
484 static void traceset_context_class_init(LttvTracesetContextClass *klass)
485 {
486 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
487
488 gobject_class->finalize = (void (*)(GObject *self))traceset_context_finalize;
489 klass->init = init;
490 klass->fini = fini;
491 klass->new_traceset_context = new_traceset_context;
492 klass->new_trace_context = new_trace_context;
493 klass->new_tracefile_context = new_tracefile_context;
494 }
495
496
497 GType 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 trace_context_finalize (LttvTraceContext *self)
529 {
530 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))->
531 finalize(G_OBJECT(self));
532 }
533
534
535 static void trace_context_class_init (LttvTraceContextClass *klass)
536 {
537 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
538
539 gobject_class->finalize = (void (*)(GObject *self)) trace_context_finalize;
540 }
541
542
543 GType lttv_trace_context_get_type(void)
544 {
545 static GType type = 0;
546 if (type == 0) {
547 static const GTypeInfo info = {
548 sizeof (LttvTraceContextClass),
549 NULL, /* base_init */
550 NULL, /* base_finalize */
551 (GClassInitFunc) trace_context_class_init, /* class_init */
552 NULL, /* class_finalize */
553 NULL, /* class_data */
554 sizeof (LttvTraceContext),
555 0, /* n_preallocs */
556 (GInstanceInitFunc) trace_context_instance_init, /* instance_init */
557 NULL /* Value handling */
558 };
559
560 type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType",
561 &info, 0);
562 }
563 return type;
564 }
565
566
567 static void tracefile_context_instance_init (GTypeInstance *instance,
568 gpointer g_class)
569 {
570 /* Be careful of anything which would not work well with shallow copies */
571 }
572
573
574 static void tracefile_context_finalize (LttvTracefileContext *self)
575 {
576 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE)))
577 ->finalize(G_OBJECT(self));
578 }
579
580
581 static void tracefile_context_class_init (LttvTracefileContextClass *klass)
582 {
583 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
584
585 gobject_class->finalize = (void (*)(GObject *self))tracefile_context_finalize;
586 }
587
588
589 GType lttv_tracefile_context_get_type(void)
590 {
591 static GType type = 0;
592 if (type == 0) {
593 static const GTypeInfo info = {
594 sizeof (LttvTracefileContextClass),
595 NULL, /* base_init */
596 NULL, /* base_finalize */
597 (GClassInitFunc) tracefile_context_class_init, /* class_init */
598 NULL, /* class_finalize */
599 NULL, /* class_data */
600 sizeof (LttvTracefileContext),
601 0, /* n_preallocs */
602 (GInstanceInitFunc) tracefile_context_instance_init, /* instance_init */
603 NULL /* Value handling */
604 };
605
606 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType",
607 &info, 0);
608 }
609 return type;
610 }
611
612
613
614 static gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
615 g_assert(key == value);
616 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
617 return TRUE;
618 }
619
620 #ifdef DEBUG
621 // Test to see if pqueue is traversed in the right order.
622 static LttTime test_time;
623
624 static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) {
625
626 LttvTracefileContext *tfc = (LttvTracefileContext *)key;
627
628 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
629 g_quark_to_string(ltt_tracefile_name(tfc->tf)),
630 tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec,
631 tfc->index, tfc->t_context->index);
632
633 if(user_data != NULL) {
634 if(((LttvTracefileContext *)user_data) == (LttvTracefileContext *)value) {
635 g_assert(compare_tracefile(user_data, value) == 0);
636 } else
637 g_assert(compare_tracefile(user_data, value) != 0);
638 }
639 g_assert(ltt_time_compare(test_time, tfc->timestamp) <= 0);
640 test_time.tv_sec = tfc->timestamp.tv_sec;
641 test_time.tv_nsec = tfc->timestamp.tv_nsec;
642
643
644 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
645 return FALSE;
646 }
647 #endif //DEBUG
648
649
650
651 void lttv_process_traceset_begin(LttvTracesetContext *self,
652 LttvHooks *before_traceset,
653 LttvHooks *before_trace,
654 LttvHooks *before_tracefile,
655 LttvHooks *event,
656 LttvHooksByIdChannelArray *event_by_id_channel)
657 {
658
659 /* simply add hooks in context. _before hooks are called by add_hooks. */
660 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
661 lttv_traceset_context_add_hooks(self,
662 before_traceset,
663 before_trace,
664 before_tracefile,
665 event,
666 event_by_id_channel);
667
668 }
669
670 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
671
672 /* Note : a _middle must be preceded from a _seek or another middle */
673 guint lttv_process_traceset_middle(LttvTracesetContext *self,
674 LttTime end,
675 gulong nb_events,
676 const LttvTracesetContextPosition *end_position)
677 {
678
679 unsigned count = 0;
680
681 struct bt_ctf_event *event;
682
683 while(TRUE) {
684
685 if((count >= nb_events) && (nb_events != G_MAXULONG)) {
686 break;
687 }
688
689 if((event = bt_ctf_iter_read_event(self->iter)) != NULL) {
690
691 count++;
692
693 /* TODO ybrosseau: encapsulate the event into something */
694 lttv_hooks_call(self->event_hooks, event);
695
696 if(bt_iter_next(bt_ctf_get_iter(self->iter)) < 0) {
697 printf("ERROR NEXT\n");
698 break;
699 }
700 } else {
701 /* READ FAILED */
702
703 break;
704
705 }
706 }
707
708
709
710 return count;
711 #ifdef BABEL_CLEANUP
712 GTree *pqueue = self->pqueue;
713
714 LttvTracefileContext *tfc;
715
716 LttEvent *e;
717
718 unsigned count = 0;
719
720 gboolean is_live = FALSE; /* set this flag if we detect a live trace */
721
722 guint read_ret;
723
724 //enum read_state last_read_state = LAST_NONE;
725
726 gint last_ret = 0; /* return value of the last hook list called */
727
728 /* Get the next event from the pqueue, call its hooks,
729 reinsert in the pqueue the following event from the same tracefile
730 unless the tracefile is finished or the event is later than the
731 end time. */
732
733 while(TRUE) {
734 tfc = NULL;
735 g_tree_foreach(pqueue, get_first, &tfc);
736 /* End of traceset : tfc is NULL */
737 if(unlikely(tfc == NULL))
738 {
739 break;
740 }
741
742 /* Have we reached :
743 * - the maximum number of events specified?
744 * - the end position ?
745 * - the end time ?
746 * then the read is finished. We leave the queue in the same state and
747 * break the loop.
748 */
749 if(tfc->tf->trace->is_live && ltt_time_compare(tfc->timestamp, tfc->tf->trace->live_safe_timestamp) >= 0) {
750
751 break;
752 }
753 if(unlikely(last_ret == TRUE
754 || ((count >= nb_events) && (nb_events != G_MAXULONG))
755 || (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
756 end_position) == 0)
757 || ltt_time_compare(end, tfc->timestamp) <= 0))
758 {
759 break;
760 }
761
762 /* Get the tracefile with an event for the smallest time found. If two
763 or more tracefiles have events for the same time, hope that lookup
764 and remove are consistent. */
765
766 #ifdef DEBUG
767 test_time.tv_sec = 0;
768 test_time.tv_nsec = 0;
769 g_debug("test tree before remove");
770 g_tree_foreach(pqueue, test_tree, tfc);
771 #endif //DEBUG
772 g_tree_remove(pqueue, tfc);
773
774 #ifdef DEBUG
775 test_time.tv_sec = 0;
776 test_time.tv_nsec = 0;
777 g_debug("test tree after remove");
778 g_tree_foreach(pqueue, test_tree, tfc);
779 #endif //DEBUG
780
781
782 e = ltt_tracefile_get_event(tfc->tf);
783
784 //if(last_read_state != LAST_EMPTY) {
785 /* Only call hooks if the last read has given an event or if we are at the
786 * first pass (not if last read returned end of tracefile) */
787 count++;
788
789 tfc->target_pid = -1; /* unset target PID */
790 /* Hooks :
791 * return values : 0 : continue read, 1 : go to next position and stop read,
792 * 2 : stay at the current position and stop read */
793 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
794 lttv_hooks_by_id_get(tfc->event_by_id, e->event_id), tfc);
795
796 #if 0
797 /* This is buggy : it won't work well with state computation */
798 if(unlikely(last_ret == 2)) {
799 /* This is a case where we want to stay at this position and stop read. */
800 g_tree_insert(pqueue, tfc, tfc);
801 count--;
802 break;
803 }
804 #endif //0
805 read_ret = ltt_tracefile_read(tfc->tf);
806
807
808 if(likely(!read_ret)) {
809 //g_debug("An event is ready");
810 tfc->timestamp = ltt_event_time(e);
811
812
813 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
814 g_tree_insert(pqueue, tfc, tfc);
815 if(tfc->tf->trace->is_live && ltt_time_compare(tfc->timestamp, tfc->tf->trace->live_safe_timestamp) >= 0)
816 {
817 is_live |= TRUE;
818 break;
819 }
820 #ifdef DEBUG
821 test_time.tv_sec = 0;
822 test_time.tv_nsec = 0;
823 g_debug("test tree after event ready");
824 g_tree_foreach(pqueue, test_tree, NULL);
825 #endif //DEBUG
826
827 //last_read_state = LAST_OK;
828 } else {
829 tfc->timestamp = ltt_time_infinite;
830
831 if(read_ret == ERANGE) {
832 // last_read_state = LAST_EMPTY;
833 g_debug("End of trace");
834 } else
835 g_error("Error happened in lttv_process_traceset_middle");
836 }
837 }
838
839 if (unlikely((count == 0) && is_live)) {
840 return -1;
841 } else {
842 return count;
843 }
844
845 #endif /* BABEL_CLEANUP */
846 }
847
848
849 void lttv_process_traceset_end(LttvTracesetContext *self,
850 LttvHooks *after_traceset,
851 LttvHooks *after_trace,
852 LttvHooks *after_tracefile,
853 LttvHooks *event,
854 LttvHooksByIdChannelArray *event_by_id_channel)
855 {
856 /* Remove hooks from context. _after hooks are called by remove_hooks. */
857 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
858 lttv_traceset_context_remove_hooks(self,
859 after_traceset,
860 after_trace,
861 after_tracefile,
862 event,
863 event_by_id_channel);
864 }
865
866 /* Subtile modification :
867 * if tracefile has no event at or after the time requested, it is not put in
868 * the queue, as the next read would fail.
869 *
870 * Don't forget to empty the traceset pqueue before calling this.
871 */
872 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
873 {
874
875
876 #ifdef BABEL_CLEANUP
877 guint i, nb_tracefile;
878
879 gint ret;
880
881 LttvTracefileContext **tfc;
882
883 nb_tracefile = self->tracefiles->len;
884
885 GTree *pqueue = self->ts_context->pqueue;
886
887 for(i = 0 ; i < nb_tracefile ; i++) {
888 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
889
890 g_tree_remove(pqueue, *tfc);
891
892 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
893 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
894
895 if(ret == 0) { /* not ERANGE especially */
896 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
897 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
898 g_tree_insert(pqueue, (*tfc), (*tfc));
899 } else {
900 (*tfc)->timestamp = ltt_time_infinite;
901 }
902 }
903 #ifdef DEBUG
904 test_time.tv_sec = 0;
905 test_time.tv_nsec = 0;
906 g_debug("test tree after seek_time");
907 g_tree_foreach(pqueue, test_tree, NULL);
908 #endif //DEBUG
909 #endif
910 }
911
912 /****************************************************************************
913 * lttv_process_trace_update
914 *
915 * process the changes that occur in the trace. Use a regular file polling to
916 * monitor the tracefile.
917 *
918 * Return the number of tracefile updated
919 ***************************************************************************/
920 guint lttv_process_trace_update(LttvTraceContext *self)
921 {
922 guint i;
923 guint nb_tracefile = 0;
924
925 LttTracefile *tf = 0;
926 LttvTracefileContext **tfc;
927
928 /* Skip non live traces */
929 if(self->t->is_live) {
930
931 nb_tracefile = ltt_trace_update(self->t);
932
933 /* Recreate the pqueue following an update*/
934 GTree *pqueue = self->ts_context->pqueue;
935
936 for(i = 0 ; i < self->tracefiles->len ; i++) {
937 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
938 tf = (*tfc)->tf;
939 if(g_tree_remove(pqueue, *tfc) == FALSE) {
940 if(tf->buf_index != NULL) {
941
942 if(ltt_tracefile_read(tf) == 0) {
943
944 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
945 g_tree_insert(pqueue, (*tfc), (*tfc));
946
947 }
948 }
949 } else {
950 g_tree_insert(pqueue, (*tfc), (*tfc));
951
952 }
953
954
955 }
956 //Update self time span
957 self->time_span.end_time = LTT_TIME_MAX(self->t->live_safe_timestamp,
958 self->time_span.end_time);
959 //Update self tscontext time span
960 self->ts_context->time_span.end_time = LTT_TIME_MAX(self->time_span.end_time,
961 self->ts_context->time_span.end_time);
962 }
963 return nb_tracefile;
964
965 }
966
967 /****************************************************************************
968 * lttv_process_traceset_update
969 *
970 * process the changes that occur in the traceset.
971 *
972 * Return the number of file presently monitor(open for writting). If 0, the
973 * current traceset probably received all the data.
974 ***************************************************************************/
975 guint lttv_process_traceset_update(LttvTracesetContext *self)
976 {
977 guint i;
978 guint nb_trace;
979 guint open_counter = 0;
980
981 nb_trace = lttv_traceset_number(self->ts);
982
983 for(i = 0 ; i < nb_trace ; i++) {
984 open_counter += lttv_process_trace_update(self->traces[i]);
985 }
986 return open_counter;
987 }
988
989 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
990 {
991 #ifdef WAIT_FOR_BABELTRACE_FIX_SEEK_ZERO
992 struct bt_iter_pos seekpos;
993 int ret;
994 seekpos.type = BT_SEEK_TIME;
995 seekpos.u.seek_time = ltt_time_to_uint64(start);
996 ret = bt_iter_set_pos(bt_ctf_get_iter(self->iter), &seekpos);
997 if(ret < 0) {
998 printf("Seek by time error: %s,\n",strerror(-ret));
999 }
1000 #else
1001 #warning Seek time disabled because of babeltrace bugs
1002 #endif
1003
1004 #ifdef BABEL_CLEANUP
1005 guint i, nb_trace;
1006
1007
1008
1009 LttvTraceContext *tc;
1010
1011 //g_tree_destroy(self->pqueue);
1012 //self->pqueue = g_tree_new(compare_tracefile);
1013
1014 nb_trace = lttv_traceset_number(self->ts);
1015 for(i = 0 ; i < nb_trace ; i++) {
1016 tc = self->traces[i];
1017 lttv_process_trace_seek_time(tc, start);
1018 }
1019 #endif
1020 }
1021
1022
1023 gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
1024 const LttvTracesetContextPosition *pos)
1025 {
1026 guint i;
1027 /* If a position is set, seek the traceset to this position */
1028 if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
1029
1030 /* Test to see if the traces has been added to the trace set :
1031 * It should NEVER happen. Clear all positions if a new trace comes in. */
1032 /* FIXME I know this test is not optimal : should keep a number of
1033 * tracefiles variable in the traceset.. eventually */
1034 guint num_traces = lttv_traceset_number(self->ts);
1035 guint tf_count = 0;
1036 for(i=0; i<num_traces;i++) {
1037 GArray * tracefiles = self->traces[i]->tracefiles;
1038 guint j;
1039 guint num_tracefiles = tracefiles->len;
1040 for(j=0;j<num_tracefiles;j++)
1041 tf_count++;
1042 }
1043 g_assert(tf_count == pos->tfcp->len);
1044
1045
1046 //g_tree_destroy(self->pqueue);
1047 //self->pqueue = g_tree_new(compare_tracefile);
1048
1049 for(i=0;i<pos->tfcp->len; i++) {
1050 LttvTracefileContextPosition *tfcp =
1051 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1052
1053 g_tree_remove(self->pqueue, tfcp->tfc);
1054
1055 if(tfcp->used == TRUE) {
1056 if(ltt_tracefile_seek_position(tfcp->tfc->tf, tfcp->event) != 0)
1057 return 1;
1058 tfcp->tfc->timestamp =
1059 ltt_event_time(ltt_tracefile_get_event(tfcp->tfc->tf));
1060 g_assert(ltt_time_compare(tfcp->tfc->timestamp,
1061 ltt_time_infinite) != 0);
1062 g_tree_insert(self->pqueue, tfcp->tfc, tfcp->tfc);
1063
1064 } else {
1065 tfcp->tfc->timestamp = ltt_time_infinite;
1066 }
1067 }
1068 }
1069 #ifdef DEBUG
1070 test_time.tv_sec = 0;
1071 test_time.tv_nsec = 0;
1072 g_debug("test tree after seek_position");
1073 g_tree_foreach(self->pqueue, test_tree, NULL);
1074 #endif //DEBUG
1075
1076
1077
1078 return 0;
1079 }
1080
1081
1082 #if 0 // pmf: temporary disable
1083 static LttField *
1084 find_field(LttEventType *et, const GQuark field)
1085 {
1086 LttField *f;
1087
1088 if(field == 0) return NULL;
1089
1090 f = ltt_eventtype_field_by_name(et, field);
1091 if (!f) {
1092 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field),
1093 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et))),
1094 g_quark_to_string(ltt_eventtype_name(et)));
1095 }
1096
1097 return f;
1098 }
1099 #endif
1100
1101 struct marker_info *lttv_trace_hook_get_marker(LttTrace *t, LttvTraceHook *th)
1102 {
1103 return marker_get_info_from_id(th->mdata, th->id);
1104 }
1105
1106 int lttv_trace_find_hook(LttTrace *t, GQuark channel_name, GQuark event_name,
1107 GQuark fields[], LttvHook h, gpointer hook_data,
1108 GArray **trace_hooks)
1109 {
1110 struct marker_info *info;
1111 guint16 marker_id;
1112 int init_array_size;
1113 GArray *group;
1114 struct marker_data *mdata;
1115
1116 group = g_datalist_id_get_data(&t->tracefiles, channel_name);
1117 if (unlikely(!group || group->len == 0)) {
1118 g_info("No channel for marker named %s.%s found",
1119 g_quark_to_string(channel_name), g_quark_to_string(event_name));
1120 return 1;
1121 }
1122
1123 mdata = g_array_index (group, LttTracefile, 0).mdata;
1124 info = marker_get_info_from_name(mdata, event_name);
1125 if(unlikely(info == NULL)) {
1126 g_info("No marker named %s.%s found",
1127 g_quark_to_string(channel_name), g_quark_to_string(event_name));
1128 return 1;
1129 }
1130
1131 init_array_size = (*trace_hooks)->len;
1132
1133 /* for each marker with the requested name */
1134 do {
1135 LttvTraceHook tmpth;
1136 int found;
1137 GQuark *f;
1138 struct marker_field *marker_field;
1139
1140 marker_id = marker_get_id_from_info(mdata, info);
1141
1142 tmpth.h = h;
1143 tmpth.mdata = mdata;
1144 tmpth.channel = channel_name;
1145 tmpth.id = marker_id;
1146 tmpth.hook_data = hook_data;
1147 tmpth.fields = g_ptr_array_new();
1148
1149 /* for each field requested */
1150 for(f = fields; f && *f != 0; f++) {
1151 found = 0;
1152 for_each_marker_field(marker_field, info) {
1153 if(marker_field->name == *f) {
1154 found = 1;
1155 g_ptr_array_add(tmpth.fields, marker_field);
1156 break;
1157 }
1158 }
1159 if(!found) {
1160 /* Did not find the one of the fields in this instance of the
1161 marker. Print a warning and skip this marker completely.
1162 Still iterate on other markers with same name. */
1163 g_ptr_array_free(tmpth.fields, TRUE);
1164 g_info("Field %s cannot be found in marker %s.%s",
1165 g_quark_to_string(*f), g_quark_to_string(channel_name),
1166 g_quark_to_string(event_name));
1167 goto skip_marker;
1168 }
1169 }
1170 /* all fields were found: add the tracehook to the array */
1171 *trace_hooks = g_array_append_val(*trace_hooks, tmpth);
1172 skip_marker:
1173 info = info->next;
1174 } while(info != NULL);
1175
1176 /* Error if no new trace hook has been added */
1177 if (init_array_size == (*trace_hooks)->len) {
1178 g_info("No marker of name %s.%s has all requested fields",
1179 g_quark_to_string(channel_name), g_quark_to_string(event_name));
1180 return 1;
1181 }
1182 return 0;
1183 }
1184
1185 void lttv_trace_hook_remove_all(GArray **th)
1186 {
1187 int i;
1188 for(i=0; i<(*th)->len; i++) {
1189 g_ptr_array_free(g_array_index(*th, LttvTraceHook, i).fields, TRUE);
1190 }
1191 if((*th)->len)
1192 *th = g_array_remove_range(*th, 0, (*th)->len);
1193 }
1194
1195 LttvTracesetContextPosition *
1196 lttv_traceset_context_position_new(const LttvTracesetContext *self)
1197 {
1198 guint num_traces = lttv_traceset_number(self->ts);
1199 guint tf_count = 0;
1200 guint i;
1201
1202 for(i=0; i<num_traces;i++) {
1203 GArray * tracefiles = self->traces[i]->tracefiles;
1204 guint j;
1205 guint num_tracefiles = tracefiles->len;
1206 for(j=0;j<num_tracefiles;j++)
1207 tf_count++;
1208 }
1209 LttvTracesetContextPosition *pos = g_new(LttvTracesetContextPosition, 1);
1210 pos->tfcp = g_array_sized_new(FALSE, TRUE,
1211 sizeof(LttvTracefileContextPosition),
1212 tf_count);
1213 g_array_set_size(pos->tfcp, tf_count);
1214 for(i=0;i<pos->tfcp->len;i++) {
1215 LttvTracefileContextPosition *tfcp =
1216 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1217 tfcp->event = ltt_event_position_new();
1218 }
1219
1220 pos->timestamp = ltt_time_infinite;
1221 return pos;
1222 }
1223
1224 /* Save all positions, the ones with infinite time will have NULL
1225 * ep. */
1226 /* note : a position must be destroyed when a trace is added/removed from a
1227 * traceset */
1228 void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1229 LttvTracesetContextPosition *pos)
1230 {
1231 guint i;
1232 guint num_traces = lttv_traceset_number(self->ts);
1233 guint tf_count = 0;
1234
1235 pos->timestamp = ltt_time_infinite;
1236
1237 for(i=0; i<num_traces;i++) {
1238 GArray * tracefiles = self->traces[i]->tracefiles;
1239 guint j;
1240 guint num_tracefiles = tracefiles->len;
1241
1242 for(j=0;j<num_tracefiles;j++) {
1243 g_assert(tf_count < pos->tfcp->len);
1244 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1245 LttvTracefileContext*, j);
1246 LttvTracefileContextPosition *tfcp =
1247 &g_array_index(pos->tfcp, LttvTracefileContextPosition, tf_count);
1248
1249 tfcp->tfc = *tfc;
1250
1251 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1252 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1253 ltt_event_position(event, tfcp->event);
1254 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1255 pos->timestamp = (*tfc)->timestamp;
1256 tfcp->used = TRUE;
1257 } else {
1258 tfcp->used = FALSE;
1259 }
1260
1261 //g_array_append_val(pos->tfc, *tfc);
1262 //g_array_append_val(pos->ep, ep);
1263 tf_count++;
1264 }
1265
1266 }
1267 }
1268
1269 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1270 {
1271 int i;
1272
1273 for(i=0;i<pos->tfcp->len;i++) {
1274 LttvTracefileContextPosition *tfcp =
1275 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1276 g_free(tfcp->event);
1277 tfcp->event = NULL;
1278 tfcp->used = FALSE;
1279 }
1280 g_array_free(pos->tfcp, TRUE);
1281 g_free(pos);
1282 }
1283
1284 void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1285 const LttvTracesetContextPosition *src)
1286 {
1287 int i;
1288 LttvTracefileContextPosition *src_tfcp, *dest_tfcp;
1289
1290 g_assert(src->tfcp->len == dest->tfcp->len);
1291
1292 for(i=0;i<src->tfcp->len;i++) {
1293 src_tfcp =
1294 &g_array_index(src->tfcp, LttvTracefileContextPosition, i);
1295 dest_tfcp =
1296 &g_array_index(dest->tfcp, LttvTracefileContextPosition, i);
1297
1298 dest_tfcp->used = src_tfcp->used;
1299 dest_tfcp->tfc = src_tfcp->tfc;
1300
1301 if(src_tfcp->used) {
1302 ltt_event_position_copy(
1303 dest_tfcp->event,
1304 src_tfcp->event);
1305 }
1306 }
1307 dest->timestamp = src->timestamp;
1308 }
1309
1310 gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1311 const LttvTracesetContextPosition *pos)
1312 {
1313 int i;
1314 int ret = 0;
1315
1316 if(pos->tfcp->len == 0) {
1317 if(lttv_traceset_number(self->ts) == 0) return 0;
1318 else return 1;
1319 }
1320 if(lttv_traceset_number(self->ts) == 0)
1321 return -1;
1322
1323 for(i=0;i<pos->tfcp->len;i++) {
1324 LttvTracefileContextPosition *tfcp =
1325 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1326
1327 if(tfcp->used == FALSE) {
1328 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) < 0) {
1329 ret = -1;
1330 }
1331 } else {
1332 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) == 0) {
1333 ret = 1;
1334 } else {
1335 LttEvent *event = ltt_tracefile_get_event(tfcp->tfc->tf);
1336
1337 ret = ltt_event_position_compare((LttEventPosition*)event,
1338 tfcp->event);
1339 }
1340 }
1341 if(ret != 0) return ret;
1342
1343 }
1344 return 0;
1345 }
1346
1347
1348 gint
1349 lttv_traceset_context_pos_pos_compare(const LttvTracesetContextPosition *pos1,
1350 const LttvTracesetContextPosition *pos2)
1351 {
1352 int i, j;
1353 int ret = 0;
1354
1355 if(ltt_time_compare(pos1->timestamp, ltt_time_infinite) == 0) {
1356 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
1357 return 0;
1358 else
1359 return 1;
1360 }
1361 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
1362 return -1;
1363
1364 for(i=0;i<pos1->tfcp->len;i++) {
1365 LttvTracefileContextPosition *tfcp1 =
1366 &g_array_index(pos1->tfcp, LttvTracefileContextPosition, i);
1367
1368 if(tfcp1->used == TRUE) {
1369 for(j=0;j<pos2->tfcp->len;j++) {
1370 LttvTracefileContextPosition *tfcp2 =
1371 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1372
1373 if(tfcp1->tfc == tfcp2->tfc) {
1374 if(tfcp2->used == TRUE)
1375 ret = ltt_event_position_compare(tfcp1->event, tfcp2->event);
1376 else
1377 ret = -1;
1378
1379 if(ret != 0) return ret;
1380 }
1381 }
1382
1383 } else {
1384 for(j=0;j<pos2->tfcp->len;j++) {
1385 LttvTracefileContextPosition *tfcp2 =
1386 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1387
1388 if(tfcp1->tfc == tfcp2->tfc)
1389 if(tfcp2->used == TRUE) ret = 1;
1390 if(ret != 0) return ret;
1391 }
1392 }
1393 }
1394 return 0;
1395 }
1396
1397
1398 LttTime
1399 lttv_traceset_context_position_get_time(const LttvTracesetContextPosition *pos)
1400 {
1401 return pos->timestamp;
1402 }
1403
1404
1405 LttvTracefileContext *
1406 lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1407 {
1408 GTree *pqueue = self->pqueue;
1409 LttvTracefileContext *tfc = NULL;
1410
1411 g_tree_foreach(pqueue, get_first, &tfc);
1412
1413 return tfc;
1414 }
1415
1416 /* lttv_process_traceset_synchronize_tracefiles
1417 *
1418 * Use the sync_position field of the trace set context to synchronize each
1419 * tracefile with the previously saved position.
1420 *
1421 * If no previous position has been saved, it simply does nothing.
1422 */
1423 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1424 {
1425 int retval;
1426
1427 retval= lttv_process_traceset_seek_position(tsc, tsc->sync_position);
1428 g_assert_cmpint(retval, ==, 0);
1429 }
1430
1431
1432
1433
1434 void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1435 {
1436 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1437 }
1438
1439 struct seek_back_data {
1440 guint first_event; /* Index of the first event in the array : we will always
1441 overwrite at this position : this is a circular array.
1442 */
1443 guint events_found;
1444 guint n; /* number of events requested */
1445 GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
1446 LttvFilter *filter1;
1447 LttvFilter *filter2;
1448 LttvFilter *filter3;
1449 gpointer data;
1450 check_handler *check;
1451 gboolean *stop_flag;
1452 guint raw_event_count;
1453 };
1454
1455 static gint seek_back_event_hook(void *hook_data, void* call_data)
1456 {
1457 struct seek_back_data *sd = (struct seek_back_data*)hook_data;
1458 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1459 LttvTracesetContext *tsc = tfc->t_context->ts_context;
1460 LttvTracesetContextPosition *pos;
1461
1462 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
1463 return TRUE;
1464 sd->raw_event_count++;
1465
1466 if(sd->filter1 != NULL && sd->filter1->head != NULL &&
1467 !lttv_filter_tree_parse(sd->filter1->head,
1468 ltt_tracefile_get_event(tfc->tf),
1469 tfc->tf,
1470 tfc->t_context->t,
1471 tfc,NULL,NULL)) {
1472 return FALSE;
1473 }
1474 if(sd->filter2 != NULL && sd->filter2->head != NULL &&
1475 !lttv_filter_tree_parse(sd->filter2->head,
1476 ltt_tracefile_get_event(tfc->tf),
1477 tfc->tf,
1478 tfc->t_context->t,
1479 tfc,NULL,NULL)) {
1480 return FALSE;
1481 }
1482 if(sd->filter3 != NULL && sd->filter3->head != NULL &&
1483 !lttv_filter_tree_parse(sd->filter3->head,
1484 ltt_tracefile_get_event(tfc->tf),
1485 tfc->tf,
1486 tfc->t_context->t,
1487 tfc,NULL,NULL)) {
1488 return FALSE;
1489 }
1490
1491 pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array,
1492 sd->first_event);
1493
1494 lttv_traceset_context_position_save(tsc, pos);
1495
1496 if(sd->first_event >= sd->array->len - 1) sd->first_event = 0;
1497 else sd->first_event++;
1498
1499 sd->events_found = min(sd->n, sd->events_found + 1);
1500
1501 return FALSE;
1502 }
1503
1504 /* Seek back n events back from the current position.
1505 *
1506 * Parameters :
1507 * @self The trace set context
1508 * @n number of events to jump over
1509 * @first_offset The initial offset value used.
1510 * never put first_offset at ltt_time_zero.
1511 * @time_seeker Function pointer of the function to use to seek time :
1512 * either lttv_process_traceset_seek_time
1513 * or lttv_state_traceset_seek_time_closest
1514 * @filter The filter to call.
1515 *
1516 * Return value : the number of events found (might be lower than the number
1517 * requested if beginning of traceset is reached).
1518 *
1519 * The first search will go back first_offset and try to find the last n events
1520 * matching the filter. If there are not enough, it will try to go back from the
1521 * new trace point from first_offset*2, and so on, until beginning of trace or n
1522 * events are found.
1523 *
1524 * Note : this function does not take in account the LttvFilter : use the
1525 * similar function found in state.c instead.
1526 *
1527 * Note2 : the caller must make sure that the LttvTracesetContext does not
1528 * contain any hook, as process_traceset_middle is used in this routine.
1529 */
1530 guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
1531 guint n, LttTime first_offset,
1532 seek_time_fct time_seeker,
1533 check_handler *check,
1534 gboolean *stop_flag,
1535 LttvFilter *filter1,
1536 LttvFilter *filter2,
1537 LttvFilter *filter3,
1538 gpointer data)
1539 {
1540 if(lttv_traceset_number(self->ts) == 0) return 0;
1541 g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
1542
1543 guint i;
1544 LttvTracesetContextPosition *next_iter_end_pos =
1545 lttv_traceset_context_position_new(self);
1546 LttvTracesetContextPosition *end_pos =
1547 lttv_traceset_context_position_new(self);
1548 LttvTracesetContextPosition *saved_pos =
1549 lttv_traceset_context_position_new(self);
1550 LttTime time;
1551 LttTime asked_time;
1552 LttTime time_offset;
1553 struct seek_back_data sd;
1554 LttvHooks *hooks = lttv_hooks_new();
1555 int retval;
1556
1557 sd.first_event = 0;
1558 sd.events_found = 0;
1559 sd.array = g_ptr_array_sized_new(n);
1560 sd.filter1 = filter1;
1561 sd.filter2 = filter2;
1562 sd.filter3 = filter3;
1563 sd.data = data;
1564 sd.n = n;
1565 sd.check = check;
1566 sd.stop_flag = stop_flag;
1567 sd.raw_event_count = 0;
1568 g_ptr_array_set_size(sd.array, n);
1569 for(i=0;i<n;i++) {
1570 g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new(self);
1571 }
1572
1573 lttv_traceset_context_position_save(self, next_iter_end_pos);
1574 lttv_traceset_context_position_save(self, saved_pos);
1575 /* Get the current time from which we will offset */
1576 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1577 /* the position saved might be end of traceset... */
1578 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1579 time = self->time_span.end_time;
1580 }
1581 time_offset = first_offset;
1582
1583 lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT);
1584
1585 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1586
1587 while(1) {
1588 lttv_traceset_context_position_copy(end_pos, next_iter_end_pos);
1589
1590 /* We must seek the traceset back to time - time_offset */
1591 /* this time becomes the new reference time */
1592 if(ltt_time_compare(time, time_offset) > 0)
1593 time = ltt_time_sub(time, time_offset);
1594 else
1595 time = self->time_span.start_time;
1596 asked_time = time;
1597
1598 time_seeker(self, time);
1599 lttv_traceset_context_position_save(self, next_iter_end_pos);
1600 /* Resync the time in case of a seek_closest */
1601 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1602 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1603 time = self->time_span.end_time;
1604 }
1605
1606 /* Process the traceset, calling a hook which adds events
1607 * to the array, overwriting the tail. It changes first_event and
1608 * events_found too. */
1609 /* We would like to have a clean context here : no other hook than our's */
1610
1611 lttv_process_traceset_middle(self, ltt_time_infinite,
1612 G_MAXUINT, end_pos);
1613
1614 /* stop criteria : - n events found
1615 * - asked_time < beginning of trace */
1616 if(sd.events_found < n) {
1617 if(sd.first_event > 0) {
1618 /* Save the first position */
1619 LttvTracesetContextPosition *pos =
1620 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0);
1621 lttv_traceset_context_position_copy(saved_pos, pos);
1622 }
1623 g_assert(n-sd.events_found <= sd.array->len);
1624 /* Change array size to n - events_found */
1625 for(i=n-sd.events_found;i<sd.array->len;i++) {
1626 LttvTracesetContextPosition *pos =
1627 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1628 lttv_traceset_context_position_destroy(pos);
1629 }
1630 g_ptr_array_set_size(sd.array, n-sd.events_found);
1631 sd.first_event = 0;
1632
1633 /*
1634 * Did not fill our event list and started before the beginning of the
1635 * trace. There is no hope to fill it then.
1636 * It is OK to compare with trace start time here because we explicitely
1637 * seeked by time (not by position), so we cannot miss multiple event
1638 * happening exactly at trace start.
1639 */
1640 if(ltt_time_compare(asked_time, self->time_span.start_time) == 0)
1641 break;
1642
1643 } else break; /* Second end criterion : n events found */
1644
1645 time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL);
1646 }
1647
1648 lttv_traceset_context_position_destroy(end_pos);
1649 lttv_traceset_context_position_destroy(next_iter_end_pos);
1650
1651 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1652
1653 if(sd.events_found >= n) {
1654 /* Seek the traceset to the first event in the circular array */
1655 LttvTracesetContextPosition *pos =
1656 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array,
1657 sd.first_event);
1658 retval= lttv_process_traceset_seek_position(self, pos);
1659 g_assert_cmpint(retval, ==, 0);
1660 } else {
1661 /* Will seek to the last saved position : in the worst case, it will be the
1662 * original position (if events_found is 0) */
1663 retval= lttv_process_traceset_seek_position(self, saved_pos);
1664 g_assert_cmpint(retval, ==, 0);
1665 }
1666
1667 for(i=0;i<sd.array->len;i++) {
1668 LttvTracesetContextPosition *pos =
1669 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1670 lttv_traceset_context_position_destroy(pos);
1671 }
1672 g_ptr_array_free(sd.array, TRUE);
1673
1674 lttv_hooks_destroy(hooks);
1675
1676 lttv_traceset_context_position_destroy(saved_pos);
1677
1678 return sd.events_found;
1679 }
1680
1681
1682 struct seek_forward_data {
1683 guint event_count; /* event counter */
1684 guint n; /* requested number of events to jump over */
1685 LttvFilter *filter1;
1686 LttvFilter *filter2;
1687 LttvFilter *filter3;
1688 gpointer data;
1689 check_handler *check;
1690 gboolean *stop_flag;
1691 guint raw_event_count; /* event counter */
1692 };
1693
1694 static gint seek_forward_event_hook(void *hook_data, void* call_data)
1695 {
1696 struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
1697 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1698
1699 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
1700 return TRUE;
1701 sd->raw_event_count++;
1702
1703 if(sd->filter1 != NULL && sd->filter1->head != NULL &&
1704 !lttv_filter_tree_parse(sd->filter1->head,
1705 ltt_tracefile_get_event(tfc->tf),
1706 tfc->tf,
1707 tfc->t_context->t,
1708 tfc,NULL,NULL)) {
1709 return FALSE;
1710 }
1711 if(sd->filter2 != NULL && sd->filter2->head != NULL &&
1712 !lttv_filter_tree_parse(sd->filter2->head,
1713 ltt_tracefile_get_event(tfc->tf),
1714 tfc->tf,
1715 tfc->t_context->t,
1716 tfc,NULL,NULL)) {
1717 return FALSE;
1718 }
1719 if(sd->filter3 != NULL && sd->filter3->head != NULL &&
1720 !lttv_filter_tree_parse(sd->filter3->head,
1721 ltt_tracefile_get_event(tfc->tf),
1722 tfc->tf,
1723 tfc->t_context->t,
1724 tfc,NULL,NULL)) {
1725 return FALSE;
1726 }
1727
1728 sd->event_count++;
1729 if(sd->event_count >= sd->n)
1730 return TRUE;
1731 return FALSE;
1732 }
1733
1734 /* Seek back n events forward from the current position (1 to n)
1735 * 0 is ok too, but it will actually do nothing.
1736 *
1737 * Parameters :
1738 * @self the trace set context
1739 * @n number of events to jump over
1740 * @filter filter to call.
1741 *
1742 * returns : the number of events jumped over (may be less than requested if end
1743 * of traceset reached) */
1744 guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
1745 guint n,
1746 check_handler *check,
1747 gboolean *stop_flag,
1748 LttvFilter *filter1,
1749 LttvFilter *filter2,
1750 LttvFilter *filter3,
1751 gpointer data)
1752 {
1753 struct seek_forward_data sd;
1754 sd.event_count = 0;
1755 sd.n = n;
1756 sd.filter1 = filter1;
1757 sd.filter2 = filter2;
1758 sd.filter3 = filter3;
1759 sd.data = data;
1760 sd.check = check;
1761 sd.stop_flag = stop_flag;
1762 sd.raw_event_count = 0;
1763
1764 if(sd.event_count >= sd.n) return sd.event_count;
1765
1766 LttvHooks *hooks = lttv_hooks_new();
1767
1768 lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
1769
1770 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1771
1772 /* it will end on the end of traceset, or the fact that the
1773 * hook returns TRUE.
1774 */
1775 lttv_process_traceset_middle(self, ltt_time_infinite,
1776 G_MAXUINT, NULL);
1777
1778 /* Here, our position is either the end of traceset, or the exact position
1779 * after n events : leave it like this. This might be placed on an event that
1780 * will be filtered out, we don't care : all we know is that the following
1781 * event filtered in will be the right one. */
1782
1783 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1784
1785 lttv_hooks_destroy(hooks);
1786
1787 return sd.event_count;
1788 }
1789
1790
This page took 0.126572 seconds and 4 git commands to generate.