1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
24 #include <lttv/lttv.h>
25 #include <lttv/tracecontext.h>
26 #include <ltt/event.h>
27 #include <ltt/facility.h>
28 #include <ltt/trace.h>
30 #include <lttv/filter.h>
33 #define min(a,b) (((a)<(b))?(a):(b))
36 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
40 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
41 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
43 if(likely(trace_a
!= trace_b
)) {
44 comparison
= ltt_time_compare(trace_a
->timestamp
, trace_b
->timestamp
);
45 if(unlikely(comparison
== 0)) {
46 if(trace_a
->index
< trace_b
->index
) comparison
= -1;
47 else if(trace_a
->index
> trace_b
->index
) comparison
= 1;
48 else if(trace_a
->t_context
->index
< trace_b
->t_context
->index
)
50 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
57 typedef struct _LttvTracefileContextPosition
{
58 LttEventPosition
*event
;
59 LttvTracefileContext
*tfc
;
60 gboolean used
; /* Tells if the tfc is at end of traceset position */
61 } LttvTracefileContextPosition
;
64 struct _LttvTracesetContextPosition
{
65 GArray
*tfcp
; /* Array of LttvTracefileContextPosition */
66 LttTime timestamp
; /* Current time at the saved position */
67 /* If ltt_time_infinite : no position is
68 * set, else, a position is set (may be end
69 * of trace, with ep->len == 0) */
72 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
74 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
78 void lttv_context_fini(LttvTracesetContext
*self
)
80 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
85 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
87 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
94 lttv_context_new_trace_context(LttvTracesetContext
*self
)
96 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
100 LttvTracefileContext
*
101 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
103 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
106 /****************************************************************************
107 * lttv_traceset_context_compute_time_span
109 * Keep the time span is sync with on the fly addition and removal of traces
110 * in a trace set. It must be called each time a trace is added/removed from
111 * the traceset. It could be more efficient to call it only once a bunch
112 * of traces are loaded, but the calculation is not long, so it's not
115 * Author : Xang Xiu Yang
116 ***************************************************************************/
117 static void lttv_traceset_context_compute_time_span(
118 LttvTracesetContext
*self
,
119 TimeInterval
*time_span
)
121 LttvTraceset
* traceset
= self
->ts
;
122 int numTraces
= lttv_traceset_number(traceset
);
125 LttvTraceContext
*tc
;
128 time_span
->start_time
.tv_sec
= 0;
129 time_span
->start_time
.tv_nsec
= 0;
130 time_span
->end_time
.tv_sec
= 0;
131 time_span
->end_time
.tv_nsec
= 0;
133 for(i
=0; i
<numTraces
;i
++){
134 tc
= self
->traces
[i
];
137 ltt_trace_time_span_get(trace
, &s
, &e
);
138 tc
->time_span
.start_time
= s
;
139 tc
->time_span
.end_time
= e
;
142 time_span
->start_time
= s
;
143 time_span
->end_time
= e
;
145 if(s
.tv_sec
< time_span
->start_time
.tv_sec
146 || (s
.tv_sec
== time_span
->start_time
.tv_sec
147 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
148 time_span
->start_time
= s
;
149 if(e
.tv_sec
> time_span
->end_time
.tv_sec
150 || (e
.tv_sec
== time_span
->end_time
.tv_sec
151 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
152 time_span
->end_time
= e
;
157 static void init_tracefile_context(LttTracefile
*tracefile
,
158 LttvTraceContext
*tc
)
160 LttvTracefileContext
*tfc
;
161 LttvTracesetContext
*tsc
= tc
->ts_context
;
163 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
165 tfc
->index
= tc
->tracefiles
->len
;
166 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
171 tfc
->event
= lttv_hooks_new();
172 tfc
->event_by_id
= lttv_hooks_by_id_new();
173 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
178 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
182 LttvTraceContext
*tc
;
184 GData
**tracefiles_groups
;
186 struct compute_tracefile_group_args args
;
188 nb_trace
= lttv_traceset_number(ts
);
190 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
191 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
192 self
->ts_a
= lttv_traceset_attribute(ts
);
193 for(i
= 0 ; i
< nb_trace
; i
++) {
194 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
195 self
->traces
[i
] = tc
;
197 tc
->ts_context
= self
;
199 tc
->vt
= lttv_traceset_get(ts
, i
);
200 tc
->t
= lttv_trace(tc
->vt
);
201 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
202 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
203 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
204 sizeof(LttvTracefileContext
*), 10);
206 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
207 if(tracefiles_groups
!= NULL
) {
208 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
211 g_datalist_foreach(tracefiles_groups
,
212 (GDataForeachFunc
)compute_tracefile_group
,
217 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
218 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
219 nb_tracefile
= nb_control
+ nb_per_cpu
;
220 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
222 for(j
= 0 ; j
< nb_tracefile
; j
++) {
223 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
224 tc
->tracefiles
[j
] = tfc
;
229 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
232 tfc
->control
= FALSE
;
233 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
237 tfc
->e
= ltt_event_new();
238 tfc
->event
= lttv_hooks_new();
239 tfc
->event_by_id
= lttv_hooks_by_id_new();
240 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
245 self
->sync_position
= lttv_traceset_context_position_new(self
);
246 self
->pqueue
= g_tree_new(compare_tracefile
);
247 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
248 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
253 void fini(LttvTracesetContext
*self
)
255 guint i
, j
, nb_trace
, nb_tracefile
;
257 LttvTraceContext
*tc
;
259 LttvTracefileContext
**tfc
;
261 LttvTraceset
*ts
= self
->ts
;
263 g_tree_destroy(self
->pqueue
);
264 g_object_unref(self
->a
);
265 lttv_traceset_context_position_destroy(self
->sync_position
);
267 nb_trace
= lttv_traceset_number(ts
);
269 for(i
= 0 ; i
< nb_trace
; i
++) {
270 tc
= self
->traces
[i
];
272 g_object_unref(tc
->a
);
274 nb_tracefile
= tc
->tracefiles
->len
;
276 for(j
= 0 ; j
< nb_tracefile
; j
++) {
277 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
278 lttv_hooks_destroy((*tfc
)->event
);
279 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
280 g_object_unref((*tfc
)->a
);
281 g_object_unref(*tfc
);
283 g_array_free(tc
->tracefiles
, TRUE
);
286 g_free(self
->traces
);
290 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
291 LttvHooks
*before_traceset
,
292 LttvHooks
*before_trace
,
293 LttvHooks
*before_tracefile
,
295 LttvHooksById
*event_by_id
)
297 LttvTraceset
*ts
= self
->ts
;
301 LttvTraceContext
*tc
;
303 lttv_hooks_call(before_traceset
, self
);
305 nb_trace
= lttv_traceset_number(ts
);
307 for(i
= 0 ; i
< nb_trace
; i
++) {
308 tc
= self
->traces
[i
];
309 lttv_trace_context_add_hooks(tc
,
318 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
319 LttvHooks
*after_traceset
,
320 LttvHooks
*after_trace
,
321 LttvHooks
*after_tracefile
,
323 LttvHooksById
*event_by_id
)
326 LttvTraceset
*ts
= self
->ts
;
330 LttvTraceContext
*tc
;
332 nb_trace
= lttv_traceset_number(ts
);
334 for(i
= 0 ; i
< nb_trace
; i
++) {
335 tc
= self
->traces
[i
];
336 lttv_trace_context_remove_hooks(tc
,
343 lttv_hooks_call(after_traceset
, self
);
348 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
349 LttvHooks
*before_trace
,
350 LttvHooks
*before_tracefile
,
352 LttvHooksById
*event_by_id
)
354 guint i
, nb_tracefile
;
356 LttvTracefileContext
**tfc
;
358 lttv_hooks_call(before_trace
, self
);
360 nb_tracefile
= self
->tracefiles
->len
;
362 for(i
= 0 ; i
< nb_tracefile
; i
++) {
363 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
364 lttv_tracefile_context_add_hooks(*tfc
,
373 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
374 LttvHooks
*after_trace
,
375 LttvHooks
*after_tracefile
,
377 LttvHooksById
*event_by_id
)
379 guint i
, nb_tracefile
;
381 LttvTracefileContext
**tfc
;
383 nb_tracefile
= self
->tracefiles
->len
;
385 for(i
= 0 ; i
< nb_tracefile
; i
++) {
386 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
387 lttv_tracefile_context_remove_hooks(*tfc
,
393 lttv_hooks_call(after_trace
, self
);
396 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
397 LttvHooks
*before_tracefile
,
399 LttvHooksById
*event_by_id
)
405 lttv_hooks_call(before_tracefile
, self
);
406 lttv_hooks_add_list(self
->event
, event
);
407 if(event_by_id
!= NULL
) {
408 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
409 index
= g_array_index(event_by_id
->array
, guint
, i
);
410 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
411 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
416 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
417 LttvHooks
*after_tracefile
,
419 LttvHooksById
*event_by_id
)
425 lttv_hooks_remove_list(self
->event
, event
);
426 if(event_by_id
!= NULL
) {
427 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
428 index
= g_array_index(event_by_id
->array
, guint
, i
);
429 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
431 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
435 lttv_hooks_call(after_tracefile
, self
);
440 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext
*tfc
,
442 LttvHooks
*event_by_id
)
445 h
= lttv_hooks_by_id_find(tfc
->event_by_id
, i
);
446 lttv_hooks_add_list(h
, event_by_id
);
449 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext
*tfc
,
452 lttv_hooks_by_id_remove(tfc
->event_by_id
, i
);
455 static LttvTracesetContext
*
456 new_traceset_context(LttvTracesetContext
*self
)
458 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
462 static LttvTraceContext
*
463 new_trace_context(LttvTracesetContext
*self
)
465 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
469 static LttvTracefileContext
*
470 new_tracefile_context(LttvTracesetContext
*self
)
472 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
477 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
479 /* Be careful of anything which would not work well with shallow copies */
484 traceset_context_finalize (LttvTracesetContext
*self
)
486 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
487 ->finalize(G_OBJECT(self
));
492 traceset_context_class_init (LttvTracesetContextClass
*klass
)
494 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
496 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
499 klass
->new_traceset_context
= new_traceset_context
;
500 klass
->new_trace_context
= new_trace_context
;
501 klass
->new_tracefile_context
= new_tracefile_context
;
506 lttv_traceset_context_get_type(void)
508 static GType type
= 0;
510 static const GTypeInfo info
= {
511 sizeof (LttvTracesetContextClass
),
512 NULL
, /* base_init */
513 NULL
, /* base_finalize */
514 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
515 NULL
, /* class_finalize */
516 NULL
, /* class_data */
517 sizeof (LttvTracesetContext
),
519 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
520 NULL
/* Value handling */
523 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
531 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
533 /* Be careful of anything which would not work well with shallow copies */
538 trace_context_finalize (LttvTraceContext
*self
)
540 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
541 finalize(G_OBJECT(self
));
546 trace_context_class_init (LttvTraceContextClass
*klass
)
548 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
550 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
555 lttv_trace_context_get_type(void)
557 static GType type
= 0;
559 static const GTypeInfo info
= {
560 sizeof (LttvTraceContextClass
),
561 NULL
, /* base_init */
562 NULL
, /* base_finalize */
563 (GClassInitFunc
) trace_context_class_init
, /* class_init */
564 NULL
, /* class_finalize */
565 NULL
, /* class_data */
566 sizeof (LttvTraceContext
),
568 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
569 NULL
/* Value handling */
572 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
580 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
582 /* Be careful of anything which would not work well with shallow copies */
587 tracefile_context_finalize (LttvTracefileContext
*self
)
589 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
590 ->finalize(G_OBJECT(self
));
595 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
597 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
599 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
604 lttv_tracefile_context_get_type(void)
606 static GType type
= 0;
608 static const GTypeInfo info
= {
609 sizeof (LttvTracefileContextClass
),
610 NULL
, /* base_init */
611 NULL
, /* base_finalize */
612 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
613 NULL
, /* class_finalize */
614 NULL
, /* class_data */
615 sizeof (LttvTracefileContext
),
617 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
618 NULL
/* Value handling */
621 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
629 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
630 g_assert(key
== value
);
631 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
636 // Test to see if pqueue is traversed in the right order.
637 static LttTime test_time
;
639 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
641 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
643 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
644 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
645 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
646 tfc
->index
, tfc
->t_context
->index
);
648 if(user_data
!= NULL
) {
649 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
650 g_assert(compare_tracefile(user_data
, value
) == 0);
652 g_assert(compare_tracefile(user_data
, value
) != 0);
654 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
655 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
656 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
659 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
666 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
667 LttvHooks
*before_traceset
,
668 LttvHooks
*before_trace
,
669 LttvHooks
*before_tracefile
,
671 LttvHooksById
*event_by_id
)
674 /* simply add hooks in context. _before hooks are called by add_hooks. */
675 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
676 lttv_traceset_context_add_hooks(self
,
685 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
687 /* Note : a _middle must be preceded from a _seek or another middle */
688 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
691 const LttvTracesetContextPosition
*end_position
)
693 GTree
*pqueue
= self
->pqueue
;
695 guint fac_id
, ev_id
, id
;
697 LttvTracefileContext
*tfc
;
705 //enum read_state last_read_state = LAST_NONE;
707 gint last_ret
= 0; /* return value of the last hook list called */
709 /* Get the next event from the pqueue, call its hooks,
710 reinsert in the pqueue the following event from the same tracefile
711 unless the tracefile is finished or the event is later than the
716 g_tree_foreach(pqueue
, get_first
, &tfc
);
717 /* End of traceset : tfc is NULL */
718 if(unlikely(tfc
== NULL
))
724 * - the maximum number of events specified?
725 * - the end position ?
727 * then the read is finished. We leave the queue in the same state and
731 if(unlikely(last_ret
== TRUE
||
732 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
733 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
734 end_position
) == 0)||
735 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
740 /* Get the tracefile with an event for the smallest time found. If two
741 or more tracefiles have events for the same time, hope that lookup
742 and remove are consistent. */
745 test_time
.tv_sec
= 0;
746 test_time
.tv_nsec
= 0;
747 g_debug("test tree before remove");
748 g_tree_foreach(pqueue
, test_tree
, tfc
);
750 g_tree_remove(pqueue
, tfc
);
753 test_time
.tv_sec
= 0;
754 test_time
.tv_nsec
= 0;
755 g_debug("test tree after remove");
756 g_tree_foreach(pqueue
, test_tree
, tfc
);
760 e
= ltt_tracefile_get_event(tfc
->tf
);
762 //if(last_read_state != LAST_EMPTY) {
763 /* Only call hooks if the last read has given an event or if we are at the
764 * first pass (not if last read returned end of tracefile) */
767 fac_id
= ltt_event_facility_id(e
);
768 ev_id
= ltt_event_eventtype_id(e
);
769 id
= GET_HOOK_ID(fac_id
, ev_id
);
771 * return values : 0 : continue read, 1 : go to next position and stop read,
772 * 2 : stay at the current position and stop read */
773 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
774 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
777 /* This is buggy : it won't work well with state computation */
778 if(unlikely(last_ret
== 2)) {
779 /* This is a case where we want to stay at this position and stop read. */
780 g_tree_insert(pqueue
, tfc
, tfc
);
784 read_ret
= ltt_tracefile_read(tfc
->tf
);
787 if(likely(!read_ret
)) {
788 //g_debug("An event is ready");
789 tfc
->timestamp
= ltt_event_time(e
);
790 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
791 g_tree_insert(pqueue
, tfc
, tfc
);
793 test_time
.tv_sec
= 0;
794 test_time
.tv_nsec
= 0;
795 g_debug("test tree after event ready");
796 g_tree_foreach(pqueue
, test_tree
, NULL
);
799 //last_read_state = LAST_OK;
801 tfc
->timestamp
= ltt_time_infinite
;
803 if(read_ret
== ERANGE
) {
804 // last_read_state = LAST_EMPTY;
805 g_debug("End of trace");
807 g_error("Error happened in lttv_process_traceset_middle");
813 void lttv_process_traceset_end(LttvTracesetContext
*self
,
814 LttvHooks
*after_traceset
,
815 LttvHooks
*after_trace
,
816 LttvHooks
*after_tracefile
,
818 LttvHooksById
*event_by_id
)
820 /* Remove hooks from context. _after hooks are called by remove_hooks. */
821 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
822 lttv_traceset_context_remove_hooks(self
,
830 /* Subtile modification :
831 * if tracefile has no event at or after the time requested, it is not put in
832 * the queue, as the next read would fail.
834 * Don't forget to empty the traceset pqueue before calling this.
836 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
838 guint i
, nb_tracefile
;
842 LttvTracefileContext
**tfc
;
844 nb_tracefile
= self
->tracefiles
->len
;
846 GTree
*pqueue
= self
->ts_context
->pqueue
;
848 for(i
= 0 ; i
< nb_tracefile
; i
++) {
849 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
851 g_tree_remove(pqueue
, *tfc
);
853 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
854 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
856 if(ret
== 0) { /* not ERANGE especially */
857 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
858 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
859 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
861 (*tfc
)->timestamp
= ltt_time_infinite
;
865 test_time
.tv_sec
= 0;
866 test_time
.tv_nsec
= 0;
867 g_debug("test tree after seek_time");
868 g_tree_foreach(pqueue
, test_tree
, NULL
);
876 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
880 LttvTraceContext
*tc
;
882 //g_tree_destroy(self->pqueue);
883 //self->pqueue = g_tree_new(compare_tracefile);
885 nb_trace
= lttv_traceset_number(self
->ts
);
886 for(i
= 0 ; i
< nb_trace
; i
++) {
887 tc
= self
->traces
[i
];
888 lttv_process_trace_seek_time(tc
, start
);
893 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
894 const LttvTracesetContextPosition
*pos
)
897 /* If a position is set, seek the traceset to this position */
898 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
900 /* Test to see if the traces has been added to the trace set :
901 * It should NEVER happen. Clear all positions if a new trace comes in. */
902 /* FIXME I know this test is not optimal : should keep a number of
903 * tracefiles variable in the traceset.. eventually */
904 guint num_traces
= lttv_traceset_number(self
->ts
);
906 for(i
=0; i
<num_traces
;i
++) {
907 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
909 guint num_tracefiles
= tracefiles
->len
;
910 for(j
=0;j
<num_tracefiles
;j
++)
913 g_assert(tf_count
== pos
->tfcp
->len
);
916 //g_tree_destroy(self->pqueue);
917 //self->pqueue = g_tree_new(compare_tracefile);
919 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
920 LttvTracefileContextPosition
*tfcp
=
921 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
923 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
925 if(tfcp
->used
== TRUE
) {
926 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
928 tfcp
->tfc
->timestamp
=
929 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
930 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
931 ltt_time_infinite
) != 0);
932 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
935 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
940 test_time
.tv_sec
= 0;
941 test_time
.tv_nsec
= 0;
942 g_debug("test tree after seek_position");
943 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
954 find_field(LttEventType
*et
, const GQuark field
)
965 if(field
== 0) return NULL
;
967 f
= ltt_eventtype_field(et
);
968 t
= ltt_eventtype_type(et
);
969 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
970 nb
= ltt_type_member_number(t
);
971 for(i
= 0 ; i
< nb
; i
++) {
972 ltt_type_member_type(t
, i
, &name
);
973 if(name
== field
) break;
976 return ltt_field_member(f
, i
);
979 LttvTraceHookByFacility
*lttv_trace_hook_get_fac(LttvTraceHook
*th
,
982 return &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, facility_id
);
985 /* Get the first facility corresponding to the name. As the types must be
986 * compatible, it is relevant to use the field name and sizes of the first
987 * facility to create data structures and assume the data will be compatible
988 * thorough the trace */
989 LttvTraceHookByFacility
*lttv_trace_hook_get_first(LttvTraceHook
*th
)
991 g_assert(th
->fac_list
->len
> 0);
992 return g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0);
996 /* Returns 0 on success, -1 if fails. */
998 lttv_trace_find_hook(LttTrace
*t
, GQuark facility
, GQuark event
,
999 GQuark field1
, GQuark field2
, GQuark field3
, LttvHook h
, gpointer hook_data
,
1004 LttEventType
*et
, *first_et
;
1008 guint i
, fac_id
, ev_id
;
1010 LttvTraceHookByFacility
*thf
, *first_thf
;
1012 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
1014 if(unlikely(facilities
== NULL
)) goto facility_error
;
1016 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
1017 sizeof(LttvTraceHookByFacility
),
1019 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
1021 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
1022 sizeof(LttvTraceHookByFacility
*),
1024 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
1026 fac_id
= g_array_index(facilities
, guint
, 0);
1027 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
1029 et
= ltt_facility_eventtype_get_by_name(f
, event
);
1030 if(unlikely(et
== NULL
)) goto event_error
;
1032 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
1033 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0) = thf
;
1035 ev_id
= ltt_eventtype_id(et
);
1038 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
1039 thf
->f1
= find_field(et
, field1
);
1040 thf
->f2
= find_field(et
, field2
);
1041 thf
->f3
= find_field(et
, field3
);
1042 thf
->hook_data
= hook_data
;
1047 /* Check for type compatibility too */
1048 for(i
=1;i
<facilities
->len
;i
++) {
1049 fac_id
= g_array_index(facilities
, guint
, i
);
1050 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
1052 et
= ltt_facility_eventtype_get_by_name(f
, event
);
1053 if(unlikely(et
== NULL
)) goto event_error
;
1055 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
1056 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
) = thf
;
1057 ev_id
= ltt_eventtype_id(et
);
1059 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
1060 thf
->f1
= find_field(et
, field1
);
1061 if(check_fields_compatibility(first_et
, et
,
1062 first_thf
->f1
, thf
->f1
))
1065 thf
->f2
= find_field(et
, field2
);
1066 if(check_fields_compatibility(first_et
, et
,
1067 first_thf
->f2
, thf
->f2
))
1070 thf
->f3
= find_field(et
, field3
);
1071 if(check_fields_compatibility(first_et
, et
,
1072 first_thf
->f3
, thf
->f3
))
1074 thf
->hook_data
= hook_data
;
1082 g_error("Event type does not exist for event %s",
1083 g_quark_to_string(event
));
1086 g_error("No %s facility", g_quark_to_string(facility
));
1089 g_array_free(th
->fac_index
, TRUE
);
1090 g_array_free(th
->fac_list
, TRUE
);
1091 th
->fac_index
= NULL
;
1092 th
->fac_list
= NULL
;
1096 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
1098 g_array_free(th
->fac_index
, TRUE
);
1099 g_array_free(th
->fac_list
, TRUE
);
1105 LttvTracesetContextPosition
*lttv_traceset_context_position_new(
1106 const LttvTracesetContext
*self
)
1108 guint num_traces
= lttv_traceset_number(self
->ts
);
1112 for(i
=0; i
<num_traces
;i
++) {
1113 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1115 guint num_tracefiles
= tracefiles
->len
;
1116 for(j
=0;j
<num_tracefiles
;j
++)
1119 LttvTracesetContextPosition
*pos
=
1120 g_new(LttvTracesetContextPosition
, 1);
1121 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1122 sizeof(LttvTracefileContextPosition
),
1124 g_array_set_size(pos
->tfcp
, tf_count
);
1125 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1126 LttvTracefileContextPosition
*tfcp
=
1127 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1128 tfcp
->event
= ltt_event_position_new();
1131 pos
->timestamp
= ltt_time_infinite
;
1135 /* Save all positions, the ones with infinite time will have NULL
1137 /* note : a position must be destroyed when a trace is added/removed from a
1139 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1140 LttvTracesetContextPosition
*pos
)
1143 guint num_traces
= lttv_traceset_number(self
->ts
);
1146 pos
->timestamp
= ltt_time_infinite
;
1148 for(i
=0; i
<num_traces
;i
++) {
1149 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1151 guint num_tracefiles
= tracefiles
->len
;
1153 for(j
=0;j
<num_tracefiles
;j
++) {
1154 g_assert(tf_count
< pos
->tfcp
->len
);
1155 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1156 LttvTracefileContext
*, j
);
1157 LttvTracefileContextPosition
*tfcp
=
1158 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1162 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1163 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1164 ltt_event_position(event
, tfcp
->event
);
1165 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1166 pos
->timestamp
= (*tfc
)->timestamp
;
1172 //g_array_append_val(pos->tfc, *tfc);
1173 //g_array_append_val(pos->ep, ep);
1180 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1184 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1185 LttvTracefileContextPosition
*tfcp
=
1186 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1187 g_free(tfcp
->event
);
1191 g_array_free(pos
->tfcp
, TRUE
);
1195 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1196 const LttvTracesetContextPosition
*src
)
1199 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1201 g_assert(src
->tfcp
->len
== src
->tfcp
->len
);
1203 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1205 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1207 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1209 dest_tfcp
->used
= src_tfcp
->used
;
1210 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1212 if(src_tfcp
->used
) {
1213 ltt_event_position_copy(
1218 dest
->timestamp
= src
->timestamp
;
1221 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1222 const LttvTracesetContextPosition
*pos
)
1227 if(pos
->tfcp
->len
== 0) {
1228 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1231 if(lttv_traceset_number(self
->ts
) == 0)
1234 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1235 LttvTracefileContextPosition
*tfcp
=
1236 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1238 if(tfcp
->used
== FALSE
) {
1239 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1243 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1246 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1248 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1252 if(ret
!= 0) return ret
;
1259 gint
lttv_traceset_context_pos_pos_compare(
1260 const LttvTracesetContextPosition
*pos1
,
1261 const LttvTracesetContextPosition
*pos2
)
1266 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1267 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1272 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1275 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1276 LttvTracefileContextPosition
*tfcp1
=
1277 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1279 if(tfcp1
->used
== TRUE
) {
1280 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1281 LttvTracefileContextPosition
*tfcp2
=
1282 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1284 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1285 if(tfcp2
->used
== TRUE
)
1286 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1290 if(ret
!= 0) return ret
;
1295 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1296 LttvTracefileContextPosition
*tfcp2
=
1297 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1299 if(tfcp1
->tfc
== tfcp2
->tfc
)
1300 if(tfcp2
->used
== TRUE
) ret
= 1;
1301 if(ret
!= 0) return ret
;
1309 LttTime
lttv_traceset_context_position_get_time(
1310 const LttvTracesetContextPosition
*pos
)
1312 return pos
->timestamp
;
1316 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1318 GTree
*pqueue
= self
->pqueue
;
1319 LttvTracefileContext
*tfc
= NULL
;
1321 g_tree_foreach(pqueue
, get_first
, &tfc
);
1326 /* lttv_process_traceset_synchronize_tracefiles
1328 * Use the sync_position field of the trace set context to synchronize each
1329 * tracefile with the previously saved position.
1331 * If no previous position has been saved, it simply does nothing.
1333 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1335 g_assert(lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
) == 0);
1341 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1343 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1346 struct seek_back_data
{
1347 guint first_event
; /* Index of the first event in the array : we will always
1348 overwrite at this position : this is a circular array.
1351 guint n
; /* number of events requested */
1352 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1356 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1358 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1359 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1360 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1361 LttvTracesetContextPosition
*pos
;
1363 if(sd
->filter
!= NULL
&& sd
->filter
->head
!= NULL
) {
1364 if(!lttv_filter_tree_parse(sd
->filter
->head
,
1365 ltt_tracefile_get_event(tfc
->tf
),
1372 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1375 lttv_traceset_context_position_save(tsc
, pos
);
1377 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1378 else sd
->first_event
++;
1380 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1385 /* Seek back n events back from the current position.
1388 * @self The trace set context
1389 * @n number of events to jump over
1390 * @first_offset The initial offset value used.
1391 * never put first_offset at ltt_time_zero.
1392 * @time_seeker Function pointer of the function to use to seek time :
1393 * either lttv_process_traceset_seek_time
1394 * or lttv_state_traceset_seek_time_closest
1395 * @filter The filter to call.
1397 * Return value : the number of events found (might be lower than the number
1398 * requested if beginning of traceset is reached).
1400 * The first search will go back first_offset and try to find the last n events
1401 * matching the filter. If there are not enough, it will try to go back from the
1402 * new trace point from first_offset*2, and so on, until beginning of trace or n
1405 * Note : this function does not take in account the LttvFilter : use the
1406 * similar function found in state.c instead.
1408 * Note2 : the caller must make sure that the LttvTracesetContext does not
1409 * contain any hook, as process_traceset_middle is used in this routine.
1411 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1412 guint n
, LttTime first_offset
,
1413 seek_time_fct time_seeker
,
1416 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1417 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1420 LttvTracesetContextPosition
*next_iter_end_pos
=
1421 lttv_traceset_context_position_new(self
);
1422 LttvTracesetContextPosition
*end_pos
=
1423 lttv_traceset_context_position_new(self
);
1424 LttvTracesetContextPosition
*saved_pos
=
1425 lttv_traceset_context_position_new(self
);
1428 LttTime time_offset
;
1429 struct seek_back_data sd
;
1430 LttvHooks
*hooks
= lttv_hooks_new();
1433 sd
.events_found
= 0;
1434 sd
.array
= g_ptr_array_sized_new(n
);
1437 g_ptr_array_set_size(sd
.array
, n
);
1439 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1442 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1443 lttv_traceset_context_position_save(self
, saved_pos
);
1444 /* Get the current time from which we will offset */
1445 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1446 /* the position saved might be end of traceset... */
1447 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1448 time
= self
->time_span
.end_time
;
1451 time_offset
= first_offset
;
1453 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1455 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1458 /* stop criteria : - n events found
1459 * - asked_time < beginning of trace */
1460 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) < 0) break;
1462 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1464 /* We must seek the traceset back to time - time_offset */
1465 /* this time becomes the new reference time */
1466 time
= ltt_time_sub(time
, time_offset
);
1469 time_seeker(self
, time
);
1470 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1471 /* Resync the time in case of a seek_closest */
1472 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1473 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1474 time
= self
->time_span
.end_time
;
1477 /* Process the traceset, calling a hook which adds events
1478 * to the array, overwriting the tail. It changes first_event and
1479 * events_found too. */
1480 /* We would like to have a clean context here : no other hook than our's */
1482 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1483 G_MAXUINT
, end_pos
);
1485 if(sd
.events_found
< n
) {
1486 if(sd
.first_event
> 0) {
1487 /* Save the first position */
1488 LttvTracesetContextPosition
*pos
=
1489 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1490 lttv_traceset_context_position_copy(saved_pos
, pos
);
1492 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1493 /* Change array size to n - events_found */
1494 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1495 LttvTracesetContextPosition
*pos
=
1496 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1497 lttv_traceset_context_position_destroy(pos
);
1499 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1502 } else break; /* Second end criterion : n events found */
1504 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1507 lttv_traceset_context_position_destroy(end_pos
);
1508 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1510 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1512 if(sd
.events_found
>= n
) {
1513 /* Seek the traceset to the first event in the circular array */
1514 LttvTracesetContextPosition
*pos
=
1515 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1517 g_assert(lttv_process_traceset_seek_position(self
, pos
) == 0);
1519 /* Will seek to the last saved position : in the worst case, it will be the
1520 * original position (if events_found is 0) */
1521 g_assert(lttv_process_traceset_seek_position(self
, saved_pos
) == 0);
1524 for(i
=0;i
<sd
.array
->len
;i
++) {
1525 LttvTracesetContextPosition
*pos
=
1526 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1527 lttv_traceset_context_position_destroy(pos
);
1529 g_ptr_array_free(sd
.array
, TRUE
);
1531 lttv_hooks_destroy(hooks
);
1533 lttv_traceset_context_position_destroy(saved_pos
);
1535 return sd
.events_found
;
1539 struct seek_forward_data
{
1540 guint event_count
; /* event counter */
1541 guint n
; /* requested number of events to jump over */
1545 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1547 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1548 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1550 if(sd
->filter
== NULL
|| lttv_filter_tree_parse(sd
->filter
->head
,
1551 ltt_tracefile_get_event(tfc
->tf
),
1556 if(sd
->event_count
>= sd
->n
)
1562 /* Seek back n events forward from the current position (1 to n)
1563 * 0 is ok too, but it will actually do nothing.
1566 * @self the trace set context
1567 * @n number of events to jump over
1568 * @filter filter to call.
1570 * returns : the number of events jumped over (may be less than requested if end
1571 * of traceset reached) */
1572 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1573 guint n
, LttvFilter
*filter
)
1575 struct seek_forward_data sd
;
1580 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1582 LttvHooks
*hooks
= lttv_hooks_new();
1584 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1586 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1588 /* it will end on the end of traceset, or the fact that the
1589 * hook returns TRUE.
1591 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1594 /* Here, our position is either the end of traceset, or the exact position
1595 * after n events : leave it like this. This might be placed on an event that
1596 * will be filtered out, we don't care : all we know is that the following
1597 * event filtered in will be the right one. */
1599 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1601 lttv_hooks_destroy(hooks
);
1603 return sd
.event_count
;