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