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