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