Fix tracecontext seek backward underflow
[lttv.git] / lttv / lttv / tracecontext.c
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
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <string.h>
24 #include <lttv/lttv.h>
25 #include <lttv/tracecontext.h>
26 #include <ltt/event.h>
27 #include <ltt/trace.h>
28 #include <lttv/filter.h>
29 #include <errno.h>
30
31 gint compare_tracefile(gconstpointer a, gconstpointer b)
32 {
33 gint comparison = 0;
34
35 const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
36 const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
37
38 if(likely(trace_a != trace_b)) {
39 comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
40 if(unlikely(comparison == 0)) {
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 }
48 }
49 return comparison;
50 }
51
52 typedef 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
59 struct _LttvTracesetContextPosition {
60 GArray *tfcp; /* Array of LttvTracefileContextPosition */
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) */
65 };
66
67 void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
68 {
69 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
70 }
71
72
73 void lttv_context_fini(LttvTracesetContext *self)
74 {
75 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
76 }
77
78
79 LttvTracesetContext *
80 lttv_context_new_traceset_context(LttvTracesetContext *self)
81 {
82 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
83 }
84
85
86
87
88 LttvTraceContext *
89 lttv_context_new_trace_context(LttvTracesetContext *self)
90 {
91 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
92 }
93
94
95 LttvTracefileContext *
96 lttv_context_new_tracefile_context(LttvTracesetContext *self)
97 {
98 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
99 }
100
101 /****************************************************************************
102 * lttv_traceset_context_compute_time_span
103 *
104 * Keep the time span in sync with on the fly addition and removal of traces
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
111 ***************************************************************************/
112 void lttv_traceset_context_compute_time_span(LttvTracesetContext *self,
113 TimeInterval *time_span)
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
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;
126
127 for(i=0; i<numTraces;i++){
128 tc = self->traces[i];
129 trace = tc->t;
130
131 ltt_trace_time_span_get(trace, &s, &e);
132 tc->time_span.start_time = s;
133 tc->time_span.end_time = e;
134
135 if(i==0){
136 time_span->start_time = s;
137 time_span->end_time = e;
138 }else{
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;
147 }
148 }
149 }
150
151 static 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);
168 tfc->target_pid = -1;
169 }
170
171
172 static void
173 init(LttvTracesetContext *self, LttvTraceset *ts)
174 {
175 guint i, nb_trace;
176
177 LttvTraceContext *tc;
178
179 GData **tracefiles_groups;
180
181 struct compute_tracefile_group_args args;
182
183 nb_trace = lttv_traceset_number(ts);
184 self->ts = ts;
185 self->traces = g_new(LttvTraceContext *, nb_trace);
186 self->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
187 self->ts_a = lttv_traceset_attribute(ts);
188 for(i = 0 ; i < nb_trace ; i++) {
189 tc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
190 self->traces[i] = tc;
191
192 tc->ts_context = self;
193 tc->index = i;
194 tc->vt = lttv_traceset_get(ts, i);
195 tc->t = lttv_trace(tc->vt);
196 tc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
197 tc->t_a = lttv_trace_attribute(tc->vt);
198 tc->tracefiles = g_array_sized_new(FALSE, TRUE,
199 sizeof(LttvTracefileContext*), 10);
200
201 tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t);
202 if(tracefiles_groups != NULL) {
203 args.func = (ForEachTraceFileFunc)init_tracefile_context;
204 args.func_args = tc;
205
206 g_datalist_foreach(tracefiles_groups,
207 (GDataForeachFunc)compute_tracefile_group,
208 &args);
209 }
210
211 #if 0
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;
215 tc->tracefiles = g_new(LttvTracefileContext *, nb_tracefile);
216
217 for(j = 0 ; j < nb_tracefile ; j++) {
218 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
219 tc->tracefiles[j] = tfc;
220 tfc->index = j;
221
222 if(j < nb_control) {
223 tfc->control = TRUE;
224 tfc->tf = ltt_trace_control_tracefile_get(tc->t, j);
225 }
226 else {
227 tfc->control = FALSE;
228 tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
229 }
230
231 tfc->t_context = tc;
232 tfc->e = ltt_event_new();
233 tfc->event = lttv_hooks_new();
234 tfc->event_by_id = lttv_hooks_by_id_new();
235 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
236 }
237 #endif //0
238
239 }
240 self->sync_position = lttv_traceset_context_position_new(self);
241 self->pqueue = g_tree_new(compare_tracefile);
242 lttv_process_traceset_seek_time(self, ltt_time_zero);
243 lttv_traceset_context_compute_time_span(self, &self->time_span);
244
245 }
246
247
248 void fini(LttvTracesetContext *self)
249 {
250 guint i, j, nb_trace, nb_tracefile;
251
252 LttvTraceContext *tc;
253
254 LttvTracefileContext **tfc;
255
256 LttvTraceset *ts = self->ts;
257
258 g_tree_destroy(self->pqueue);
259 g_object_unref(self->a);
260 lttv_traceset_context_position_destroy(self->sync_position);
261
262 nb_trace = lttv_traceset_number(ts);
263
264 for(i = 0 ; i < nb_trace ; i++) {
265 tc = self->traces[i];
266
267 g_object_unref(tc->a);
268
269 nb_tracefile = tc->tracefiles->len;
270
271 for(j = 0 ; j < nb_tracefile ; j++) {
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);
277 }
278 g_array_free(tc->tracefiles, TRUE);
279 g_object_unref(tc);
280 }
281 g_free(self->traces);
282 }
283
284
285 void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
286 LttvHooks *before_traceset,
287 LttvHooks *before_trace,
288 LttvHooks *before_tracefile,
289 LttvHooks *event,
290 LttvHooksByIdChannelArray *event_by_id_channel)
291 {
292 LttvTraceset *ts = self->ts;
293
294 guint i, nb_trace;
295
296 LttvTraceContext *tc;
297
298 lttv_hooks_call(before_traceset, self);
299
300 nb_trace = lttv_traceset_number(ts);
301
302 for(i = 0 ; i < nb_trace ; i++) {
303 tc = self->traces[i];
304 lttv_trace_context_add_hooks(tc,
305 before_trace,
306 before_tracefile,
307 event,
308 event_by_id_channel);
309 }
310 }
311
312
313 void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
314 LttvHooks *after_traceset,
315 LttvHooks *after_trace,
316 LttvHooks *after_tracefile,
317 LttvHooks *event,
318 LttvHooksByIdChannelArray *event_by_id_channel)
319 {
320
321 LttvTraceset *ts = self->ts;
322
323 guint i, nb_trace;
324
325 LttvTraceContext *tc;
326
327 nb_trace = lttv_traceset_number(ts);
328
329 for(i = 0 ; i < nb_trace ; i++) {
330 tc = self->traces[i];
331 lttv_trace_context_remove_hooks(tc,
332 after_trace,
333 after_tracefile,
334 event,
335 event_by_id_channel);
336 }
337
338 lttv_hooks_call(after_traceset, self);
339
340
341 }
342
343 void lttv_trace_context_add_hooks(LttvTraceContext *self,
344 LttvHooks *before_trace,
345 LttvHooks *before_tracefile,
346 LttvHooks *event,
347 LttvHooksByIdChannelArray *event_by_id_channel)
348 {
349 guint i, j, nb_tracefile;
350 LttvTracefileContext **tfc;
351 LttTracefile *tf;
352
353 lttv_hooks_call(before_trace, self);
354
355 nb_tracefile = self->tracefiles->len;
356
357 for(i = 0 ; i < nb_tracefile ; i++) {
358 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
359 tf = (*tfc)->tf;
360 lttv_tracefile_context_add_hooks(*tfc,
361 before_tracefile,
362 event,
363 NULL);
364 if (event_by_id_channel) {
365 for(j = 0; j < event_by_id_channel->array->len; j++) {
366 LttvHooksByIdChannel *hooks = &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 }
375 }
376 }
377
378
379
380 void lttv_trace_context_remove_hooks(LttvTraceContext *self,
381 LttvHooks *after_trace,
382 LttvHooks *after_tracefile,
383 LttvHooks *event,
384 LttvHooksByIdChannelArray *event_by_id_channel)
385 {
386 guint i, j, nb_tracefile;
387 LttvTracefileContext **tfc;
388 LttTracefile *tf;
389
390 nb_tracefile = self->tracefiles->len;
391
392 for(i = 0 ; i < nb_tracefile ; i++) {
393 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
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 }
406 lttv_tracefile_context_remove_hooks(*tfc,
407 after_tracefile,
408 event,
409 NULL);
410
411 }
412
413 lttv_hooks_call(after_trace, self);
414 }
415
416 void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
417 LttvHooks *before_tracefile,
418 LttvHooks *event,
419 LttvHooksById *event_by_id)
420 {
421 guint i, index;
422 LttvHooks *hook;
423
424 lttv_hooks_call(before_tracefile, self);
425 lttv_hooks_add_list(self->event, event);
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));
431 }
432 }
433 }
434
435 void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
436 LttvHooks *after_tracefile,
437 LttvHooks *event,
438 LttvHooksById *event_by_id)
439 {
440 guint i, index;
441
442 LttvHooks *hook;
443
444 lttv_hooks_remove_list(self->event, event);
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);
449 if(hook != NULL)
450 lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, index));
451 }
452 }
453
454 lttv_hooks_call(after_tracefile, self);
455 }
456
457 static LttvTracesetContext *
458 new_traceset_context(LttvTracesetContext *self)
459 {
460 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
461 }
462
463
464 static LttvTraceContext *
465 new_trace_context(LttvTracesetContext *self)
466 {
467 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
468 }
469
470
471 static LttvTracefileContext *
472 new_tracefile_context(LttvTracesetContext *self)
473 {
474 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
475 }
476
477
478 static void
479 traceset_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
485 static void
486 traceset_context_finalize (LttvTracesetContext *self)
487 {
488 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE)))
489 ->finalize(G_OBJECT(self));
490 }
491
492
493 static void
494 traceset_context_class_init (LttvTracesetContextClass *klass)
495 {
496 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
497
498 gobject_class->finalize = (void (*)(GObject *self))traceset_context_finalize;
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
507 GType
508 lttv_traceset_context_get_type(void)
509 {
510 static GType type = 0;
511 if (type == 0) {
512 static const GTypeInfo info = {
513 sizeof (LttvTracesetContextClass),
514 NULL, /* base_init */
515 NULL, /* base_finalize */
516 (GClassInitFunc) traceset_context_class_init, /* class_init */
517 NULL, /* class_finalize */
518 NULL, /* class_data */
519 sizeof (LttvTracesetContext),
520 0, /* n_preallocs */
521 (GInstanceInitFunc) traceset_context_instance_init, /* instance_init */
522 NULL /* Value handling */
523 };
524
525 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType",
526 &info, 0);
527 }
528 return type;
529 }
530
531
532 static void
533 trace_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
539 static void
540 trace_context_finalize (LttvTraceContext *self)
541 {
542 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))->
543 finalize(G_OBJECT(self));
544 }
545
546
547 static void
548 trace_context_class_init (LttvTraceContextClass *klass)
549 {
550 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
551
552 gobject_class->finalize = (void (*)(GObject *self)) trace_context_finalize;
553 }
554
555
556 GType
557 lttv_trace_context_get_type(void)
558 {
559 static GType type = 0;
560 if (type == 0) {
561 static const GTypeInfo info = {
562 sizeof (LttvTraceContextClass),
563 NULL, /* base_init */
564 NULL, /* base_finalize */
565 (GClassInitFunc) trace_context_class_init, /* class_init */
566 NULL, /* class_finalize */
567 NULL, /* class_data */
568 sizeof (LttvTraceContext),
569 0, /* n_preallocs */
570 (GInstanceInitFunc) trace_context_instance_init, /* instance_init */
571 NULL /* Value handling */
572 };
573
574 type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType",
575 &info, 0);
576 }
577 return type;
578 }
579
580
581 static void
582 tracefile_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
588 static void
589 tracefile_context_finalize (LttvTracefileContext *self)
590 {
591 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE)))
592 ->finalize(G_OBJECT(self));
593 }
594
595
596 static void
597 tracefile_context_class_init (LttvTracefileContextClass *klass)
598 {
599 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
600
601 gobject_class->finalize = (void (*)(GObject *self))tracefile_context_finalize;
602 }
603
604
605 GType
606 lttv_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 */
619 (GInstanceInitFunc) tracefile_context_instance_init, /* instance_init */
620 NULL /* Value handling */
621 };
622
623 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType",
624 &info, 0);
625 }
626 return type;
627 }
628
629
630
631 static gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
632 g_assert(key == value);
633 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
634 return TRUE;
635 }
636
637 #ifdef DEBUG
638 // Test to see if pqueue is traversed in the right order.
639 static LttTime test_time;
640
641 static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) {
642
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);
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;
659
660
661 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
662 return FALSE;
663 }
664 #endif //DEBUG
665
666
667
668 void lttv_process_traceset_begin(LttvTracesetContext *self,
669 LttvHooks *before_traceset,
670 LttvHooks *before_trace,
671 LttvHooks *before_tracefile,
672 LttvHooks *event,
673 LttvHooksByIdChannelArray *event_by_id_channel)
674 {
675
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,
683 event_by_id_channel);
684
685 }
686
687 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
688
689 /* Note : a _middle must be preceded from a _seek or another middle */
690 guint lttv_process_traceset_middle(LttvTracesetContext *self,
691 LttTime end,
692 gulong nb_events,
693 const LttvTracesetContextPosition *end_position)
694 {
695 GTree *pqueue = self->pqueue;
696
697 LttvTracefileContext *tfc;
698
699 LttEvent *e;
700
701 unsigned count = 0;
702
703 guint read_ret;
704
705 //enum read_state last_read_state = LAST_NONE;
706
707 gint last_ret = 0; /* return value of the last hook list called */
708
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
712 end time. */
713
714 while(TRUE) {
715 tfc = NULL;
716 g_tree_foreach(pqueue, get_first, &tfc);
717 /* End of traceset : tfc is NULL */
718 if(unlikely(tfc == NULL))
719 {
720 return count;
721 }
722
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
731 if(unlikely(last_ret == TRUE ||
732 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
733 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
734 end_position) == 0)||
735 ltt_time_compare(end, tfc->timestamp) <= 0))
736 {
737 return count;
738 }
739
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. */
743
744 #ifdef DEBUG
745 test_time.tv_sec = 0;
746 test_time.tv_nsec = 0;
747 g_debug("test tree before remove");
748 g_tree_foreach(pqueue, test_tree, tfc);
749 #endif //DEBUG
750 g_tree_remove(pqueue, tfc);
751
752 #ifdef DEBUG
753 test_time.tv_sec = 0;
754 test_time.tv_nsec = 0;
755 g_debug("test tree after remove");
756 g_tree_foreach(pqueue, test_tree, tfc);
757 #endif //DEBUG
758
759
760 e = ltt_tracefile_get_event(tfc->tf);
761
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
767 tfc->target_pid = -1; /* unset target PID */
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 */
771 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
772 lttv_hooks_by_id_get(tfc->event_by_id, e->event_id), tfc);
773
774 #if 0
775 /* This is buggy : it won't work well with state computation */
776 if(unlikely(last_ret == 2)) {
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 }
781 #endif //0
782 read_ret = ltt_tracefile_read(tfc->tf);
783
784
785 if(likely(!read_ret)) {
786 //g_debug("An event is ready");
787 tfc->timestamp = ltt_event_time(e);
788 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
789 g_tree_insert(pqueue, tfc, tfc);
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
797 //last_read_state = LAST_OK;
798 } else {
799 tfc->timestamp = ltt_time_infinite;
800
801 if(read_ret == ERANGE) {
802 // last_read_state = LAST_EMPTY;
803 g_debug("End of trace");
804 } else
805 g_error("Error happened in lttv_process_traceset_middle");
806 }
807 }
808 }
809
810
811 void lttv_process_traceset_end(LttvTracesetContext *self,
812 LttvHooks *after_traceset,
813 LttvHooks *after_trace,
814 LttvHooks *after_tracefile,
815 LttvHooks *event,
816 LttvHooksByIdChannelArray *event_by_id_channel)
817 {
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,
825 event_by_id_channel);
826 }
827
828 /* Subtile modification :
829 * if tracefile has no event at or after the time requested, it is not put in
830 * the queue, as the next read would fail.
831 *
832 * Don't forget to empty the traceset pqueue before calling this.
833 */
834 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
835 {
836 guint i, nb_tracefile;
837
838 gint ret;
839
840 LttvTracefileContext **tfc;
841
842 nb_tracefile = self->tracefiles->len;
843
844 GTree *pqueue = self->ts_context->pqueue;
845
846 for(i = 0 ; i < nb_tracefile ; i++) {
847 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
848
849 g_tree_remove(pqueue, *tfc);
850
851 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
852 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
853
854 if(ret == 0) { /* not ERANGE especially */
855 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
856 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
857 g_tree_insert(pqueue, (*tfc), (*tfc));
858 } else {
859 (*tfc)->timestamp = ltt_time_infinite;
860 }
861 }
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
868 }
869
870
871 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
872 {
873 guint i, nb_trace;
874
875 LttvTraceContext *tc;
876
877 //g_tree_destroy(self->pqueue);
878 //self->pqueue = g_tree_new(compare_tracefile);
879
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 }
885 }
886
887
888 gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
889 const LttvTracesetContextPosition *pos)
890 {
891 guint i;
892 /* If a position is set, seek the traceset to this position */
893 if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
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);
913
914 for(i=0;i<pos->tfcp->len; i++) {
915 LttvTracefileContextPosition *tfcp =
916 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
917
918 g_tree_remove(self->pqueue, tfcp->tfc);
919
920 if(tfcp->used == TRUE) {
921 if(ltt_tracefile_seek_position(tfcp->tfc->tf, tfcp->event) != 0)
922 return 1;
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
929 } else {
930 tfcp->tfc->timestamp = ltt_time_infinite;
931 }
932 }
933 }
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
943 return 0;
944 }
945
946
947 #if 0 // pmf: temporary disable
948 static LttField *
949 find_field(LttEventType *et, const GQuark field)
950 {
951 LttField *f;
952
953 if(field == 0) return NULL;
954
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;
963 }
964 #endif
965
966 struct marker_info *lttv_trace_hook_get_marker(LttTrace *t, LttvTraceHook *th)
967 {
968 return marker_get_info_from_id(th->mdata, th->id);
969 }
970
971 int lttv_trace_find_hook(LttTrace *t, GQuark channel_name, GQuark event_name,
972 GQuark fields[], LttvHook h, gpointer hook_data, GArray **trace_hooks)
973 {
974 struct marker_info *info;
975 guint16 marker_id;
976 int init_array_size;
977 GArray *group;
978 struct marker_data *mdata;
979
980 group = g_datalist_id_get_data(&t->tracefiles, channel_name);
981 if (unlikely(!group || group->len == 0)) {
982 g_info("No channel for marker named %s.%s found",
983 g_quark_to_string(channel_name), g_quark_to_string(event_name));
984 return 1;
985 }
986
987 mdata = g_array_index (group, LttTracefile, 0).mdata;
988 info = marker_get_info_from_name(mdata, event_name);
989 if(unlikely(info == NULL)) {
990 g_info("No marker named %s.%s found",
991 g_quark_to_string(channel_name), g_quark_to_string(event_name));
992 return 1;
993 }
994
995 init_array_size = (*trace_hooks)->len;
996
997 /* for each marker with the requested name */
998 do {
999 LttvTraceHook tmpth;
1000 int found;
1001 GQuark *f;
1002 struct marker_field *marker_field;
1003
1004 marker_id = marker_get_id_from_info(mdata, info);
1005
1006 tmpth.h = h;
1007 tmpth.mdata = mdata;
1008 tmpth.channel = channel_name;
1009 tmpth.id = marker_id;
1010 tmpth.hook_data = hook_data;
1011 tmpth.fields = g_ptr_array_new();
1012
1013 /* for each field requested */
1014 for(f = fields; f && *f != 0; f++) {
1015 found = 0;
1016 for_each_marker_field(marker_field, info) {
1017 if(marker_field->name == *f) {
1018 found = 1;
1019 g_ptr_array_add(tmpth.fields, marker_field);
1020 break;
1021 }
1022 }
1023 if(!found) {
1024 /* Did not find the one of the fields in this instance of the
1025 marker. Print a warning and skip this marker completely.
1026 Still iterate on other markers with same name. */
1027 g_ptr_array_free(tmpth.fields, TRUE);
1028 g_info("Field %s cannot be found in marker %s.%s",
1029 g_quark_to_string(*f), g_quark_to_string(channel_name),
1030 g_quark_to_string(event_name));
1031 goto skip_marker;
1032 }
1033 }
1034 /* all fields were found: add the tracehook to the array */
1035 *trace_hooks = g_array_append_val(*trace_hooks, tmpth);
1036 skip_marker:
1037 info = info->next;
1038 } while(info != NULL);
1039
1040 /* Error if no new trace hook has been added */
1041 if (init_array_size == (*trace_hooks)->len) {
1042 g_info("No marker of name %s.%s has all requested fields",
1043 g_quark_to_string(channel_name), g_quark_to_string(event_name));
1044 return 1;
1045 }
1046 return 0;
1047 }
1048
1049 void lttv_trace_hook_remove_all(GArray **th)
1050 {
1051 int i;
1052 for(i=0; i<(*th)->len; i++) {
1053 g_ptr_array_free(g_array_index(*th, LttvTraceHook, i).fields, TRUE);
1054 }
1055 if((*th)->len)
1056 *th = g_array_remove_range(*th, 0, (*th)->len);
1057 }
1058
1059 LttvTracesetContextPosition *lttv_traceset_context_position_new(
1060 const LttvTracesetContext *self)
1061 {
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
1085 pos->timestamp = ltt_time_infinite;
1086 return pos;
1087 }
1088
1089 /* Save all positions, the ones with infinite time will have NULL
1090 * ep. */
1091 /* note : a position must be destroyed when a trace is added/removed from a
1092 * traceset */
1093 void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1094 LttvTracesetContextPosition *pos)
1095 {
1096 guint i;
1097 guint num_traces = lttv_traceset_number(self->ts);
1098 guint tf_count = 0;
1099
1100 pos->timestamp = ltt_time_infinite;
1101
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++) {
1108 g_assert(tf_count < pos->tfcp->len);
1109 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1110 LttvTracefileContext*, j);
1111 LttvTracefileContextPosition *tfcp =
1112 &g_array_index(pos->tfcp, LttvTracefileContextPosition, tf_count);
1113
1114 tfcp->tfc = *tfc;
1115
1116 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1117 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1118 ltt_event_position(event, tfcp->event);
1119 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1120 pos->timestamp = (*tfc)->timestamp;
1121 tfcp->used = TRUE;
1122 } else {
1123 tfcp->used = FALSE;
1124 }
1125
1126 //g_array_append_val(pos->tfc, *tfc);
1127 //g_array_append_val(pos->ep, ep);
1128 tf_count++;
1129 }
1130
1131 }
1132 }
1133
1134 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1135 {
1136 int i;
1137
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;
1144 }
1145 g_array_free(pos->tfcp, TRUE);
1146 g_free(pos);
1147 }
1148
1149 void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1150 const LttvTracesetContextPosition *src)
1151 {
1152 int i;
1153 LttvTracefileContextPosition *src_tfcp, *dest_tfcp;
1154
1155 g_assert(src->tfcp->len == dest->tfcp->len);
1156
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) {
1167 ltt_event_position_copy(
1168 dest_tfcp->event,
1169 src_tfcp->event);
1170 }
1171 }
1172 dest->timestamp = src->timestamp;
1173 }
1174
1175 gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1176 const LttvTracesetContextPosition *pos)
1177 {
1178 int i;
1179 int ret = 0;
1180
1181 if(pos->tfcp->len == 0) {
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
1188 for(i=0;i<pos->tfcp->len;i++) {
1189 LttvTracefileContextPosition *tfcp =
1190 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1191
1192 if(tfcp->used == FALSE) {
1193 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) < 0) {
1194 ret = -1;
1195 }
1196 } else {
1197 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) == 0) {
1198 ret = 1;
1199 } else {
1200 LttEvent *event = ltt_tracefile_get_event(tfcp->tfc->tf);
1201
1202 ret = ltt_event_position_compare((LttEventPosition*)event,
1203 tfcp->event);
1204 }
1205 }
1206 if(ret != 0) return ret;
1207
1208 }
1209 return 0;
1210 }
1211
1212
1213 gint lttv_traceset_context_pos_pos_compare(
1214 const LttvTracesetContextPosition *pos1,
1215 const LttvTracesetContextPosition *pos2)
1216 {
1217 int i, j;
1218 int ret = 0;
1219
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;
1225 }
1226 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
1227 return -1;
1228
1229 for(i=0;i<pos1->tfcp->len;i++) {
1230 LttvTracefileContextPosition *tfcp1 =
1231 &g_array_index(pos1->tfcp, LttvTracefileContextPosition, i);
1232
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);
1241 else
1242 ret = -1;
1243
1244 if(ret != 0) return ret;
1245 }
1246 }
1247
1248 } else {
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;
1256 }
1257 }
1258 }
1259 return 0;
1260 }
1261
1262
1263 LttTime lttv_traceset_context_position_get_time(
1264 const LttvTracesetContextPosition *pos)
1265 {
1266 return pos->timestamp;
1267 }
1268
1269
1270 LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1271 {
1272 GTree *pqueue = self->pqueue;
1273 LttvTracefileContext *tfc = NULL;
1274
1275 g_tree_foreach(pqueue, get_first, &tfc);
1276
1277 return tfc;
1278 }
1279
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 */
1287 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1288 {
1289 int retval;
1290
1291 retval= lttv_process_traceset_seek_position(tsc, tsc->sync_position);
1292 g_assert_cmpint(retval, ==, 0);
1293 }
1294
1295
1296
1297
1298 void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1299 {
1300 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1301 }
1302
1303 struct 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;
1308 guint n; /* number of events requested */
1309 GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
1310 LttvFilter *filter1;
1311 LttvFilter *filter2;
1312 LttvFilter *filter3;
1313 gpointer data;
1314 check_handler *check;
1315 gboolean *stop_flag;
1316 guint raw_event_count;
1317 };
1318
1319 static 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;
1325
1326 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
1327 return TRUE;
1328 sd->raw_event_count++;
1329
1330 if(sd->filter1 != NULL && sd->filter1->head != NULL &&
1331 !lttv_filter_tree_parse(sd->filter1->head,
1332 ltt_tracefile_get_event(tfc->tf),
1333 tfc->tf,
1334 tfc->t_context->t,
1335 tfc,NULL,NULL)) {
1336 return FALSE;
1337 }
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,
1343 tfc,NULL,NULL)) {
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,
1351 tfc,NULL,NULL)) {
1352 return FALSE;
1353 }
1354
1355 pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array,
1356 sd->first_event);
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
1363 sd->events_found = min(sd->n, sd->events_found + 1);
1364
1365 return FALSE;
1366 }
1367
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
1373 * @first_offset The initial offset value used.
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.
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 */
1394 guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
1395 guint n, LttTime first_offset,
1396 seek_time_fct time_seeker,
1397 check_handler *check,
1398 gboolean *stop_flag,
1399 LttvFilter *filter1,
1400 LttvFilter *filter2,
1401 LttvFilter *filter3,
1402 gpointer data)
1403 {
1404 if(lttv_traceset_number(self->ts) == 0) return 0;
1405 g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
1406
1407 guint i;
1408 LttvTracesetContextPosition *next_iter_end_pos =
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);
1414 LttTime time;
1415 LttTime asked_time;
1416 LttTime time_offset;
1417 struct seek_back_data sd;
1418 LttvHooks *hooks = lttv_hooks_new();
1419 int retval;
1420
1421 sd.first_event = 0;
1422 sd.events_found = 0;
1423 sd.array = g_ptr_array_sized_new(n);
1424 sd.filter1 = filter1;
1425 sd.filter2 = filter2;
1426 sd.filter3 = filter3;
1427 sd.data = data;
1428 sd.n = n;
1429 sd.check = check;
1430 sd.stop_flag = stop_flag;
1431 sd.raw_event_count = 0;
1432 g_ptr_array_set_size(sd.array, n);
1433 for(i=0;i<n;i++) {
1434 g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new(self);
1435 }
1436
1437 lttv_traceset_context_position_save(self, next_iter_end_pos);
1438 lttv_traceset_context_position_save(self, saved_pos);
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) {
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 */
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;
1460 asked_time = time;
1461
1462 time_seeker(self, time);
1463 lttv_traceset_context_position_save(self, next_iter_end_pos);
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 }
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
1478 /* stop criteria : - n events found
1479 * - asked_time < beginning of trace */
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;
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;
1506
1507 } else break; /* Second end criterion : n events found */
1508
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
1517 if(sd.events_found >= n) {
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);
1522 retval= lttv_process_traceset_seek_position(self, pos);
1523 g_assert_cmpint(retval, ==, 0);
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) */
1527 retval= lttv_process_traceset_seek_position(self, saved_pos);
1528 g_assert_cmpint(retval, ==, 0);
1529 }
1530
1531 for(i=0;i<sd.array->len;i++) {
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
1540 lttv_traceset_context_position_destroy(saved_pos);
1541
1542 return sd.events_found;
1543 }
1544
1545
1546 struct seek_forward_data {
1547 guint event_count; /* event counter */
1548 guint n; /* requested number of events to jump over */
1549 LttvFilter *filter1;
1550 LttvFilter *filter2;
1551 LttvFilter *filter3;
1552 gpointer data;
1553 check_handler *check;
1554 gboolean *stop_flag;
1555 guint raw_event_count; /* event counter */
1556 };
1557
1558 static gint seek_forward_event_hook(void *hook_data, void* call_data)
1559 {
1560 struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
1561 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1562
1563 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
1564 return TRUE;
1565 sd->raw_event_count++;
1566
1567 if(sd->filter1 != NULL && sd->filter1->head != NULL &&
1568 !lttv_filter_tree_parse(sd->filter1->head,
1569 ltt_tracefile_get_event(tfc->tf),
1570 tfc->tf,
1571 tfc->t_context->t,
1572 tfc,NULL,NULL)) {
1573 return FALSE;
1574 }
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,
1580 tfc,NULL,NULL)) {
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,
1588 tfc,NULL,NULL)) {
1589 return FALSE;
1590 }
1591
1592 sd->event_count++;
1593 if(sd->event_count >= sd->n)
1594 return TRUE;
1595 return FALSE;
1596 }
1597
1598 /* Seek back n events forward from the current position (1 to n)
1599 * 0 is ok too, but it will actually do nothing.
1600 *
1601 * Parameters :
1602 * @self the trace set context
1603 * @n number of events to jump over
1604 * @filter filter to call.
1605 *
1606 * returns : the number of events jumped over (may be less than requested if end
1607 * of traceset reached) */
1608 guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
1609 guint n,
1610 check_handler *check,
1611 gboolean *stop_flag,
1612 LttvFilter *filter1,
1613 LttvFilter *filter2,
1614 LttvFilter *filter3,
1615 gpointer data)
1616 {
1617 struct seek_forward_data sd;
1618 sd.event_count = 0;
1619 sd.n = n;
1620 sd.filter1 = filter1;
1621 sd.filter2 = filter2;
1622 sd.filter3 = filter3;
1623 sd.data = data;
1624 sd.check = check;
1625 sd.stop_flag = stop_flag;
1626 sd.raw_event_count = 0;
1627
1628 if(sd.event_count >= sd.n) return sd.event_count;
1629
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
1637 * hook returns TRUE.
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
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. */
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.071845 seconds and 4 git commands to generate.