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