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