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