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