update compat
[lttv.git] / tags / lttv-0.11.3-23102008 / lttv / lttv / tracecontext.c
CommitLineData
13ab9fcb 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include <string.h>
24#include <lttv/lttv.h>
25#include <lttv/tracecontext.h>
26#include <ltt/event.h>
27#include <ltt/trace.h>
28#include <lttv/filter.h>
29#include <errno.h>
30
31#define min(a,b) (((a)<(b))?(a):(b))
32
33
34gint compare_tracefile(gconstpointer a, gconstpointer b)
35{
36 gint comparison = 0;
37
38 const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
39 const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
40
41 if(likely(trace_a != trace_b)) {
42 comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
43 if(unlikely(comparison == 0)) {
44 if(trace_a->index < trace_b->index) comparison = -1;
45 else if(trace_a->index > trace_b->index) comparison = 1;
46 else if(trace_a->t_context->index < trace_b->t_context->index)
47 comparison = -1;
48 else if(trace_a->t_context->index > trace_b->t_context->index)
49 comparison = 1;
50 }
51 }
52 return comparison;
53}
54
55typedef struct _LttvTracefileContextPosition {
56 LttEventPosition *event;
57 LttvTracefileContext *tfc;
58 gboolean used; /* Tells if the tfc is at end of traceset position */
59} LttvTracefileContextPosition;
60
61
62struct _LttvTracesetContextPosition {
63 GArray *tfcp; /* Array of LttvTracefileContextPosition */
64 LttTime timestamp; /* Current time at the saved position */
65 /* If ltt_time_infinite : no position is
66 * set, else, a position is set (may be end
67 * of trace, with ep->len == 0) */
68};
69
70void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
71{
72 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
73}
74
75
76void lttv_context_fini(LttvTracesetContext *self)
77{
78 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
79}
80
81
82LttvTracesetContext *
83lttv_context_new_traceset_context(LttvTracesetContext *self)
84{
85 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
86}
87
88
89
90
91LttvTraceContext *
92lttv_context_new_trace_context(LttvTracesetContext *self)
93{
94 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
95}
96
97
98LttvTracefileContext *
99lttv_context_new_tracefile_context(LttvTracesetContext *self)
100{
101 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
102}
103
104/****************************************************************************
105 * lttv_traceset_context_compute_time_span
106 *
107 * Keep the time span is sync with on the fly addition and removal of traces
108 * in a trace set. It must be called each time a trace is added/removed from
109 * the traceset. It could be more efficient to call it only once a bunch
110 * of traces are loaded, but the calculation is not long, so it's not
111 * critical.
112 *
113 * Author : Xang Xiu Yang
114 ***************************************************************************/
115static void lttv_traceset_context_compute_time_span(
116 LttvTracesetContext *self,
117 TimeInterval *time_span)
118{
119 LttvTraceset * traceset = self->ts;
120 int numTraces = lttv_traceset_number(traceset);
121 int i;
122 LttTime s, e;
123 LttvTraceContext *tc;
124 LttTrace * trace;
125
126 time_span->start_time.tv_sec = 0;
127 time_span->start_time.tv_nsec = 0;
128 time_span->end_time.tv_sec = 0;
129 time_span->end_time.tv_nsec = 0;
130
131 for(i=0; i<numTraces;i++){
132 tc = self->traces[i];
133 trace = tc->t;
134
135 ltt_trace_time_span_get(trace, &s, &e);
136 tc->time_span.start_time = s;
137 tc->time_span.end_time = e;
138
139 if(i==0){
140 time_span->start_time = s;
141 time_span->end_time = e;
142 }else{
143 if(s.tv_sec < time_span->start_time.tv_sec
144 || (s.tv_sec == time_span->start_time.tv_sec
145 && s.tv_nsec < time_span->start_time.tv_nsec))
146 time_span->start_time = s;
147 if(e.tv_sec > time_span->end_time.tv_sec
148 || (e.tv_sec == time_span->end_time.tv_sec
149 && e.tv_nsec > time_span->end_time.tv_nsec))
150 time_span->end_time = e;
151 }
152 }
153}
154
155static void init_tracefile_context(LttTracefile *tracefile,
156 LttvTraceContext *tc)
157{
158 LttvTracefileContext *tfc;
159 LttvTracesetContext *tsc = tc->ts_context;
160
161 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(tsc)->new_tracefile_context(tsc);
162
163 tfc->index = tc->tracefiles->len;
164 tc->tracefiles = g_array_append_val(tc->tracefiles, tfc);
165
166 tfc->tf = tracefile;
167
168 tfc->t_context = tc;
169 tfc->event = lttv_hooks_new();
170 tfc->event_by_id = lttv_hooks_by_id_new();
171 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
172 tfc->target_pid = -1;
173}
174
175
176static void
177init(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
252void 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
289void 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
317void 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
347void 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
372void 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
395void 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
415void 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
439void 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
448void 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
454static LttvTracesetContext *
455new_traceset_context(LttvTracesetContext *self)
456{
457 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
458}
459
460
461static LttvTraceContext *
462new_trace_context(LttvTracesetContext *self)
463{
464 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
465}
466
467
468static LttvTracefileContext *
469new_tracefile_context(LttvTracesetContext *self)
470{
471 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
472}
473
474
475static void
476traceset_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
482static void
483traceset_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
490static void
491traceset_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
504GType
505lttv_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
529static void
530trace_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
536static void
537trace_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
544static void
545trace_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
553GType
554lttv_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
578static void
579tracefile_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
585static void
586tracefile_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
593static void
594tracefile_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
602GType
603lttv_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
628static 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.
636static LttTime test_time;
637
638static 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
665void 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 */
687guint lttv_process_traceset_middle(LttvTracesetContext *self,
688 LttTime end,
689 gulong nb_events,
690 const LttvTracesetContextPosition *end_position)
691{
692 GTree *pqueue = self->pqueue;
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 gint last_ret = 0; /* 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
757 e = ltt_tracefile_get_event(tfc->tf);
758
759 //if(last_read_state != LAST_EMPTY) {
760 /* Only call hooks if the last read has given an event or if we are at the
761 * first pass (not if last read returned end of tracefile) */
762 count++;
763
764 tfc->target_pid = -1; /* unset target PID */
765 /* Hooks :
766 * return values : 0 : continue read, 1 : go to next position and stop read,
767 * 2 : stay at the current position and stop read */
768 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
769 lttv_hooks_by_id_get(tfc->event_by_id, e->event_id), tfc);
770
771#if 0
772 /* This is buggy : it won't work well with state computation */
773 if(unlikely(last_ret == 2)) {
774 /* This is a case where we want to stay at this position and stop read. */
775 g_tree_insert(pqueue, tfc, tfc);
776 return count - 1;
777 }
778#endif //0
779 read_ret = ltt_tracefile_read(tfc->tf);
780
781
782 if(likely(!read_ret)) {
783 //g_debug("An event is ready");
784 tfc->timestamp = ltt_event_time(e);
785 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
786 g_tree_insert(pqueue, tfc, tfc);
787#ifdef DEBUG
788 test_time.tv_sec = 0;
789 test_time.tv_nsec = 0;
790 g_debug("test tree after event ready");
791 g_tree_foreach(pqueue, test_tree, NULL);
792#endif //DEBUG
793
794 //last_read_state = LAST_OK;
795 } else {
796 tfc->timestamp = ltt_time_infinite;
797
798 if(read_ret == ERANGE) {
799 // last_read_state = LAST_EMPTY;
800 g_debug("End of trace");
801 } else
802 g_error("Error happened in lttv_process_traceset_middle");
803 }
804 }
805}
806
807
808void lttv_process_traceset_end(LttvTracesetContext *self,
809 LttvHooks *after_traceset,
810 LttvHooks *after_trace,
811 LttvHooks *after_tracefile,
812 LttvHooks *event,
813 LttvHooksById *event_by_id)
814{
815 /* Remove hooks from context. _after hooks are called by remove_hooks. */
816 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
817 lttv_traceset_context_remove_hooks(self,
818 after_traceset,
819 after_trace,
820 after_tracefile,
821 event,
822 event_by_id);
823}
824
825/* Subtile modification :
826 * if tracefile has no event at or after the time requested, it is not put in
827 * the queue, as the next read would fail.
828 *
829 * Don't forget to empty the traceset pqueue before calling this.
830 */
831void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
832{
833 guint i, nb_tracefile;
834
835 gint ret;
836
837 LttvTracefileContext **tfc;
838
839 nb_tracefile = self->tracefiles->len;
840
841 GTree *pqueue = self->ts_context->pqueue;
842
843 for(i = 0 ; i < nb_tracefile ; i++) {
844 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
845
846 g_tree_remove(pqueue, *tfc);
847
848 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
849 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
850
851 if(ret == 0) { /* not ERANGE especially */
852 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
853 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
854 g_tree_insert(pqueue, (*tfc), (*tfc));
855 } else {
856 (*tfc)->timestamp = ltt_time_infinite;
857 }
858 }
859#ifdef DEBUG
860 test_time.tv_sec = 0;
861 test_time.tv_nsec = 0;
862 g_debug("test tree after seek_time");
863 g_tree_foreach(pqueue, test_tree, NULL);
864#endif //DEBUG
865}
866
867
868void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
869{
870 guint i, nb_trace;
871
872 LttvTraceContext *tc;
873
874 //g_tree_destroy(self->pqueue);
875 //self->pqueue = g_tree_new(compare_tracefile);
876
877 nb_trace = lttv_traceset_number(self->ts);
878 for(i = 0 ; i < nb_trace ; i++) {
879 tc = self->traces[i];
880 lttv_process_trace_seek_time(tc, start);
881 }
882}
883
884
885gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
886 const LttvTracesetContextPosition *pos)
887{
888 guint i;
889 /* If a position is set, seek the traceset to this position */
890 if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
891
892 /* Test to see if the traces has been added to the trace set :
893 * It should NEVER happen. Clear all positions if a new trace comes in. */
894 /* FIXME I know this test is not optimal : should keep a number of
895 * tracefiles variable in the traceset.. eventually */
896 guint num_traces = lttv_traceset_number(self->ts);
897 guint tf_count = 0;
898 for(i=0; i<num_traces;i++) {
899 GArray * tracefiles = self->traces[i]->tracefiles;
900 guint j;
901 guint num_tracefiles = tracefiles->len;
902 for(j=0;j<num_tracefiles;j++)
903 tf_count++;
904 }
905 g_assert(tf_count == pos->tfcp->len);
906
907
908 //g_tree_destroy(self->pqueue);
909 //self->pqueue = g_tree_new(compare_tracefile);
910
911 for(i=0;i<pos->tfcp->len; i++) {
912 LttvTracefileContextPosition *tfcp =
913 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
914
915 g_tree_remove(self->pqueue, tfcp->tfc);
916
917 if(tfcp->used == TRUE) {
918 if(ltt_tracefile_seek_position(tfcp->tfc->tf, tfcp->event) != 0)
919 return 1;
920 tfcp->tfc->timestamp =
921 ltt_event_time(ltt_tracefile_get_event(tfcp->tfc->tf));
922 g_assert(ltt_time_compare(tfcp->tfc->timestamp,
923 ltt_time_infinite) != 0);
924 g_tree_insert(self->pqueue, tfcp->tfc, tfcp->tfc);
925
926 } else {
927 tfcp->tfc->timestamp = ltt_time_infinite;
928 }
929 }
930 }
931#ifdef DEBUG
932 test_time.tv_sec = 0;
933 test_time.tv_nsec = 0;
934 g_debug("test tree after seek_position");
935 g_tree_foreach(self->pqueue, test_tree, NULL);
936#endif //DEBUG
937
938
939
940 return 0;
941}
942
943
944#if 0 // pmf: temporary disable
945static LttField *
946find_field(LttEventType *et, const GQuark field)
947{
948 LttField *f;
949
950 if(field == 0) return NULL;
951
952 f = ltt_eventtype_field_by_name(et, field);
953 if (!f) {
954 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field),
955 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et))),
956 g_quark_to_string(ltt_eventtype_name(et)));
957 }
958
959 return f;
960}
961#endif
962
963struct marker_info *lttv_trace_hook_get_marker(LttTrace *t, LttvTraceHook *th)
964{
965 return marker_get_info_from_id(t, th->id);
966}
967
968int lttv_trace_find_hook(LttTrace *t, GQuark facility_name, GQuark event_name,
969 GQuark fields[], LttvHook h, gpointer hook_data, GArray **trace_hooks)
970{
971 struct marker_info *info;
972 guint16 marker_id;
973 int init_array_size;
974 GQuark marker_name;
975
976 marker_name = lttv_merge_facility_event_name(facility_name, event_name);
977
978 info = marker_get_info_from_name(t, marker_name);
979 if(unlikely(info == NULL)) {
980 g_warning("No marker of name %s found", g_quark_to_string(marker_name));
981 return 1;
982 }
983
984 init_array_size = (*trace_hooks)->len;
985
986 /* for each marker with the requested name */
987 do {
988 LttvTraceHook tmpth;
989 int found;
990 GQuark *f;
991 struct marker_field *marker_field;
992
993 marker_id = marker_get_id_from_info(t, info);
994
995 tmpth.h = h;
996 tmpth.id = marker_id;
997 tmpth.hook_data = hook_data;
998 tmpth.fields = g_ptr_array_new();
999
1000 /* for each field requested */
1001 for(f = fields; f && *f != 0; f++) {
1002 found = 0;
1003 for_each_marker_field(marker_field, info) {
1004 if(marker_field->name == *f) {
1005 found = 1;
1006 g_ptr_array_add(tmpth.fields, marker_field);
1007 break;
1008 }
1009 }
1010 if(!found) {
1011 /* Did not find the one of the fields in this instance of the
1012 marker. Print a warning and skip this marker completely.
1013 Still iterate on other markers with same name. */
1014 g_ptr_array_free(tmpth.fields, TRUE);
1015 g_warning("Field %s cannot be found in marker %s",
1016 g_quark_to_string(*f), g_quark_to_string(marker_name));
1017 goto skip_marker;
1018 }
1019 }
1020 /* all fields were found: add the tracehook to the array */
1021 *trace_hooks = g_array_append_val(*trace_hooks, tmpth);
1022skip_marker:
1023 info = info->next;
1024 } while(info != NULL);
1025
1026 /* Error if no new trace hook has been added */
1027 if (init_array_size == (*trace_hooks)->len) {
1028 g_warning("No marker of name %s has all requested fields",
1029 g_quark_to_string(marker_name));
1030 return 1;
1031 }
1032 return 0;
1033}
1034
1035void lttv_trace_hook_remove_all(GArray **th)
1036{
1037 int i;
1038 for(i=0; i<(*th)->len; i++) {
1039 g_ptr_array_free(g_array_index(*th, LttvTraceHook, i).fields, TRUE);
1040 }
1041 if((*th)->len)
1042 *th = g_array_remove_range(*th, 0, (*th)->len);
1043}
1044
1045LttvTracesetContextPosition *lttv_traceset_context_position_new(
1046 const LttvTracesetContext *self)
1047{
1048 guint num_traces = lttv_traceset_number(self->ts);
1049 guint tf_count = 0;
1050 guint i;
1051
1052 for(i=0; i<num_traces;i++) {
1053 GArray * tracefiles = self->traces[i]->tracefiles;
1054 guint j;
1055 guint num_tracefiles = tracefiles->len;
1056 for(j=0;j<num_tracefiles;j++)
1057 tf_count++;
1058 }
1059 LttvTracesetContextPosition *pos =
1060 g_new(LttvTracesetContextPosition, 1);
1061 pos->tfcp = g_array_sized_new(FALSE, TRUE,
1062 sizeof(LttvTracefileContextPosition),
1063 tf_count);
1064 g_array_set_size(pos->tfcp, tf_count);
1065 for(i=0;i<pos->tfcp->len;i++) {
1066 LttvTracefileContextPosition *tfcp =
1067 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1068 tfcp->event = ltt_event_position_new();
1069 }
1070
1071 pos->timestamp = ltt_time_infinite;
1072 return pos;
1073}
1074
1075/* Save all positions, the ones with infinite time will have NULL
1076 * ep. */
1077/* note : a position must be destroyed when a trace is added/removed from a
1078 * traceset */
1079void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1080 LttvTracesetContextPosition *pos)
1081{
1082 guint i;
1083 guint num_traces = lttv_traceset_number(self->ts);
1084 guint tf_count = 0;
1085
1086 pos->timestamp = ltt_time_infinite;
1087
1088 for(i=0; i<num_traces;i++) {
1089 GArray * tracefiles = self->traces[i]->tracefiles;
1090 guint j;
1091 guint num_tracefiles = tracefiles->len;
1092
1093 for(j=0;j<num_tracefiles;j++) {
1094 g_assert(tf_count < pos->tfcp->len);
1095 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1096 LttvTracefileContext*, j);
1097 LttvTracefileContextPosition *tfcp =
1098 &g_array_index(pos->tfcp, LttvTracefileContextPosition, tf_count);
1099
1100 tfcp->tfc = *tfc;
1101
1102 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1103 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1104 ltt_event_position(event, tfcp->event);
1105 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1106 pos->timestamp = (*tfc)->timestamp;
1107 tfcp->used = TRUE;
1108 } else {
1109 tfcp->used = FALSE;
1110 }
1111
1112 //g_array_append_val(pos->tfc, *tfc);
1113 //g_array_append_val(pos->ep, ep);
1114 tf_count++;
1115 }
1116
1117 }
1118}
1119
1120void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1121{
1122 int i;
1123
1124 for(i=0;i<pos->tfcp->len;i++) {
1125 LttvTracefileContextPosition *tfcp =
1126 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1127 g_free(tfcp->event);
1128 tfcp->event = NULL;
1129 tfcp->used = FALSE;
1130 }
1131 g_array_free(pos->tfcp, TRUE);
1132 g_free(pos);
1133}
1134
1135void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1136 const LttvTracesetContextPosition *src)
1137{
1138 int i;
1139 LttvTracefileContextPosition *src_tfcp, *dest_tfcp;
1140
1141 g_assert(src->tfcp->len == src->tfcp->len);
1142
1143 for(i=0;i<src->tfcp->len;i++) {
1144 src_tfcp =
1145 &g_array_index(src->tfcp, LttvTracefileContextPosition, i);
1146 dest_tfcp =
1147 &g_array_index(dest->tfcp, LttvTracefileContextPosition, i);
1148
1149 dest_tfcp->used = src_tfcp->used;
1150 dest_tfcp->tfc = src_tfcp->tfc;
1151
1152 if(src_tfcp->used) {
1153 ltt_event_position_copy(
1154 dest_tfcp->event,
1155 src_tfcp->event);
1156 }
1157 }
1158 dest->timestamp = src->timestamp;
1159}
1160
1161gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1162 const LttvTracesetContextPosition *pos)
1163{
1164 int i;
1165 int ret = 0;
1166
1167 if(pos->tfcp->len == 0) {
1168 if(lttv_traceset_number(self->ts) == 0) return 0;
1169 else return 1;
1170 }
1171 if(lttv_traceset_number(self->ts) == 0)
1172 return -1;
1173
1174 for(i=0;i<pos->tfcp->len;i++) {
1175 LttvTracefileContextPosition *tfcp =
1176 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1177
1178 if(tfcp->used == FALSE) {
1179 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) < 0) {
1180 ret = -1;
1181 }
1182 } else {
1183 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) == 0) {
1184 ret = 1;
1185 } else {
1186 LttEvent *event = ltt_tracefile_get_event(tfcp->tfc->tf);
1187
1188 ret = ltt_event_position_compare((LttEventPosition*)event,
1189 tfcp->event);
1190 }
1191 }
1192 if(ret != 0) return ret;
1193
1194 }
1195 return 0;
1196}
1197
1198
1199gint lttv_traceset_context_pos_pos_compare(
1200 const LttvTracesetContextPosition *pos1,
1201 const LttvTracesetContextPosition *pos2)
1202{
1203 int i, j;
1204 int ret = 0;
1205
1206 if(ltt_time_compare(pos1->timestamp, ltt_time_infinite) == 0) {
1207 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
1208 return 0;
1209 else
1210 return 1;
1211 }
1212 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
1213 return -1;
1214
1215 for(i=0;i<pos1->tfcp->len;i++) {
1216 LttvTracefileContextPosition *tfcp1 =
1217 &g_array_index(pos1->tfcp, LttvTracefileContextPosition, i);
1218
1219 if(tfcp1->used == TRUE) {
1220 for(j=0;j<pos2->tfcp->len;j++) {
1221 LttvTracefileContextPosition *tfcp2 =
1222 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1223
1224 if(tfcp1->tfc == tfcp2->tfc) {
1225 if(tfcp2->used == TRUE)
1226 ret = ltt_event_position_compare(tfcp1->event, tfcp2->event);
1227 else
1228 ret = -1;
1229
1230 if(ret != 0) return ret;
1231 }
1232 }
1233
1234 } else {
1235 for(j=0;j<pos2->tfcp->len;j++) {
1236 LttvTracefileContextPosition *tfcp2 =
1237 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1238
1239 if(tfcp1->tfc == tfcp2->tfc)
1240 if(tfcp2->used == TRUE) ret = 1;
1241 if(ret != 0) return ret;
1242 }
1243 }
1244 }
1245 return 0;
1246}
1247
1248
1249LttTime lttv_traceset_context_position_get_time(
1250 const LttvTracesetContextPosition *pos)
1251{
1252 return pos->timestamp;
1253}
1254
1255
1256LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1257{
1258 GTree *pqueue = self->pqueue;
1259 LttvTracefileContext *tfc = NULL;
1260
1261 g_tree_foreach(pqueue, get_first, &tfc);
1262
1263 return tfc;
1264}
1265
1266/* lttv_process_traceset_synchronize_tracefiles
1267 *
1268 * Use the sync_position field of the trace set context to synchronize each
1269 * tracefile with the previously saved position.
1270 *
1271 * If no previous position has been saved, it simply does nothing.
1272 */
1273void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1274{
1275 g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
1276}
1277
1278
1279
1280
1281void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1282{
1283 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1284}
1285
1286struct seek_back_data {
1287 guint first_event; /* Index of the first event in the array : we will always
1288 overwrite at this position : this is a circular array.
1289 */
1290 guint events_found;
1291 guint n; /* number of events requested */
1292 GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
1293 LttvFilter *filter1;
1294 LttvFilter *filter2;
1295 LttvFilter *filter3;
1296 gpointer data;
1297 check_handler *check;
1298 gboolean *stop_flag;
1299 guint raw_event_count;
1300};
1301
1302static gint seek_back_event_hook(void *hook_data, void* call_data)
1303{
1304 struct seek_back_data *sd = (struct seek_back_data*)hook_data;
1305 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1306 LttvTracesetContext *tsc = tfc->t_context->ts_context;
1307 LttvTracesetContextPosition *pos;
1308
1309 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
1310 return TRUE;
1311 sd->raw_event_count++;
1312
1313 if(sd->filter1 != NULL && sd->filter1->head != NULL &&
1314 !lttv_filter_tree_parse(sd->filter1->head,
1315 ltt_tracefile_get_event(tfc->tf),
1316 tfc->tf,
1317 tfc->t_context->t,
1318 tfc,NULL,NULL)) {
1319 return FALSE;
1320 }
1321 if(sd->filter2 != NULL && sd->filter2->head != NULL &&
1322 !lttv_filter_tree_parse(sd->filter2->head,
1323 ltt_tracefile_get_event(tfc->tf),
1324 tfc->tf,
1325 tfc->t_context->t,
1326 tfc,NULL,NULL)) {
1327 return FALSE;
1328 }
1329 if(sd->filter3 != NULL && sd->filter3->head != NULL &&
1330 !lttv_filter_tree_parse(sd->filter3->head,
1331 ltt_tracefile_get_event(tfc->tf),
1332 tfc->tf,
1333 tfc->t_context->t,
1334 tfc,NULL,NULL)) {
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 */
1377guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
1378 guint n, LttTime first_offset,
1379 seek_time_fct time_seeker,
1380 check_handler *check,
1381 gboolean *stop_flag,
1382 LttvFilter *filter1,
1383 LttvFilter *filter2,
1384 LttvFilter *filter3,
1385 gpointer data)
1386{
1387 if(lttv_traceset_number(self->ts) == 0) return 0;
1388 g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
1389
1390 guint i;
1391 LttvTracesetContextPosition *next_iter_end_pos =
1392 lttv_traceset_context_position_new(self);
1393 LttvTracesetContextPosition *end_pos =
1394 lttv_traceset_context_position_new(self);
1395 LttvTracesetContextPosition *saved_pos =
1396 lttv_traceset_context_position_new(self);
1397 LttTime time;
1398 LttTime asked_time;
1399 LttTime time_offset;
1400 struct seek_back_data sd;
1401 LttvHooks *hooks = lttv_hooks_new();
1402
1403 sd.first_event = 0;
1404 sd.events_found = 0;
1405 sd.array = g_ptr_array_sized_new(n);
1406 sd.filter1 = filter1;
1407 sd.filter2 = filter2;
1408 sd.filter3 = filter3;
1409 sd.data = data;
1410 sd.n = n;
1411 sd.check = check;
1412 sd.stop_flag = stop_flag;
1413 sd.raw_event_count = 0;
1414 g_ptr_array_set_size(sd.array, n);
1415 for(i=0;i<n;i++) {
1416 g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new(self);
1417 }
1418
1419 lttv_traceset_context_position_save(self, next_iter_end_pos);
1420 lttv_traceset_context_position_save(self, saved_pos);
1421 /* Get the current time from which we will offset */
1422 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1423 /* the position saved might be end of traceset... */
1424 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1425 time = self->time_span.end_time;
1426 }
1427 asked_time = time;
1428 time_offset = first_offset;
1429
1430 lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT);
1431
1432 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1433
1434 while(1) {
1435 /* stop criteria : - n events found
1436 * - asked_time < beginning of trace */
1437 if(ltt_time_compare(asked_time, self->time_span.start_time) < 0) break;
1438
1439 lttv_traceset_context_position_copy(end_pos, next_iter_end_pos);
1440
1441 /* We must seek the traceset back to time - time_offset */
1442 /* this time becomes the new reference time */
1443 time = ltt_time_sub(time, time_offset);
1444 asked_time = time;
1445
1446 time_seeker(self, time);
1447 lttv_traceset_context_position_save(self, next_iter_end_pos);
1448 /* Resync the time in case of a seek_closest */
1449 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1450 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1451 time = self->time_span.end_time;
1452 }
1453
1454 /* Process the traceset, calling a hook which adds events
1455 * to the array, overwriting the tail. It changes first_event and
1456 * events_found too. */
1457 /* We would like to have a clean context here : no other hook than our's */
1458
1459 lttv_process_traceset_middle(self, ltt_time_infinite,
1460 G_MAXUINT, end_pos);
1461
1462 if(sd.events_found < n) {
1463 if(sd.first_event > 0) {
1464 /* Save the first position */
1465 LttvTracesetContextPosition *pos =
1466 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0);
1467 lttv_traceset_context_position_copy(saved_pos, pos);
1468 }
1469 g_assert(n-sd.events_found <= sd.array->len);
1470 /* Change array size to n - events_found */
1471 for(i=n-sd.events_found;i<sd.array->len;i++) {
1472 LttvTracesetContextPosition *pos =
1473 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1474 lttv_traceset_context_position_destroy(pos);
1475 }
1476 g_ptr_array_set_size(sd.array, n-sd.events_found);
1477 sd.first_event = 0;
1478
1479 } else break; /* Second end criterion : n events found */
1480
1481 time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL);
1482 }
1483
1484 lttv_traceset_context_position_destroy(end_pos);
1485 lttv_traceset_context_position_destroy(next_iter_end_pos);
1486
1487 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1488
1489 if(sd.events_found >= n) {
1490 /* Seek the traceset to the first event in the circular array */
1491 LttvTracesetContextPosition *pos =
1492 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array,
1493 sd.first_event);
1494 g_assert(lttv_process_traceset_seek_position(self, pos) == 0);
1495 } else {
1496 /* Will seek to the last saved position : in the worst case, it will be the
1497 * original position (if events_found is 0) */
1498 g_assert(lttv_process_traceset_seek_position(self, saved_pos) == 0);
1499 }
1500
1501 for(i=0;i<sd.array->len;i++) {
1502 LttvTracesetContextPosition *pos =
1503 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1504 lttv_traceset_context_position_destroy(pos);
1505 }
1506 g_ptr_array_free(sd.array, TRUE);
1507
1508 lttv_hooks_destroy(hooks);
1509
1510 lttv_traceset_context_position_destroy(saved_pos);
1511
1512 return sd.events_found;
1513}
1514
1515
1516struct seek_forward_data {
1517 guint event_count; /* event counter */
1518 guint n; /* requested number of events to jump over */
1519 LttvFilter *filter1;
1520 LttvFilter *filter2;
1521 LttvFilter *filter3;
1522 gpointer data;
1523 check_handler *check;
1524 gboolean *stop_flag;
1525 guint raw_event_count; /* event counter */
1526};
1527
1528static gint seek_forward_event_hook(void *hook_data, void* call_data)
1529{
1530 struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
1531 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1532
1533 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
1534 return TRUE;
1535 sd->raw_event_count++;
1536
1537 if(sd->filter1 != NULL && sd->filter1->head != NULL &&
1538 !lttv_filter_tree_parse(sd->filter1->head,
1539 ltt_tracefile_get_event(tfc->tf),
1540 tfc->tf,
1541 tfc->t_context->t,
1542 tfc,NULL,NULL)) {
1543 return FALSE;
1544 }
1545 if(sd->filter2 != NULL && sd->filter2->head != NULL &&
1546 !lttv_filter_tree_parse(sd->filter2->head,
1547 ltt_tracefile_get_event(tfc->tf),
1548 tfc->tf,
1549 tfc->t_context->t,
1550 tfc,NULL,NULL)) {
1551 return FALSE;
1552 }
1553 if(sd->filter3 != NULL && sd->filter3->head != NULL &&
1554 !lttv_filter_tree_parse(sd->filter3->head,
1555 ltt_tracefile_get_event(tfc->tf),
1556 tfc->tf,
1557 tfc->t_context->t,
1558 tfc,NULL,NULL)) {
1559 return FALSE;
1560 }
1561
1562 sd->event_count++;
1563 if(sd->event_count >= sd->n)
1564 return TRUE;
1565 return FALSE;
1566}
1567
1568/* Seek back n events forward from the current position (1 to n)
1569 * 0 is ok too, but it will actually do nothing.
1570 *
1571 * Parameters :
1572 * @self the trace set context
1573 * @n number of events to jump over
1574 * @filter filter to call.
1575 *
1576 * returns : the number of events jumped over (may be less than requested if end
1577 * of traceset reached) */
1578guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
1579 guint n,
1580 check_handler *check,
1581 gboolean *stop_flag,
1582 LttvFilter *filter1,
1583 LttvFilter *filter2,
1584 LttvFilter *filter3,
1585 gpointer data)
1586{
1587 struct seek_forward_data sd;
1588 sd.event_count = 0;
1589 sd.n = n;
1590 sd.filter1 = filter1;
1591 sd.filter2 = filter2;
1592 sd.filter3 = filter3;
1593 sd.data = data;
1594 sd.check = check;
1595 sd.stop_flag = stop_flag;
1596 sd.raw_event_count = 0;
1597
1598 if(sd.event_count >= sd.n) return sd.event_count;
1599
1600 LttvHooks *hooks = lttv_hooks_new();
1601
1602 lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
1603
1604 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1605
1606 /* it will end on the end of traceset, or the fact that the
1607 * hook returns TRUE.
1608 */
1609 lttv_process_traceset_middle(self, ltt_time_infinite,
1610 G_MAXUINT, NULL);
1611
1612 /* Here, our position is either the end of traceset, or the exact position
1613 * after n events : leave it like this. This might be placed on an event that
1614 * will be filtered out, we don't care : all we know is that the following
1615 * event filtered in will be the right one. */
1616
1617 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1618
1619 lttv_hooks_destroy(hooks);
1620
1621 return sd.event_count;
1622}
1623
1624
This page took 0.080847 seconds and 4 git commands to generate.