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