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