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