fix seek so that adding and removing a trace from a traceset will work
[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 gboolean last_ret = FALSE; /* 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 e = ltt_tracefile_get_event(tfc->tf);
759
760 if(last_read_state != LAST_EMPTY) {
761 /* Only call hooks if the last read has given an event or if we are at the
762 * first pass (not if last read returned end of tracefile) */
763 count++;
764
765 fac_id = ltt_event_facility_id(e);
766 ev_id = ltt_event_eventtype_id(e);
767 id = GET_HOOK_ID(fac_id, ev_id);
768 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
769 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
770 }
771
772 read_ret = ltt_tracefile_read(tfc->tf);
773
774 if(likely(!read_ret)) {
775 //g_debug("An event is ready");
776 tfc->timestamp = ltt_event_time(e);
777 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
778 g_tree_insert(pqueue, tfc, tfc);
779 #ifdef DEBUG
780 test_time.tv_sec = 0;
781 test_time.tv_nsec = 0;
782 g_debug("test tree after event ready");
783 g_tree_foreach(pqueue, test_tree, NULL);
784 #endif //DEBUG
785
786 last_read_state = LAST_OK;
787 } else {
788 tfc->timestamp = ltt_time_infinite;
789
790 if(read_ret == ERANGE) {
791 last_read_state = LAST_EMPTY;
792 g_debug("End of trace");
793 } else
794 g_error("Error happened in lttv_process_traceset_middle");
795 }
796 }
797 }
798
799
800 void lttv_process_traceset_end(LttvTracesetContext *self,
801 LttvHooks *after_traceset,
802 LttvHooks *after_trace,
803 LttvHooks *after_tracefile,
804 LttvHooks *event,
805 LttvHooksById *event_by_id)
806 {
807 /* Remove hooks from context. _after hooks are called by remove_hooks. */
808 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
809 lttv_traceset_context_remove_hooks(self,
810 after_traceset,
811 after_trace,
812 after_tracefile,
813 event,
814 event_by_id);
815 }
816
817 /* Subtile modification :
818 * if tracefile has no event at or after the time requested, it is not put in
819 * the queue, as the next read would fail.
820 *
821 * Don't forget to empty the traceset pqueue before calling this.
822 */
823 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
824 {
825 guint i, nb_tracefile;
826
827 gint ret;
828
829 LttvTracefileContext **tfc;
830
831 nb_tracefile = self->tracefiles->len;
832
833 GTree *pqueue = self->ts_context->pqueue;
834
835 for(i = 0 ; i < nb_tracefile ; i++) {
836 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
837
838 g_tree_remove(pqueue, *tfc);
839
840 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
841 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
842
843 if(ret == 0) { /* not ERANGE especially */
844 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
845 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
846 g_tree_insert(pqueue, (*tfc), (*tfc));
847 } else {
848 (*tfc)->timestamp = ltt_time_infinite;
849 }
850 }
851 #ifdef DEBUG
852 test_time.tv_sec = 0;
853 test_time.tv_nsec = 0;
854 g_debug("test tree after seek_time");
855 g_tree_foreach(pqueue, test_tree, NULL);
856 #endif //DEBUG
857
858
859
860 }
861
862
863 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
864 {
865 guint i, nb_trace;
866
867 LttvTraceContext *tc;
868
869 //g_tree_destroy(self->pqueue);
870 //self->pqueue = g_tree_new(compare_tracefile);
871
872 nb_trace = lttv_traceset_number(self->ts);
873 for(i = 0 ; i < nb_trace ; i++) {
874 tc = self->traces[i];
875 lttv_process_trace_seek_time(tc, start);
876 }
877 }
878
879
880 gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
881 const LttvTracesetContextPosition *pos)
882 {
883 guint i;
884 /* If a position is set, seek the traceset to this position */
885 if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
886
887 /* Test to see if the traces has been added to the trace set :
888 * It should NEVER happen. Clear all positions if a new trace comes in. */
889 /* FIXME I know this test is not optimal : should keep a number of
890 * tracefiles variable in the traceset.. eventually */
891 guint num_traces = lttv_traceset_number(self->ts);
892 guint tf_count = 0;
893 for(i=0; i<num_traces;i++) {
894 GArray * tracefiles = self->traces[i]->tracefiles;
895 guint j;
896 guint num_tracefiles = tracefiles->len;
897 for(j=0;j<num_tracefiles;j++)
898 tf_count++;
899 }
900 g_assert(tf_count == pos->tfcp->len);
901
902
903 //g_tree_destroy(self->pqueue);
904 //self->pqueue = g_tree_new(compare_tracefile);
905
906 for(i=0;i<pos->tfcp->len; i++) {
907 LttvTracefileContextPosition *tfcp =
908 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
909
910 g_tree_remove(self->pqueue, tfcp->tfc);
911
912 if(tfcp->used == TRUE) {
913 if(ltt_tracefile_seek_position(tfcp->tfc->tf, tfcp->event) != 0)
914 return 1;
915 tfcp->tfc->timestamp =
916 ltt_event_time(ltt_tracefile_get_event(tfcp->tfc->tf));
917 g_assert(ltt_time_compare(tfcp->tfc->timestamp,
918 ltt_time_infinite) != 0);
919 g_tree_insert(self->pqueue, tfcp->tfc, tfcp->tfc);
920
921 } else {
922 tfcp->tfc->timestamp = ltt_time_infinite;
923 }
924 }
925 }
926 #ifdef DEBUG
927 test_time.tv_sec = 0;
928 test_time.tv_nsec = 0;
929 g_debug("test tree after seek_position");
930 g_tree_foreach(self->pqueue, test_tree, NULL);
931 #endif //DEBUG
932
933
934
935 return 0;
936 }
937
938
939
940 static LttField *
941 find_field(LttEventType *et, const GQuark field)
942 {
943 LttType *t;
944
945 LttField *f;
946
947 guint i, nb;
948
949 GQuark name;
950
951 /* Field is unset */
952 if(field == 0) return NULL;
953
954 f = ltt_eventtype_field(et);
955 t = ltt_eventtype_type(et);
956 g_assert(ltt_type_class(t) == LTT_STRUCT);
957 nb = ltt_type_member_number(t);
958 for(i = 0 ; i < nb ; i++) {
959 ltt_type_member_type(t, i, &name);
960 if(name == field) break;
961 }
962 g_assert(i < nb);
963 return ltt_field_member(f, i);
964 }
965
966 LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
967 guint facility_id)
968 {
969 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
970 }
971
972 /* Get the first facility corresponding to the name. As the types must be
973 * compatible, it is relevant to use the field name and sizes of the first
974 * facility to create data structures and assume the data will be compatible
975 * thorough the trace */
976 LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
977 {
978 g_assert(th->fac_list->len > 0);
979 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
980 }
981
982
983 /* Returns 0 on success, -1 if fails. */
984 gint
985 lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
986 GQuark field1, GQuark field2, GQuark field3, LttvHook h, gpointer hook_data,
987 LttvTraceHook *th)
988 {
989 LttFacility *f;
990
991 LttEventType *et, *first_et;
992
993 GArray *facilities;
994
995 guint i, fac_id, ev_id;
996
997 LttvTraceHookByFacility *thf, *first_thf;
998
999 facilities = ltt_trace_facility_get_by_name(t, facility);
1000
1001 if(unlikely(facilities == NULL)) goto facility_error;
1002
1003 th->fac_index = g_array_sized_new(FALSE, TRUE,
1004 sizeof(LttvTraceHookByFacility),
1005 NUM_FACILITIES);
1006 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
1007
1008 th->fac_list = g_array_sized_new(FALSE, TRUE,
1009 sizeof(LttvTraceHookByFacility*),
1010 facilities->len);
1011 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
1012
1013 fac_id = g_array_index(facilities, guint, 0);
1014 f = ltt_trace_get_facility_by_num(t, fac_id);
1015
1016 et = ltt_facility_eventtype_get_by_name(f, event);
1017 if(unlikely(et == NULL)) goto event_error;
1018
1019 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1020 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf;
1021
1022 ev_id = ltt_eventtype_id(et);
1023
1024 thf->h = h;
1025 thf->id = GET_HOOK_ID(fac_id, ev_id);
1026 thf->f1 = find_field(et, field1);
1027 thf->f2 = find_field(et, field2);
1028 thf->f3 = find_field(et, field3);
1029 thf->hook_data = hook_data;
1030
1031 first_thf = thf;
1032 first_et = et;
1033
1034 /* Check for type compatibility too */
1035 for(i=1;i<facilities->len;i++) {
1036 fac_id = g_array_index(facilities, guint, i);
1037 f = ltt_trace_get_facility_by_num(t, fac_id);
1038
1039 et = ltt_facility_eventtype_get_by_name(f, event);
1040 if(unlikely(et == NULL)) goto event_error;
1041
1042 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1043 g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf;
1044 ev_id = ltt_eventtype_id(et);
1045 thf->h = h;
1046 thf->id = GET_HOOK_ID(fac_id, ev_id);
1047 thf->f1 = find_field(et, field1);
1048 if(check_fields_compatibility(first_et, et,
1049 first_thf->f1, thf->f1))
1050 goto type_error;
1051
1052 thf->f2 = find_field(et, field2);
1053 if(check_fields_compatibility(first_et, et,
1054 first_thf->f2, thf->f2))
1055 goto type_error;
1056
1057 thf->f3 = find_field(et, field3);
1058 if(check_fields_compatibility(first_et, et,
1059 first_thf->f3, thf->f3))
1060 goto type_error;
1061 thf->hook_data = hook_data;
1062 }
1063
1064 return 0;
1065
1066 type_error:
1067 goto free;
1068 event_error:
1069 g_error("Event type does not exist for event %s",
1070 g_quark_to_string(event));
1071 goto free;
1072 facility_error:
1073 g_error("No %s facility", g_quark_to_string(facility));
1074 goto free;
1075 free:
1076 g_array_free(th->fac_index, TRUE);
1077 g_array_free(th->fac_list, TRUE);
1078 th->fac_index = NULL;
1079 th->fac_list = NULL;
1080 return -1;
1081 }
1082
1083 void lttv_trace_hook_destroy(LttvTraceHook *th)
1084 {
1085 g_array_free(th->fac_index, TRUE);
1086 g_array_free(th->fac_list, TRUE);
1087 }
1088
1089
1090
1091
1092 LttvTracesetContextPosition *lttv_traceset_context_position_new(
1093 const LttvTracesetContext *self)
1094 {
1095 guint num_traces = lttv_traceset_number(self->ts);
1096 guint tf_count = 0;
1097 guint i;
1098
1099 for(i=0; i<num_traces;i++) {
1100 GArray * tracefiles = self->traces[i]->tracefiles;
1101 guint j;
1102 guint num_tracefiles = tracefiles->len;
1103 for(j=0;j<num_tracefiles;j++)
1104 tf_count++;
1105 }
1106 LttvTracesetContextPosition *pos =
1107 g_new(LttvTracesetContextPosition, 1);
1108 pos->tfcp = g_array_sized_new(FALSE, TRUE,
1109 sizeof(LttvTracefileContextPosition),
1110 tf_count);
1111 g_array_set_size(pos->tfcp, tf_count);
1112 for(i=0;i<pos->tfcp->len;i++) {
1113 LttvTracefileContextPosition *tfcp =
1114 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1115 tfcp->event = ltt_event_position_new();
1116 }
1117
1118 pos->timestamp = ltt_time_infinite;
1119 return pos;
1120 }
1121
1122 /* Save all positions, the ones with infinite time will have NULL
1123 * ep. */
1124 /* note : a position must be destroyed when a trace is added/removed from a
1125 * traceset */
1126 void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1127 LttvTracesetContextPosition *pos)
1128 {
1129 guint i;
1130 guint num_traces = lttv_traceset_number(self->ts);
1131 guint tf_count = 0;
1132
1133 pos->timestamp = ltt_time_infinite;
1134
1135 for(i=0; i<num_traces;i++) {
1136 GArray * tracefiles = self->traces[i]->tracefiles;
1137 guint j;
1138 guint num_tracefiles = tracefiles->len;
1139
1140 for(j=0;j<num_tracefiles;j++) {
1141 g_assert(tf_count < pos->tfcp->len);
1142 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1143 LttvTracefileContext*, j);
1144 LttvTracefileContextPosition *tfcp =
1145 &g_array_index(pos->tfcp, LttvTracefileContextPosition, tf_count);
1146
1147 tfcp->tfc = *tfc;
1148
1149 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1150 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1151 ltt_event_position(event, tfcp->event);
1152 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1153 pos->timestamp = (*tfc)->timestamp;
1154 tfcp->used = TRUE;
1155 } else {
1156 tfcp->used = FALSE;
1157 }
1158
1159 //g_array_append_val(pos->tfc, *tfc);
1160 //g_array_append_val(pos->ep, ep);
1161 tf_count++;
1162 }
1163
1164 }
1165 }
1166
1167 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1168 {
1169 int i;
1170
1171 for(i=0;i<pos->tfcp->len;i++) {
1172 LttvTracefileContextPosition *tfcp =
1173 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1174 g_free(tfcp->event);
1175 tfcp->event = NULL;
1176 tfcp->used = FALSE;
1177 }
1178 g_array_free(pos->tfcp, TRUE);
1179 g_free(pos);
1180 }
1181
1182 void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1183 const LttvTracesetContextPosition *src)
1184 {
1185 int i;
1186 LttvTracefileContextPosition *src_tfcp, *dest_tfcp;
1187
1188 g_assert(src->tfcp->len == src->tfcp->len);
1189
1190 for(i=0;i<src->tfcp->len;i++) {
1191 src_tfcp =
1192 &g_array_index(src->tfcp, LttvTracefileContextPosition, i);
1193 dest_tfcp =
1194 &g_array_index(dest->tfcp, LttvTracefileContextPosition, i);
1195
1196 dest_tfcp->used = src_tfcp->used;
1197 dest_tfcp->tfc = src_tfcp->tfc;
1198
1199 if(src_tfcp->used) {
1200 ltt_event_position_copy(
1201 dest_tfcp->event,
1202 src_tfcp->event);
1203 }
1204 }
1205 dest->timestamp = src->timestamp;
1206 }
1207
1208 gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1209 const LttvTracesetContextPosition *pos)
1210 {
1211 int i;
1212 int ret = 0;
1213
1214 if(pos->tfcp->len == 0) {
1215 if(lttv_traceset_number(self->ts) == 0) return 0;
1216 else return 1;
1217 }
1218 if(lttv_traceset_number(self->ts) == 0)
1219 return -1;
1220
1221 for(i=0;i<pos->tfcp->len;i++) {
1222 LttvTracefileContextPosition *tfcp =
1223 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1224
1225 if(tfcp->used == FALSE) {
1226 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) < 0) {
1227 ret = -1;
1228 }
1229 } else {
1230 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) == 0) {
1231 ret = 1;
1232 } else {
1233 LttEvent *event = ltt_tracefile_get_event(tfcp->tfc->tf);
1234
1235 ret = ltt_event_position_compare((LttEventPosition*)event,
1236 tfcp->event);
1237 }
1238 }
1239 if(ret != 0) return ret;
1240
1241 }
1242 return 0;
1243 }
1244
1245
1246 gint lttv_traceset_context_pos_pos_compare(
1247 const LttvTracesetContextPosition *pos1,
1248 const LttvTracesetContextPosition *pos2)
1249 {
1250 int i, j;
1251 int ret;
1252
1253 if(pos1->tfcp->len == 0) {
1254 if(pos2->tfcp->len == 0) return 0;
1255 else return 1;
1256 }
1257 if(pos2->tfcp->len == 0)
1258 return -1;
1259
1260 for(i=0;i<pos1->tfcp->len;i++) {
1261 LttvTracefileContextPosition *tfcp1 =
1262 &g_array_index(pos1->tfcp, LttvTracefileContextPosition, i);
1263
1264 if(tfcp1->used == TRUE) {
1265 for(j=0;j<pos2->tfcp->len;j++) {
1266 LttvTracefileContextPosition *tfcp2 =
1267 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1268
1269 if(tfcp1->tfc == tfcp2->tfc) {
1270 if(tfcp2->used == TRUE)
1271 ret = ltt_event_position_compare(tfcp1->event, tfcp2->event);
1272 else
1273 ret = -1;
1274
1275 if(ret != 0) return ret;
1276 }
1277 }
1278
1279 } else {
1280 for(j=0;j<pos2->tfcp->len;j++) {
1281 LttvTracefileContextPosition *tfcp2 =
1282 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1283
1284 if(tfcp1->tfc == tfcp2->tfc)
1285 if(tfcp2->used == TRUE) ret = 1;
1286 if(ret != 0) return ret;
1287 }
1288 }
1289 }
1290 return 0;
1291 }
1292
1293
1294 LttTime lttv_traceset_context_position_get_time(
1295 const LttvTracesetContextPosition *pos)
1296 {
1297 return pos->timestamp;
1298 }
1299
1300
1301 LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1302 {
1303 GTree *pqueue = self->pqueue;
1304 LttvTracefileContext *tfc = NULL;
1305
1306 g_tree_foreach(pqueue, get_first, &tfc);
1307
1308 return tfc;
1309 }
1310
1311 /* lttv_process_traceset_synchronize_tracefiles
1312 *
1313 * Use the sync_position field of the trace set context to synchronize each
1314 * tracefile with the previously saved position.
1315 *
1316 * If no previous position has been saved, it simply does nothing.
1317 */
1318 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1319 {
1320 g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
1321 }
1322
1323
1324
1325
1326 void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1327 {
1328 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1329 }
1330
1331 struct seek_back_data {
1332 guint first_event; /* Index of the first event in the array : we will always
1333 overwrite at this position : this is a circular array.
1334 */
1335 guint events_found;
1336 guint n; /* number of events requested */
1337 GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
1338 LttvFilter *filter;
1339 };
1340
1341 static gint seek_back_event_hook(void *hook_data, void* call_data)
1342 {
1343 struct seek_back_data *sd = (struct seek_back_data*)hook_data;
1344 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1345 LttvTracesetContext *tsc = tfc->t_context->ts_context;
1346 LttvTracesetContextPosition *pos;
1347
1348 if(sd->filter != NULL) {
1349 if(!lttv_filter_tree_parse(sd->filter->head,
1350 ltt_tracefile_get_event(tfc->tf),
1351 tfc->tf,
1352 tfc->t_context->t,
1353 tfc))
1354 return FALSE;
1355 }
1356
1357 pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array,
1358 sd->first_event);
1359
1360 lttv_traceset_context_position_save(tsc, pos);
1361
1362 if(sd->first_event >= sd->array->len - 1) sd->first_event = 0;
1363 else sd->first_event++;
1364
1365 sd->events_found = min(sd->n, sd->events_found + 1);
1366
1367 return FALSE;
1368 }
1369
1370 /* Seek back n events back from the current position.
1371 *
1372 * Parameters :
1373 * @self The trace set context
1374 * @n number of events to jump over
1375 * @first_offset The initial offset value used.
1376 * never put first_offset at ltt_time_zero.
1377 * @time_seeker Function pointer of the function to use to seek time :
1378 * either lttv_process_traceset_seek_time
1379 * or lttv_state_traceset_seek_time_closest
1380 * @filter The filter to call.
1381 *
1382 * Return value : the number of events found (might be lower than the number
1383 * requested if beginning of traceset is reached).
1384 *
1385 * The first search will go back first_offset and try to find the last n events
1386 * matching the filter. If there are not enough, it will try to go back from the
1387 * new trace point from first_offset*2, and so on, until beginning of trace or n
1388 * events are found.
1389 *
1390 * Note : this function does not take in account the LttvFilter : use the
1391 * similar function found in state.c instead.
1392 *
1393 * Note2 : the caller must make sure that the LttvTracesetContext does not
1394 * contain any hook, as process_traceset_middle is used in this routine.
1395 */
1396 guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
1397 guint n, LttTime first_offset,
1398 seek_time_fct time_seeker,
1399 LttvFilter *filter)
1400 {
1401 if(lttv_traceset_number(self->ts) == 0) return 0;
1402 g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
1403
1404 guint i;
1405 LttvTracesetContextPosition *next_iter_end_pos =
1406 lttv_traceset_context_position_new(self);
1407 LttvTracesetContextPosition *end_pos =
1408 lttv_traceset_context_position_new(self);
1409 LttvTracesetContextPosition *saved_pos =
1410 lttv_traceset_context_position_new(self);
1411 LttTime time;
1412 LttTime time_offset;
1413 struct seek_back_data sd;
1414 LttvHooks *hooks = lttv_hooks_new();
1415
1416 sd.first_event = 0;
1417 sd.events_found = 0;
1418 sd.array = g_ptr_array_sized_new(n);
1419 sd.filter = filter;
1420 sd.n = n;
1421 g_ptr_array_set_size(sd.array, n);
1422 for(i=0;i<n;i++) {
1423 g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new(self);
1424 }
1425
1426 lttv_traceset_context_position_save(self, next_iter_end_pos);
1427 lttv_traceset_context_position_save(self, saved_pos);
1428 /* Get the current time from which we will offset */
1429 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1430 /* the position saved might be end of traceset... */
1431 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1432 time = self->time_span.end_time;
1433 }
1434 time_offset = first_offset;
1435
1436 lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT);
1437
1438 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1439
1440 while(1) {
1441 /* stop criteria : - n events found
1442 * - time < beginning of trace */
1443 if(ltt_time_compare(time, self->time_span.start_time) < 0) break;
1444
1445 lttv_traceset_context_position_copy(end_pos, next_iter_end_pos);
1446
1447 /* We must seek the traceset back to time - time_offset */
1448 /* this time becomes the new reference time */
1449 time = ltt_time_sub(time, time_offset);
1450
1451 time_seeker(self, time);
1452 lttv_traceset_context_position_save(self, next_iter_end_pos);
1453 /* Resync the time in case of a seek_closest */
1454 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1455 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1456 time = self->time_span.end_time;
1457 }
1458
1459 /* Process the traceset, calling a hook which adds events
1460 * to the array, overwriting the tail. It changes first_event and
1461 * events_found too. */
1462 /* We would like to have a clean context here : no other hook than our's */
1463
1464 lttv_process_traceset_middle(self, ltt_time_infinite,
1465 G_MAXUINT, end_pos);
1466
1467 if(sd.events_found < n) {
1468 if(sd.first_event > 0) {
1469 /* Save the first position */
1470 LttvTracesetContextPosition *pos =
1471 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0);
1472 lttv_traceset_context_position_copy(saved_pos, pos);
1473 }
1474 g_assert(n-sd.events_found <= sd.array->len);
1475 /* Change array size to n - events_found */
1476 for(i=n-sd.events_found;i<sd.array->len;i++) {
1477 LttvTracesetContextPosition *pos =
1478 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1479 lttv_traceset_context_position_destroy(pos);
1480 }
1481 g_ptr_array_set_size(sd.array, n-sd.events_found);
1482 sd.first_event = 0;
1483
1484 } else break; /* Second end criterion : n events found */
1485
1486 time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL);
1487 }
1488
1489 lttv_traceset_context_position_destroy(end_pos);
1490 lttv_traceset_context_position_destroy(next_iter_end_pos);
1491
1492 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1493
1494 if(sd.events_found >= n) {
1495 /* Seek the traceset to the first event in the circular array */
1496 LttvTracesetContextPosition *pos =
1497 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array,
1498 sd.first_event);
1499 g_assert(lttv_process_traceset_seek_position(self, pos) == 0);
1500 } else {
1501 /* Will seek to the last saved position : in the worst case, it will be the
1502 * original position (if events_found is 0) */
1503 g_assert(lttv_process_traceset_seek_position(self, saved_pos) == 0);
1504 }
1505
1506 for(i=0;i<sd.array->len;i++) {
1507 LttvTracesetContextPosition *pos =
1508 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1509 lttv_traceset_context_position_destroy(pos);
1510 }
1511 g_ptr_array_free(sd.array, TRUE);
1512
1513 lttv_hooks_destroy(hooks);
1514
1515 lttv_traceset_context_position_destroy(saved_pos);
1516
1517 return sd.events_found;
1518 }
1519
1520
1521 struct seek_forward_data {
1522 guint event_count; /* event counter */
1523 guint n; /* requested number of events to jump over */
1524 LttvFilter *filter;
1525 };
1526
1527 static gint seek_forward_event_hook(void *hook_data, void* call_data)
1528 {
1529 struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
1530 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1531
1532 if(sd->filter != NULL) {
1533 if(!lttv_filter_tree_parse(sd->filter->head,
1534 ltt_tracefile_get_event(tfc->tf),
1535 tfc->tf,
1536 tfc->t_context->t,
1537 tfc))
1538 return FALSE;
1539 }
1540
1541 sd->event_count++;
1542
1543 if(sd->event_count >= sd->n)
1544 return TRUE;
1545 else
1546 return FALSE;
1547 }
1548
1549 /* Seek back n events forward from the current position
1550 *
1551 * Parameters :
1552 * @self the trace set context
1553 * @n number of events to jump over
1554 * @filter filter to call.
1555 *
1556 * returns : the number of events jumped over (may be less than requested if end
1557 * of traceset reached) */
1558 guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
1559 guint n, LttvFilter *filter)
1560 {
1561 struct seek_forward_data sd;
1562 sd.event_count = 0;
1563 sd.n = n;
1564 sd.filter = filter;
1565 LttvHooks *hooks = lttv_hooks_new();
1566
1567 lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
1568
1569 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1570
1571 /* it will end on the end of traceset, or the fact that the
1572 * hook returns TRUE.
1573 */
1574 lttv_process_traceset_middle(self, ltt_time_infinite,
1575 G_MAXUINT, NULL);
1576
1577 /* Here, our position is either the end of traceset, or the exact position
1578 * after n events : leave it like this. */
1579
1580 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1581
1582 lttv_hooks_destroy(hooks);
1583
1584 return sd.event_count;
1585 }
1586
1587
This page took 0.075984 seconds and 4 git commands to generate.