seek time refix
[lttv.git] / ltt / branches / poly / 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>
d8f124de 24#include <lttv/tracecontext.h>
ffd54a90 25#include <ltt/event.h>
b445142a 26#include <ltt/facility.h>
a5dcde2f 27#include <ltt/trace.h>
28#include <ltt/type.h>
33e44b82 29#include <lttv/filter.h>
27304273 30#include <errno.h>
dc877563 31
0bd2f89c 32#define min(a,b) (((a)<(b))?(a):(b))
8697a616 33
34
27304273 35gint compare_tracefile(gconstpointer a, gconstpointer b)
8697a616 36{
cf94ff67 37 gint comparison = 0;
8697a616 38
00e74b69 39 const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
00e74b69 40 const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
8697a616 41
1d1df11d 42 if(likely(trace_a != trace_b)) {
8fe3c6b6 43 comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
1d1df11d 44 if(unlikely(comparison == 0)) {
a855f059 45 if(trace_a->index < trace_b->index) comparison = -1;
46 else if(trace_a->index > trace_b->index) comparison = 1;
47 else if(trace_a->t_context->index < trace_b->t_context->index)
48 comparison = -1;
49 else if(trace_a->t_context->index > trace_b->t_context->index)
50 comparison = 1;
51 }
cf94ff67 52 }
cf94ff67 53 return comparison;
8697a616 54}
55
8697a616 56struct _LttvTracesetContextPosition {
27304273 57 GArray *ep; /* Array of LttEventPosition */
58 GArray *tfc; /* Array of corresponding
59 TracefileContext* */
18c87975 60 LttTime timestamp; /* Current time at the saved position */
61 /* If ltt_time_infinite : no position is
62 * set, else, a position is set (may be end
63 * of trace, with ep->len == 0) */
8697a616 64};
65
ffd54a90 66void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
dc877563 67{
ffd54a90 68 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
dc877563 69}
70
71
72void lttv_context_fini(LttvTracesetContext *self)
73{
74 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
75}
76
77
78LttvTracesetContext *
79lttv_context_new_traceset_context(LttvTracesetContext *self)
80{
81 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
82}
83
84
85
86
87LttvTraceContext *
88lttv_context_new_trace_context(LttvTracesetContext *self)
89{
90 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
91}
92
93
94LttvTracefileContext *
95lttv_context_new_tracefile_context(LttvTracesetContext *self)
96{
c6bc9cb9 97 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
dc877563 98}
99
f7afe191 100/****************************************************************************
101 * lttv_traceset_context_compute_time_span
102 *
8697a616 103 * Keep the time span is sync with on the fly addition and removal of traces
f7afe191 104 * in a trace set. It must be called each time a trace is added/removed from
105 * the traceset. It could be more efficient to call it only once a bunch
106 * of traces are loaded, but the calculation is not long, so it's not
107 * critical.
108 *
109 * Author : Xang Xiu Yang
f7afe191 110 ***************************************************************************/
111static void lttv_traceset_context_compute_time_span(
112 LttvTracesetContext *self,
33f7a12c 113 TimeInterval *time_span)
f7afe191 114{
115 LttvTraceset * traceset = self->ts;
116 int numTraces = lttv_traceset_number(traceset);
117 int i;
118 LttTime s, e;
119 LttvTraceContext *tc;
120 LttTrace * trace;
121
33f7a12c 122 time_span->start_time.tv_sec = 0;
123 time_span->start_time.tv_nsec = 0;
124 time_span->end_time.tv_sec = 0;
125 time_span->end_time.tv_nsec = 0;
912be9a5 126
f7afe191 127 for(i=0; i<numTraces;i++){
128 tc = self->traces[i];
129 trace = tc->t;
130
131 ltt_trace_time_span_get(trace, &s, &e);
132
133 if(i==0){
33f7a12c 134 time_span->start_time = s;
135 time_span->end_time = e;
f7afe191 136 }else{
33f7a12c 137 if(s.tv_sec < time_span->start_time.tv_sec
138 || (s.tv_sec == time_span->start_time.tv_sec
139 && s.tv_nsec < time_span->start_time.tv_nsec))
140 time_span->start_time = s;
141 if(e.tv_sec > time_span->end_time.tv_sec
142 || (e.tv_sec == time_span->end_time.tv_sec
143 && e.tv_nsec > time_span->end_time.tv_nsec))
144 time_span->end_time = e;
f7afe191 145 }
146 }
147}
148
eed2ef37 149static void init_tracefile_context(LttTracefile *tracefile,
150 LttvTraceContext *tc)
151{
152 LttvTracefileContext *tfc;
153 LttvTracesetContext *tsc = tc->ts_context;
154
155 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(tsc)->new_tracefile_context(tsc);
156
157 tfc->index = tc->tracefiles->len;
158 tc->tracefiles = g_array_append_val(tc->tracefiles, tfc);
159
160 tfc->tf = tracefile;
161
162 tfc->t_context = tc;
163 tfc->event = lttv_hooks_new();
164 tfc->event_by_id = lttv_hooks_by_id_new();
165 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
166}
167
dc877563 168
169static void
170init(LttvTracesetContext *self, LttvTraceset *ts)
171{
327a4314 172 guint i, nb_trace;
dc877563 173
174 LttvTraceContext *tc;
175
3865ea09 176 GData **tracefiles_groups;
dc877563 177
eed2ef37 178 struct compute_tracefile_group_args args;
308711e5 179
dc877563 180 nb_trace = lttv_traceset_number(ts);
181 self->ts = ts;
ffd54a90 182 self->traces = g_new(LttvTraceContext *, nb_trace);
ffd54a90 183 self->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
308711e5 184 self->ts_a = lttv_traceset_attribute(ts);
18c87975 185 self->sync_position = lttv_traceset_context_position_new();
dc877563 186 for(i = 0 ; i < nb_trace ; i++) {
ffd54a90 187 tc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
dc877563 188 self->traces[i] = tc;
189
190 tc->ts_context = self;
191 tc->index = i;
308711e5 192 tc->vt = lttv_traceset_get(ts, i);
193 tc->t = lttv_trace(tc->vt);
ffd54a90 194 tc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
308711e5 195 tc->t_a = lttv_trace_attribute(tc->vt);
3865ea09 196 tc->tracefiles = g_array_sized_new(FALSE, TRUE,
197 sizeof(LttvTracefileContext*), 10);
eed2ef37 198
199 tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t);
e45551ac 200 if(tracefiles_groups != NULL) {
201 args.func = (ForEachTraceFileFunc)init_tracefile_context;
202 args.func_args = tc;
eed2ef37 203
e45551ac 204 g_datalist_foreach(tracefiles_groups,
205 (GDataForeachFunc)compute_tracefile_group,
206 &args);
207 }
eed2ef37 208
209#if 0
dc877563 210 nb_control = ltt_trace_control_tracefile_number(tc->t);
211 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
212 nb_tracefile = nb_control + nb_per_cpu;
dbb7bb09 213 tc->tracefiles = g_new(LttvTracefileContext *, nb_tracefile);
dc877563 214
215 for(j = 0 ; j < nb_tracefile ; j++) {
ffd54a90 216 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
dbb7bb09 217 tc->tracefiles[j] = tfc;
218 tfc->index = j;
219
dc877563 220 if(j < nb_control) {
dc877563 221 tfc->control = TRUE;
ffd54a90 222 tfc->tf = ltt_trace_control_tracefile_get(tc->t, j);
dc877563 223 }
224 else {
dc877563 225 tfc->control = FALSE;
ffd54a90 226 tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
dc877563 227 }
eed2ef37 228
dc877563 229 tfc->t_context = tc;
d3e01c7a 230 tfc->e = ltt_event_new();
8697a616 231 tfc->event = lttv_hooks_new();
232 tfc->event_by_id = lttv_hooks_by_id_new();
ffd54a90 233 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
dc877563 234 }
eed2ef37 235#endif //0
236
dc877563 237 }
2d262115 238 self->pqueue = g_tree_new(compare_tracefile);
eed2ef37 239 lttv_process_traceset_seek_time(self, ltt_time_zero);
33f7a12c 240 lttv_traceset_context_compute_time_span(self, &self->time_span);
8697a616 241
dc877563 242}
243
244
245void fini(LttvTracesetContext *self)
246{
dbb7bb09 247 guint i, j, nb_trace, nb_tracefile;
dc877563 248
249 LttvTraceContext *tc;
250
1986f254 251 LttvTracefileContext **tfc;
dc877563 252
ffd54a90 253 LttvTraceset *ts = self->ts;
dc877563 254
8697a616 255 g_tree_destroy(self->pqueue);
2061e03d 256 g_object_unref(self->a);
18c87975 257 lttv_traceset_context_position_destroy(self->sync_position);
dc877563 258
259 nb_trace = lttv_traceset_number(ts);
260
261 for(i = 0 ; i < nb_trace ; i++) {
262 tc = self->traces[i];
263
ffd54a90 264 g_object_unref(tc->a);
dc877563 265
eed2ef37 266 nb_tracefile = tc->tracefiles->len;
dc877563 267
268 for(j = 0 ; j < nb_tracefile ; j++) {
1986f254 269 tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, j);
270 lttv_hooks_destroy((*tfc)->event);
271 lttv_hooks_by_id_destroy((*tfc)->event_by_id);
272 g_object_unref((*tfc)->a);
273 g_object_unref(*tfc);
dc877563 274 }
eed2ef37 275 g_array_free(tc->tracefiles, TRUE);
dc877563 276 g_object_unref(tc);
277 }
278 g_free(self->traces);
279}
280
281
282void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
8697a616 283 LttvHooks *before_traceset,
dc877563 284 LttvHooks *before_trace,
ffd54a90 285 LttvHooks *before_tracefile,
8697a616 286 LttvHooks *event,
287 LttvHooksById *event_by_id)
dc877563 288{
289 LttvTraceset *ts = self->ts;
290
8697a616 291 guint i, nb_trace;
dc877563 292
293 LttvTraceContext *tc;
294
8697a616 295 lttv_hooks_call(before_traceset, self);
dc877563 296
dc877563 297 nb_trace = lttv_traceset_number(ts);
298
299 for(i = 0 ; i < nb_trace ; i++) {
300 tc = self->traces[i];
8697a616 301 lttv_trace_context_add_hooks(tc,
302 before_trace,
303 before_tracefile,
304 event,
305 event_by_id);
dc877563 306 }
307}
308
309
310void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
dc877563 311 LttvHooks *after_traceset,
dc877563 312 LttvHooks *after_trace,
ffd54a90 313 LttvHooks *after_tracefile,
8697a616 314 LttvHooks *event,
315 LttvHooksById *event_by_id)
dc877563 316{
8697a616 317
dc877563 318 LttvTraceset *ts = self->ts;
319
8697a616 320 guint i, nb_trace;
dc877563 321
322 LttvTraceContext *tc;
323
dc877563 324 nb_trace = lttv_traceset_number(ts);
325
326 for(i = 0 ; i < nb_trace ; i++) {
327 tc = self->traces[i];
8697a616 328 lttv_trace_context_remove_hooks(tc,
329 after_trace,
330 after_tracefile,
331 event,
332 event_by_id);
dc877563 333 }
8697a616 334
335 lttv_hooks_call(after_traceset, self);
336
337
dc877563 338}
339
8697a616 340void lttv_trace_context_add_hooks(LttvTraceContext *self,
341 LttvHooks *before_trace,
342 LttvHooks *before_tracefile,
343 LttvHooks *event,
344 LttvHooksById *event_by_id)
a8c0f09d 345{
8697a616 346 guint i, nb_tracefile;
347
1986f254 348 LttvTracefileContext **tfc;
8697a616 349
350 lttv_hooks_call(before_trace, self);
eed2ef37 351
352 nb_tracefile = self->tracefiles->len;
8697a616 353
354 for(i = 0 ; i < nb_tracefile ; i++) {
1986f254 355 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
356 lttv_tracefile_context_add_hooks(*tfc,
8697a616 357 before_tracefile,
358 event,
359 event_by_id);
360 }
a8c0f09d 361}
362
8697a616 363
364
365void lttv_trace_context_remove_hooks(LttvTraceContext *self,
366 LttvHooks *after_trace,
367 LttvHooks *after_tracefile,
368 LttvHooks *event,
369 LttvHooksById *event_by_id)
a8c0f09d 370{
8697a616 371 guint i, nb_tracefile;
372
1986f254 373 LttvTracefileContext **tfc;
8697a616 374
eed2ef37 375 nb_tracefile = self->tracefiles->len;
8697a616 376
377 for(i = 0 ; i < nb_tracefile ; i++) {
1986f254 378 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
379 lttv_tracefile_context_remove_hooks(*tfc,
8697a616 380 after_tracefile,
381 event,
382 event_by_id);
383 }
384
385 lttv_hooks_call(after_trace, self);
a8c0f09d 386}
387
8697a616 388void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
389 LttvHooks *before_tracefile,
390 LttvHooks *event,
391 LttvHooksById *event_by_id)
a8c0f09d 392{
9d239bd9 393 guint i, index;
8697a616 394
395 LttvHooks *hook;
396
397 lttv_hooks_call(before_tracefile, self);
398 lttv_hooks_add_list(self->event, event);
9d239bd9 399 if(event_by_id != NULL) {
400 for(i = 0; i < event_by_id->array->len; i++) {
401 index = g_array_index(event_by_id->array, guint, i);
402 hook = lttv_hooks_by_id_find(self->event_by_id, index);
403 lttv_hooks_add_list(hook, lttv_hooks_by_id_get(event_by_id, index));
8697a616 404 }
9d239bd9 405 }
a8c0f09d 406}
407
8697a616 408void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
409 LttvHooks *after_tracefile,
410 LttvHooks *event,
411 LttvHooksById *event_by_id)
a8c0f09d 412{
9d239bd9 413 guint i, index;
8697a616 414
415 LttvHooks *hook;
416
8697a616 417 lttv_hooks_remove_list(self->event, event);
9d239bd9 418 if(event_by_id != NULL) {
419 for(i = 0; i < event_by_id->array->len; i++) {
420 index = g_array_index(event_by_id->array, guint, i);
421 hook = lttv_hooks_by_id_get(self->event_by_id, index);
41a9e0c3 422 if(hook != NULL)
9d239bd9 423 lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, index));
8697a616 424 }
9d239bd9 425 }
8697a616 426
427 lttv_hooks_call(after_tracefile, self);
a8c0f09d 428}
429
8697a616 430
431
a8c0f09d 432void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext *tfc,
433 unsigned i,
8697a616 434 LttvHooks *event_by_id)
a8c0f09d 435{
436 LttvHooks * h;
8697a616 437 h = lttv_hooks_by_id_find(tfc->event_by_id, i);
438 lttv_hooks_add_list(h, event_by_id);
a8c0f09d 439}
440
441void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext *tfc,
442 unsigned i)
443{
8697a616 444 lttv_hooks_by_id_remove(tfc->event_by_id, i);
a8c0f09d 445}
dc877563 446
ba576a78 447static LttvTracesetContext *
dc877563 448new_traceset_context(LttvTracesetContext *self)
449{
ffd54a90 450 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
dc877563 451}
452
453
ba576a78 454static LttvTraceContext *
dc877563 455new_trace_context(LttvTracesetContext *self)
456{
ffd54a90 457 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
dc877563 458}
459
460
ba576a78 461static LttvTracefileContext *
dc877563 462new_tracefile_context(LttvTracesetContext *self)
463{
ffd54a90 464 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
dc877563 465}
466
467
468static void
469traceset_context_instance_init (GTypeInstance *instance, gpointer g_class)
470{
471 /* Be careful of anything which would not work well with shallow copies */
472}
473
474
475static void
476traceset_context_finalize (LttvTracesetContext *self)
477{
b445142a 478 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE)))
479 ->finalize(G_OBJECT(self));
dc877563 480}
481
482
483static void
484traceset_context_class_init (LttvTracesetContextClass *klass)
485{
486 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
487
ffd54a90 488 gobject_class->finalize = (void (*)(GObject *self))traceset_context_finalize;
dc877563 489 klass->init = init;
490 klass->fini = fini;
491 klass->new_traceset_context = new_traceset_context;
492 klass->new_trace_context = new_trace_context;
493 klass->new_tracefile_context = new_tracefile_context;
494}
495
496
497GType
ffd54a90 498lttv_traceset_context_get_type(void)
dc877563 499{
500 static GType type = 0;
501 if (type == 0) {
502 static const GTypeInfo info = {
ffd54a90 503 sizeof (LttvTracesetContextClass),
dc877563 504 NULL, /* base_init */
505 NULL, /* base_finalize */
ffd54a90 506 (GClassInitFunc) traceset_context_class_init, /* class_init */
dc877563 507 NULL, /* class_finalize */
508 NULL, /* class_data */
ffd54a90 509 sizeof (LttvTracesetContext),
dc877563 510 0, /* n_preallocs */
00e74b69 511 (GInstanceInitFunc) traceset_context_instance_init, /* instance_init */
512 NULL /* Value handling */
dc877563 513 };
514
ffd54a90 515 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType",
dc877563 516 &info, 0);
517 }
518 return type;
519}
520
521
522static void
523trace_context_instance_init (GTypeInstance *instance, gpointer g_class)
524{
525 /* Be careful of anything which would not work well with shallow copies */
526}
527
528
529static void
530trace_context_finalize (LttvTraceContext *self)
531{
b445142a 532 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))->
533 finalize(G_OBJECT(self));
dc877563 534}
535
536
537static void
538trace_context_class_init (LttvTraceContextClass *klass)
539{
540 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
541
ffd54a90 542 gobject_class->finalize = (void (*)(GObject *self)) trace_context_finalize;
dc877563 543}
544
545
546GType
ffd54a90 547lttv_trace_context_get_type(void)
dc877563 548{
549 static GType type = 0;
550 if (type == 0) {
551 static const GTypeInfo info = {
ffd54a90 552 sizeof (LttvTraceContextClass),
dc877563 553 NULL, /* base_init */
554 NULL, /* base_finalize */
ffd54a90 555 (GClassInitFunc) trace_context_class_init, /* class_init */
dc877563 556 NULL, /* class_finalize */
557 NULL, /* class_data */
c6bc9cb9 558 sizeof (LttvTraceContext),
dc877563 559 0, /* n_preallocs */
00e74b69 560 (GInstanceInitFunc) trace_context_instance_init, /* instance_init */
561 NULL /* Value handling */
dc877563 562 };
563
ffd54a90 564 type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType",
dc877563 565 &info, 0);
566 }
567 return type;
568}
569
570
571static void
572tracefile_context_instance_init (GTypeInstance *instance, gpointer g_class)
573{
574 /* Be careful of anything which would not work well with shallow copies */
575}
576
577
578static void
579tracefile_context_finalize (LttvTracefileContext *self)
580{
b445142a 581 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE)))
582 ->finalize(G_OBJECT(self));
dc877563 583}
584
585
586static void
587tracefile_context_class_init (LttvTracefileContextClass *klass)
588{
589 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
590
ffd54a90 591 gobject_class->finalize = (void (*)(GObject *self))tracefile_context_finalize;
592}
593
594
595GType
596lttv_tracefile_context_get_type(void)
597{
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 */
00e74b69 609 (GInstanceInitFunc) tracefile_context_instance_init, /* instance_init */
610 NULL /* Value handling */
ffd54a90 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) {
77199e93 622 g_assert(key == value);
dc877563 623 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
624 return TRUE;
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
77199e93 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);
e7f5e89d 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;
77199e93 649
77199e93 650
651 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
698e81c2 652 return FALSE;
653}
e7f5e89d 654#endif //DEBUG
698e81c2 655
656
dc877563 657
8697a616 658void lttv_process_traceset_begin(LttvTracesetContext *self,
659 LttvHooks *before_traceset,
660 LttvHooks *before_trace,
661 LttvHooks *before_tracefile,
662 LttvHooks *event,
663 LttvHooksById *event_by_id)
664{
dc877563 665
8697a616 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);
674
2a2fa4f0 675}
676
36d36c9f 677enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
678
8697a616 679/* Note : a _middle must be preceded from a _seek or another middle */
680guint lttv_process_traceset_middle(LttvTracesetContext *self,
681 LttTime end,
b8eccacd 682 guint nb_events,
8697a616 683 const LttvTracesetContextPosition *end_position)
2a2fa4f0 684{
685 GTree *pqueue = self->pqueue;
686
698e81c2 687 guint fac_id, ev_id, id;
2a2fa4f0 688
2a2fa4f0 689 LttvTracefileContext *tfc;
690
eed2ef37 691 LttEvent *e;
692
2a2fa4f0 693 unsigned count = 0;
694
36d36c9f 695 guint read_ret;
696
697 enum read_state last_read_state = LAST_NONE;
698e81c2 698
a54f091a 699 gboolean last_ret = FALSE; /* return value of the last hook list called */
700
dc877563 701 /* Get the next event from the pqueue, call its hooks,
702 reinsert in the pqueue the following event from the same tracefile
703 unless the tracefile is finished or the event is later than the
8697a616 704 end time. */
dc877563 705
ffd54a90 706 while(TRUE) {
dc877563 707 tfc = NULL;
708 g_tree_foreach(pqueue, get_first, &tfc);
33f7a12c 709 /* End of traceset : tfc is NULL */
1d1df11d 710 if(unlikely(tfc == NULL))
a43d67ba 711 {
a43d67ba 712 return count;
713 }
dc877563 714
8697a616 715 /* Have we reached :
716 * - the maximum number of events specified?
717 * - the end position ?
718 * - the end time ?
719 * then the read is finished. We leave the queue in the same state and
720 * break the loop.
721 */
722
1d1df11d 723 if(unlikely(last_ret == TRUE ||
d052ffc3 724 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
8b0bbe19 725 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
726 end_position) == 0)||
1d1df11d 727 ltt_time_compare(end, tfc->timestamp) <= 0))
a43d67ba 728 {
a43d67ba 729 return count;
730 }
36d36c9f 731
308711e5 732 /* Get the tracefile with an event for the smallest time found. If two
733 or more tracefiles have events for the same time, hope that lookup
734 and remove are consistent. */
1986f254 735
736#ifdef DEBUG
e7f5e89d 737 test_time.tv_sec = 0;
738 test_time.tv_nsec = 0;
77199e93 739 g_debug("test tree before remove");
740 g_tree_foreach(pqueue, test_tree, tfc);
1986f254 741#endif //DEBUG
f95bc830 742 g_tree_remove(pqueue, tfc);
698e81c2 743
1986f254 744#ifdef DEBUG
e7f5e89d 745 test_time.tv_sec = 0;
746 test_time.tv_nsec = 0;
77199e93 747 g_debug("test tree after remove");
698e81c2 748 g_tree_foreach(pqueue, test_tree, tfc);
1986f254 749#endif //DEBUG
77199e93 750
eed2ef37 751 e = ltt_tracefile_get_event(tfc->tf);
dc877563 752
36d36c9f 753 if(last_read_state != LAST_EMPTY) {
754 /* Only call hooks if the last read has given an event or if we are at the
755 * first pass (not if last read returned end of tracefile) */
756 count++;
757
758 fac_id = ltt_event_facility_id(e);
759 ev_id = ltt_event_eventtype_id(e);
760 id = GET_HOOK_ID(fac_id, ev_id);
761 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
762 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
763 }
764
698e81c2 765 read_ret = ltt_tracefile_read(tfc->tf);
766
767 if(likely(!read_ret)) {
3054461a 768 //g_debug("An event is ready");
eed2ef37 769 tfc->timestamp = ltt_event_time(e);
e7f5e89d 770 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
33f7a12c 771 g_tree_insert(pqueue, tfc, tfc);
e7f5e89d 772#ifdef DEBUG
773 test_time.tv_sec = 0;
774 test_time.tv_nsec = 0;
775 g_debug("test tree after event ready");
776 g_tree_foreach(pqueue, test_tree, NULL);
777#endif //DEBUG
778
36d36c9f 779 last_read_state = LAST_OK;
698e81c2 780 } else {
1986f254 781 tfc->timestamp = ltt_time_infinite;
782
36d36c9f 783 if(read_ret == ERANGE) {
784 last_read_state = LAST_EMPTY;
698e81c2 785 g_debug("End of trace");
36d36c9f 786 } else
698e81c2 787 g_error("Error happened in lttv_process_traceset_middle");
dc877563 788 }
789 }
2a2fa4f0 790}
791
792
8697a616 793void lttv_process_traceset_end(LttvTracesetContext *self,
794 LttvHooks *after_traceset,
795 LttvHooks *after_trace,
796 LttvHooks *after_tracefile,
797 LttvHooks *event,
798 LttvHooksById *event_by_id)
2a2fa4f0 799{
8697a616 800 /* Remove hooks from context. _after hooks are called by remove_hooks. */
801 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
802 lttv_traceset_context_remove_hooks(self,
803 after_traceset,
804 after_trace,
805 after_tracefile,
806 event,
807 event_by_id);
808}
2a2fa4f0 809
27304273 810/* Subtile modification :
811 * if tracefile has no event at or after the time requested, it is not put in
348c6ba8 812 * the queue, as the next read would fail.
813 *
814 * Don't forget to empty the traceset pqueue before calling this.
815 */
8697a616 816void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
817{
818 guint i, nb_tracefile;
2a2fa4f0 819
eed2ef37 820 gint ret;
821
1986f254 822 LttvTracefileContext **tfc;
2a2fa4f0 823
eed2ef37 824 nb_tracefile = self->tracefiles->len;
dc877563 825
e7f5e89d 826 GTree *pqueue = self->ts_context->pqueue;
827
8697a616 828 for(i = 0 ; i < nb_tracefile ; i++) {
1986f254 829 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
77199e93 830
e7f5e89d 831 //g_tree_remove(pqueue, *tfc);
77199e93 832
1986f254 833 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
27304273 834 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
27304273 835
836 if(ret == 0) { /* not ERANGE especially */
1986f254 837 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
e7f5e89d 838 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
1986f254 839 g_tree_insert(pqueue, (*tfc), (*tfc));
840 } else {
841 (*tfc)->timestamp = ltt_time_infinite;
27304273 842 }
8697a616 843 }
e7f5e89d 844#ifdef DEBUG
845 test_time.tv_sec = 0;
846 test_time.tv_nsec = 0;
847 g_debug("test tree after seek_time");
848 g_tree_foreach(pqueue, test_tree, NULL);
849#endif //DEBUG
850
851
852
8697a616 853}
dc877563 854
2a2fa4f0 855
8697a616 856void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
857{
858 guint i, nb_trace;
2a2fa4f0 859
8697a616 860 LttvTraceContext *tc;
2a2fa4f0 861
348c6ba8 862 g_tree_destroy(self->pqueue);
863 self->pqueue = g_tree_new(compare_tracefile);
864
8697a616 865 nb_trace = lttv_traceset_number(self->ts);
866 for(i = 0 ; i < nb_trace ; i++) {
867 tc = self->traces[i];
868 lttv_process_trace_seek_time(tc, start);
869 }
dc877563 870}
b445142a 871
308711e5 872
8697a616 873gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
874 const LttvTracesetContextPosition *pos)
308711e5 875{
27304273 876 guint i;
8697a616 877
18c87975 878 /* If a position is set, seek the traceset to this position */
879 if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
880 g_tree_destroy(self->pqueue);
881 self->pqueue = g_tree_new(compare_tracefile);
882
883 for(i=0;i<pos->ep->len; i++) {
884 LttEventPosition **ep = &g_array_index(pos->ep, LttEventPosition*, i);
885 LttvTracefileContext **tfc =
886 &g_array_index(pos->tfc, LttvTracefileContext*, i);
887 if(*ep != NULL) {
888 if(ltt_tracefile_seek_position((*tfc)->tf, *ep) != 0)
889 return 1;
890 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
e7f5e89d 891 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
18c87975 892 g_tree_insert(self->pqueue, (*tfc), (*tfc));
893 } else {
894 (*tfc)->timestamp = ltt_time_infinite;
895 }
1986f254 896 }
308711e5 897 }
e7f5e89d 898#ifdef DEBUG
899 test_time.tv_sec = 0;
900 test_time.tv_nsec = 0;
901 g_debug("test tree after seek_position");
902 g_tree_foreach(self->pqueue, test_tree, NULL);
903#endif //DEBUG
904
905
906
2c82c4dc 907 return 0;
308711e5 908}
909
910
8697a616 911
b445142a 912static LttField *
eed2ef37 913find_field(LttEventType *et, const GQuark field)
b445142a 914{
915 LttType *t;
916
917 LttField *f;
918
919 guint i, nb;
920
eed2ef37 921 GQuark name;
b445142a 922
eed2ef37 923 /* Field is unset */
924 if(field == 0) return NULL;
925
b445142a 926 f = ltt_eventtype_field(et);
927 t = ltt_eventtype_type(et);
928 g_assert(ltt_type_class(t) == LTT_STRUCT);
929 nb = ltt_type_member_number(t);
930 for(i = 0 ; i < nb ; i++) {
931 ltt_type_member_type(t, i, &name);
eed2ef37 932 if(name == field) break;
b445142a 933 }
934 g_assert(i < nb);
935 return ltt_field_member(f, i);
936}
937
eed2ef37 938LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
939 guint facility_id)
940{
941 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
942}
943
944/* Get the first facility corresponding to the name. As the types must be
945 * compatible, it is relevant to use the field name and sizes of the first
946 * facility to create data structures and assume the data will be compatible
947 * thorough the trace */
948LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
949{
950 g_assert(th->fac_list->len > 0);
951 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
952}
953
b445142a 954
eed2ef37 955/* Returns 0 on success, -1 if fails. */
956gint
957lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
2c82c4dc 958 GQuark field1, GQuark field2, GQuark field3, LttvHook h, gpointer hook_data,
959 LttvTraceHook *th)
b445142a 960{
961 LttFacility *f;
962
eed2ef37 963 LttEventType *et, *first_et;
964
965 GArray *facilities;
966
d052ffc3 967 guint i, fac_id, ev_id;
b445142a 968
eed2ef37 969 LttvTraceHookByFacility *thf, *first_thf;
b445142a 970
eed2ef37 971 facilities = ltt_trace_facility_get_by_name(t, facility);
021eeb41 972
eed2ef37 973 if(unlikely(facilities == NULL)) goto facility_error;
974
975 th->fac_index = g_array_sized_new(FALSE, TRUE,
976 sizeof(LttvTraceHookByFacility),
977 NUM_FACILITIES);
978 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
b445142a 979
eed2ef37 980 th->fac_list = g_array_sized_new(FALSE, TRUE,
981 sizeof(LttvTraceHookByFacility*),
982 facilities->len);
983 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
984
985 fac_id = g_array_index(facilities, guint, 0);
986 f = ltt_trace_get_facility_by_num(t, fac_id);
987
cb03932a 988 et = ltt_facility_eventtype_get_by_name(f, event);
eed2ef37 989 if(unlikely(et == NULL)) goto event_error;
990
991 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1986f254 992 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf;
9d239bd9 993
d052ffc3 994 ev_id = ltt_eventtype_id(et);
995
eed2ef37 996 thf->h = h;
d052ffc3 997 thf->id = GET_HOOK_ID(fac_id, ev_id);
eed2ef37 998 thf->f1 = find_field(et, field1);
999 thf->f2 = find_field(et, field2);
1000 thf->f3 = find_field(et, field3);
2c82c4dc 1001 thf->hook_data = hook_data;
eed2ef37 1002
1003 first_thf = thf;
826f1ab2 1004 first_et = et;
eed2ef37 1005
1006 /* Check for type compatibility too */
1007 for(i=1;i<facilities->len;i++) {
1008 fac_id = g_array_index(facilities, guint, i);
1009 f = ltt_trace_get_facility_by_num(t, fac_id);
1010
f4b88a7d 1011 et = ltt_facility_eventtype_get_by_name(f, event);
eed2ef37 1012 if(unlikely(et == NULL)) goto event_error;
1013
1014 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1986f254 1015 g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf;
d052ffc3 1016 ev_id = ltt_eventtype_id(et);
eed2ef37 1017 thf->h = h;
d052ffc3 1018 thf->id = GET_HOOK_ID(fac_id, ev_id);
eed2ef37 1019 thf->f1 = find_field(et, field1);
1020 if(check_fields_compatibility(first_et, et,
1021 first_thf->f1, thf->f1))
1022 goto type_error;
1023
1024 thf->f2 = find_field(et, field2);
1025 if(check_fields_compatibility(first_et, et,
1026 first_thf->f2, thf->f2))
1027 goto type_error;
1028
1029 thf->f3 = find_field(et, field3);
1030 if(check_fields_compatibility(first_et, et,
1031 first_thf->f3, thf->f3))
1032 goto type_error;
2c82c4dc 1033 thf->hook_data = hook_data;
eed2ef37 1034 }
1035
1036 return 0;
1037
1038type_error:
1039 goto free;
1040event_error:
f4b88a7d 1041 g_error("Event type does not exist for event %s",
1042 g_quark_to_string(event));
eed2ef37 1043 goto free;
1044facility_error:
1045 g_error("No %s facility", g_quark_to_string(facility));
1046 goto free;
1047free:
1048 g_array_free(th->fac_index, TRUE);
1049 g_array_free(th->fac_list, TRUE);
1050 th->fac_index = NULL;
1051 th->fac_list = NULL;
1052 return -1;
1053}
1054
1055void lttv_trace_hook_destroy(LttvTraceHook *th)
1056{
1057 g_array_free(th->fac_index, TRUE);
1058 g_array_free(th->fac_list, TRUE);
b445142a 1059}
1060
1061
8b0bbe19 1062LttvTracesetContextPosition *lttv_traceset_context_position_new()
5e2c04a2 1063{
27304273 1064 LttvTracesetContextPosition *pos = g_new(LttvTracesetContextPosition,1);
1065 pos->ep = g_array_sized_new(FALSE, TRUE, sizeof(LttEventPosition*),
1066 10);
1067 pos->tfc = g_array_sized_new(FALSE, TRUE, sizeof(LttvTracefileContext*),
1068 10);
1069 pos->timestamp = ltt_time_infinite;
1070 return pos;
5e2c04a2 1071}
1072
3054461a 1073/* Save all positions, the ones with infinite time will have NULL
1986f254 1074 * ep. */
27304273 1075void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1076 LttvTracesetContextPosition *pos)
1077{
1986f254 1078 guint i;
1079 guint num_traces = lttv_traceset_number(self->ts);
728d0c3e 1080
33e44b82 1081 for(i=0;i<pos->ep->len;i++){
1082 LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i);
1083 if(ep != NULL) g_free(ep);
1084 }
1085
728d0c3e 1086 pos->tfc = g_array_set_size(pos->tfc, 0);
1087 pos->ep = g_array_set_size(pos->ep, 0);
0bd2f89c 1088
1089 pos->timestamp = ltt_time_infinite;
728d0c3e 1090
1986f254 1091 for(i=0; i<num_traces;i++) {
1092 GArray * tracefiles = self->traces[i]->tracefiles;
1093 guint j;
1094 guint num_tracefiles = tracefiles->len;
1095
1096 for(j=0;j<num_tracefiles;j++) {
1097 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1098 LttvTracefileContext*, j);
1099
1100 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1101 LttEventPosition *ep;
1102
1103 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1104 ep = ltt_event_position_new();
1105 ltt_event_position(event, ep);
1106 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1107 pos->timestamp = (*tfc)->timestamp;
1108 } else {
1109 ep = NULL;
1110 }
1111 g_array_append_val(pos->tfc, *tfc);
1112 g_array_append_val(pos->ep, ep);
1113 }
1114
1115 }
8697a616 1116}
1117
1118void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1119{
27304273 1120 int i;
1986f254 1121 LttEventPosition **ep;
1122
1123 for(i=0;i<pos->ep->len;i++) {
1124 ep = &g_array_index(pos->ep, LttEventPosition*, i);
1125 if(*ep != NULL)
1126 g_free(*ep);
1127 }
27304273 1128 g_array_free(pos->ep, TRUE);
1129 g_array_free(pos->tfc, TRUE);
1130 g_free(pos);
8697a616 1131}
1132
5e2c04a2 1133void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1134 const LttvTracesetContextPosition *src)
1135{
27304273 1136 int i;
1986f254 1137 LttEventPosition **src_ep, **dest_ep;
5e2c04a2 1138
728d0c3e 1139 dest->ep = g_array_set_size(dest->ep, src->ep->len);
1140 dest->tfc = g_array_set_size(dest->tfc, src->tfc->len);
27304273 1141
1142 for(i=0;i<src->ep->len;i++) {
1986f254 1143 src_ep = &g_array_index(src->ep, LttEventPosition*, i);
1144 dest_ep = &g_array_index(dest->ep, LttEventPosition*, i);
1145 if(*src_ep != NULL) {
33e44b82 1146 if(*dest_ep == NULL) *dest_ep = ltt_event_position_new();
1986f254 1147 ltt_event_position_copy(
1148 *dest_ep,
1149 *src_ep);
1150 } else
1151 *dest_ep = NULL;
27304273 1152 }
1153 for(i=0;i<src->tfc->len;i++) {
1154 g_array_index(dest->tfc, LttvTracefileContext*, i) =
1155 g_array_index(src->tfc, LttvTracefileContext*, i);
5e2c04a2 1156 }
5e2c04a2 1157 dest->timestamp = src->timestamp;
1158}
1159
8697a616 1160gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1161 const LttvTracesetContextPosition *pos)
1162{
27304273 1163 int i;
826f1ab2 1164 int ret = 0;
2c82c4dc 1165
1166 if(pos->ep->len == 0) {
1167 if(lttv_traceset_number(self->ts) == 0) return 0;
1168 else return 1;
1169 }
1170 if(lttv_traceset_number(self->ts) == 0)
1171 return -1;
1172
27304273 1173 for(i=0;i<pos->ep->len;i++) {
1174 LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i);
1175 LttvTracefileContext *tfc =
1176 g_array_index(pos->tfc, LttvTracefileContext*, i);
1986f254 1177
1178 if(ep == NULL) {
1179 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0) {
1180 ret = -1;
1181 }
1182 } else {
1183 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) == 0) {
1184 ret = 1;
1185 } else {
1186 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
8697a616 1187
1986f254 1188 ret = ltt_event_position_compare((LttEventPosition*)event,
1189 ep);
1190 }
1191 }
27304273 1192 if(ret != 0) return ret;
8697a616 1193
8697a616 1194 }
1195 return 0;
1196}
1197
1198
1199gint lttv_traceset_context_pos_pos_compare(
1200 const LttvTracesetContextPosition *pos1,
1201 const LttvTracesetContextPosition *pos2)
1202{
27304273 1203 int i, j;
1204 int ret;
8697a616 1205
2c82c4dc 1206 if(pos1->ep->len == 0) {
1207 if(pos2->ep->len == 0) return 0;
1208 else return 1;
1209 }
1210 if(pos2->ep->len == 0)
1211 return -1;
1212
27304273 1213 for(i=0;i<pos1->ep->len;i++) {
1214 LttEventPosition *ep1 = g_array_index(pos1->ep, LttEventPosition*, i);
1986f254 1215 LttvTracefileContext *tfc1 = g_array_index(pos1->tfc,
1216 LttvTracefileContext*, i);
27304273 1217
1986f254 1218 if(ep1 != NULL) {
1219 for(j=0;j<pos2->ep->len;j++) {
1220 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1221 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1222 LttvTracefileContext*, j);
1223 if(tfc1 == tfc2) {
1224 if(ep2 != NULL)
1225 ret = ltt_event_position_compare(ep1, ep2);
1226 else
1227 ret = -1;
1228
1229 if(ret != 0) return ret;
1230 }
1231 }
1232 } else {
1233 for(j=0;j<pos2->ep->len;j++) {
1234 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1235 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1236 LttvTracefileContext*, j);
1237 if(tfc1 == tfc2) {
1238 if(ep2 != NULL) ret = 1;
1239 }
27304273 1240 }
8697a616 1241 }
1242 }
1243 return 0;
1244}
1245
1246
2d262115 1247LttTime lttv_traceset_context_position_get_time(
1248 const LttvTracesetContextPosition *pos)
1249{
1250 return pos->timestamp;
1251}
1252
1253
1254LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1255{
1256 GTree *pqueue = self->pqueue;
b56b5fec 1257 LttvTracefileContext *tfc = NULL;
2d262115 1258
1259 g_tree_foreach(pqueue, get_first, &tfc);
1260
1261 return tfc;
1262}
18c87975 1263
2c82c4dc 1264/* lttv_process_traceset_synchronize_tracefiles
1265 *
1266 * Use the sync_position field of the trace set context to synchronize each
1267 * tracefile with the previously saved position.
1268 *
1269 * If no previous position has been saved, it simply does nothing.
1270 */
1271void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1272{
1273 g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
1274}
1275
1276
1277
1278
1279void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1280{
1281 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1282}
1283
0bd2f89c 1284struct seek_back_data {
1285 guint first_event; /* Index of the first event in the array : we will always
1286 overwrite at this position : this is a circular array.
1287 */
1288 guint events_found;
33e44b82 1289 guint n; /* number of events requested */
0bd2f89c 1290 GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
33e44b82 1291 LttvFilter *filter;
0bd2f89c 1292};
1293
1294static gint seek_back_event_hook(void *hook_data, void* call_data)
1295{
1296 struct seek_back_data *sd = (struct seek_back_data*)hook_data;
1297 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1298 LttvTracesetContext *tsc = tfc->t_context->ts_context;
1299 LttvTracesetContextPosition *pos;
33e44b82 1300
1301 if(sd->filter != NULL) {
1302 if(!lttv_filter_tree_parse(sd->filter->head,
1303 ltt_tracefile_get_event(tfc->tf),
1304 tfc->tf,
1305 tfc->t_context->t,
1306 tfc))
1307 return FALSE;
0bd2f89c 1308 }
33e44b82 1309
1310 pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array,
1311 sd->first_event);
0bd2f89c 1312
1313 lttv_traceset_context_position_save(tsc, pos);
1314
1315 if(sd->first_event >= sd->array->len - 1) sd->first_event = 0;
1316 else sd->first_event++;
1317
33e44b82 1318 sd->events_found = min(sd->n, sd->events_found + 1);
0bd2f89c 1319
1320 return FALSE;
1321}
1322
0bd2f89c 1323/* Seek back n events back from the current position.
1324 *
1325 * Parameters :
1326 * @self The trace set context
1327 * @n number of events to jump over
1328 * @first_offset The initial offset value used. Hint : try about 100000ns.
33e44b82 1329 * never put first_offset at ltt_time_zero.
1330 * @time_seeker Function pointer of the function to use to seek time :
1331 * either lttv_process_traceset_seek_time
1332 * or lttv_state_traceset_seek_time_closest
1333 * @filter The filter to call.
0bd2f89c 1334 *
1335 * Return value : the number of events found (might be lower than the number
1336 * requested if beginning of traceset is reached).
1337 *
1338 * The first search will go back first_offset and try to find the last n events
1339 * matching the filter. If there are not enough, it will try to go back from the
1340 * new trace point from first_offset*2, and so on, until beginning of trace or n
1341 * events are found.
1342 *
1343 * Note : this function does not take in account the LttvFilter : use the
1344 * similar function found in state.c instead.
1345 *
1346 * Note2 : the caller must make sure that the LttvTracesetContext does not
1347 * contain any hook, as process_traceset_middle is used in this routine.
1348 */
1349guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
33e44b82 1350 guint n, LttTime first_offset,
1351 seek_time_fct time_seeker,
1352 LttvFilter *filter)
0bd2f89c 1353{
33e44b82 1354 if(lttv_traceset_number(self->ts) == 0) return 0;
1355 g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
1356
0bd2f89c 1357 guint i;
1358 LttvTracesetContextPosition *next_iter_end_pos =
1359 lttv_traceset_context_position_new();
1360 LttvTracesetContextPosition *end_pos = lttv_traceset_context_position_new();
33e44b82 1361 LttvTracesetContextPosition *saved_pos = lttv_traceset_context_position_new();
0bd2f89c 1362 LttTime time;
1363 LttTime time_offset;
1364 struct seek_back_data sd;
1365 LttvHooks *hooks = lttv_hooks_new();
1366
1367 sd.first_event = 0;
1368 sd.events_found = 0;
1369 sd.array = g_ptr_array_sized_new(n);
33e44b82 1370 sd.filter = filter;
1371 sd.n = n;
0bd2f89c 1372 g_ptr_array_set_size(sd.array, n);
1373 for(i=0;i<n;i++) {
1374 g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new();
1375 }
33e44b82 1376
0bd2f89c 1377 lttv_traceset_context_position_save(self, next_iter_end_pos);
33e44b82 1378 lttv_traceset_context_position_save(self, saved_pos);
0bd2f89c 1379 /* Get the current time from which we will offset */
1380 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1381 /* the position saved might be end of traceset... */
1382 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1383 time = self->time_span.end_time;
1384 }
1385 time_offset = first_offset;
1386
1387 lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT);
1388
1389 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1390
1391 while(1) {
1392 /* stop criteria : - n events found
1393 * - time < beginning of trace */
1394 if(ltt_time_compare(time, self->time_span.start_time) < 0) break;
0bd2f89c 1395
1396 lttv_traceset_context_position_copy(end_pos, next_iter_end_pos);
1397
1398 /* We must seek the traceset back to time - time_offset */
1399 /* this time becomes the new reference time */
1400 time = ltt_time_sub(time, time_offset);
1401
33e44b82 1402 time_seeker(self, time);
0bd2f89c 1403 lttv_traceset_context_position_save(self, next_iter_end_pos);
33e44b82 1404 /* Resync the time in case of a seek_closest */
1405 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1406 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1407 time = self->time_span.end_time;
1408 }
0bd2f89c 1409
1410 /* Process the traceset, calling a hook which adds events
1411 * to the array, overwriting the tail. It changes first_event and
1412 * events_found too. */
1413 /* We would like to have a clean context here : no other hook than our's */
1414
1415 lttv_process_traceset_middle(self, ltt_time_infinite,
1416 G_MAXUINT, end_pos);
1417
33e44b82 1418 if(sd.events_found < n) {
1419 if(sd.first_event > 0) {
1420 /* Save the first position */
1421 LttvTracesetContextPosition *pos =
1422 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0);
1423 lttv_traceset_context_position_copy(saved_pos, pos);
1424 }
1425 g_assert(n-sd.events_found <= sd.array->len);
1426 /* Change array size to n - events_found */
1427 for(i=n-sd.events_found;i<sd.array->len;i++) {
1428 LttvTracesetContextPosition *pos =
1429 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1430 lttv_traceset_context_position_destroy(pos);
1431 }
1432 g_ptr_array_set_size(sd.array, n-sd.events_found);
1433 sd.first_event = 0;
1434
1435 } else break; /* Second end criterion : n events found */
1436
0bd2f89c 1437 time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL);
1438 }
1439
1440 lttv_traceset_context_position_destroy(end_pos);
1441 lttv_traceset_context_position_destroy(next_iter_end_pos);
1442
1443 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1444
33e44b82 1445 if(sd.events_found >= n) {
0bd2f89c 1446 /* Seek the traceset to the first event in the circular array */
1447 LttvTracesetContextPosition *pos =
1448 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array,
1449 sd.first_event);
1450 g_assert(lttv_process_traceset_seek_position(self, pos) == 0);
33e44b82 1451 } else {
1452 /* Will seek to the last saved position : in the worst case, it will be the
1453 * original position (if events_found is 0) */
1454 g_assert(lttv_process_traceset_seek_position(self, saved_pos) == 0);
0bd2f89c 1455 }
1456
33e44b82 1457 for(i=0;i<sd.array->len;i++) {
0bd2f89c 1458 LttvTracesetContextPosition *pos =
1459 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1460 lttv_traceset_context_position_destroy(pos);
1461 }
1462 g_ptr_array_free(sd.array, TRUE);
1463
1464 lttv_hooks_destroy(hooks);
1465
33e44b82 1466 lttv_traceset_context_position_destroy(saved_pos);
1467
0bd2f89c 1468 return sd.events_found;
1469}
1470
1471
1472struct seek_forward_data {
1473 guint event_count; /* event counter */
1474 guint n; /* requested number of events to jump over */
33e44b82 1475 LttvFilter *filter;
0bd2f89c 1476};
1477
1478static gint seek_forward_event_hook(void *hook_data, void* call_data)
1479{
1480 struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
33e44b82 1481 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
0bd2f89c 1482
33e44b82 1483 if(sd->filter != NULL) {
1484 if(!lttv_filter_tree_parse(sd->filter->head,
1485 ltt_tracefile_get_event(tfc->tf),
1486 tfc->tf,
1487 tfc->t_context->t,
1488 tfc))
1489 return FALSE;
1490 }
1491
0bd2f89c 1492 sd->event_count++;
1493
1494 if(sd->event_count >= sd->n)
1495 return TRUE;
1496 else
1497 return FALSE;
1498}
1499
1500/* Seek back n events forward from the current position
1501 *
1502 * Parameters :
33e44b82 1503 * @self the trace set context
1504 * @n number of events to jump over
1505 * @filter filter to call.
0bd2f89c 1506 *
1507 * returns : the number of events jumped over (may be less than requested if end
1508 * of traceset reached) */
1509guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
33e44b82 1510 guint n, LttvFilter *filter)
0bd2f89c 1511{
1512 struct seek_forward_data sd;
1513 sd.event_count = 0;
1514 sd.n = n;
33e44b82 1515 sd.filter = filter;
0bd2f89c 1516 LttvHooks *hooks = lttv_hooks_new();
1517
1518 lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
1519
1520 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1521
1522 /* it will end on the end of traceset, or the fact that the
1523 * hook returns TRUE.
1524 */
1525 lttv_process_traceset_middle(self, ltt_time_infinite,
1526 G_MAXUINT, NULL);
1527
1528 /* Here, our position is either the end of traceset, or the exact position
1529 * after n events : leave it like this. */
1530
1531 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1532
1533 lttv_hooks_destroy(hooks);
1534
1535 return sd.event_count;
1536}
1537
1538
This page took 0.110118 seconds and 4 git commands to generate.