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