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