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/trace.h>
28 #include <lttv/filter.h>
31 #define min(a,b) (((a)<(b))?(a):(b))
34 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
38 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
39 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
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
)
48 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
55 typedef struct _LttvTracefileContextPosition
{
56 LttEventPosition
*event
;
57 LttvTracefileContext
*tfc
;
58 gboolean used
; /* Tells if the tfc is at end of traceset position */
59 } LttvTracefileContextPosition
;
62 struct _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) */
70 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
72 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
76 void lttv_context_fini(LttvTracesetContext
*self
)
78 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
83 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
85 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
92 lttv_context_new_trace_context(LttvTracesetContext
*self
)
94 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
98 LttvTracefileContext
*
99 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
101 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
104 /****************************************************************************
105 * lttv_traceset_context_compute_time_span
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
113 * Author : Xang Xiu Yang
114 ***************************************************************************/
115 static void lttv_traceset_context_compute_time_span(
116 LttvTracesetContext
*self
,
117 TimeInterval
*time_span
)
119 LttvTraceset
* traceset
= self
->ts
;
120 int numTraces
= lttv_traceset_number(traceset
);
123 LttvTraceContext
*tc
;
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;
131 for(i
=0; i
<numTraces
;i
++){
132 tc
= self
->traces
[i
];
135 ltt_trace_time_span_get(trace
, &s
, &e
);
136 tc
->time_span
.start_time
= s
;
137 tc
->time_span
.end_time
= e
;
140 time_span
->start_time
= s
;
141 time_span
->end_time
= e
;
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
;
155 static void init_tracefile_context(LttTracefile
*tracefile
,
156 LttvTraceContext
*tc
)
158 LttvTracefileContext
*tfc
;
159 LttvTracesetContext
*tsc
= tc
->ts_context
;
161 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
163 tfc
->index
= tc
->tracefiles
->len
;
164 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
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;
177 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
181 LttvTraceContext
*tc
;
183 GData
**tracefiles_groups
;
185 struct compute_tracefile_group_args args
;
187 nb_trace
= lttv_traceset_number(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
;
196 tc
->ts_context
= self
;
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);
205 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
206 if(tracefiles_groups
!= NULL
) {
207 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
210 g_datalist_foreach(tracefiles_groups
,
211 (GDataForeachFunc
)compute_tracefile_group
,
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
);
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
;
228 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
231 tfc
->control
= FALSE
;
232 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
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
);
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
);
252 void fini(LttvTracesetContext
*self
)
254 guint i
, j
, nb_trace
, nb_tracefile
;
256 LttvTraceContext
*tc
;
258 LttvTracefileContext
**tfc
;
260 LttvTraceset
*ts
= self
->ts
;
262 g_tree_destroy(self
->pqueue
);
263 g_object_unref(self
->a
);
264 lttv_traceset_context_position_destroy(self
->sync_position
);
266 nb_trace
= lttv_traceset_number(ts
);
268 for(i
= 0 ; i
< nb_trace
; i
++) {
269 tc
= self
->traces
[i
];
271 g_object_unref(tc
->a
);
273 nb_tracefile
= tc
->tracefiles
->len
;
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
);
282 g_array_free(tc
->tracefiles
, TRUE
);
285 g_free(self
->traces
);
289 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
290 LttvHooks
*before_traceset
,
291 LttvHooks
*before_trace
,
292 LttvHooks
*before_tracefile
,
294 LttvHooksById
*event_by_id
)
296 LttvTraceset
*ts
= self
->ts
;
300 LttvTraceContext
*tc
;
302 lttv_hooks_call(before_traceset
, self
);
304 nb_trace
= lttv_traceset_number(ts
);
306 for(i
= 0 ; i
< nb_trace
; i
++) {
307 tc
= self
->traces
[i
];
308 lttv_trace_context_add_hooks(tc
,
317 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
318 LttvHooks
*after_traceset
,
319 LttvHooks
*after_trace
,
320 LttvHooks
*after_tracefile
,
322 LttvHooksById
*event_by_id
)
325 LttvTraceset
*ts
= self
->ts
;
329 LttvTraceContext
*tc
;
331 nb_trace
= lttv_traceset_number(ts
);
333 for(i
= 0 ; i
< nb_trace
; i
++) {
334 tc
= self
->traces
[i
];
335 lttv_trace_context_remove_hooks(tc
,
342 lttv_hooks_call(after_traceset
, self
);
347 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
348 LttvHooks
*before_trace
,
349 LttvHooks
*before_tracefile
,
351 LttvHooksById
*event_by_id
)
353 guint i
, nb_tracefile
;
355 LttvTracefileContext
**tfc
;
357 lttv_hooks_call(before_trace
, self
);
359 nb_tracefile
= self
->tracefiles
->len
;
361 for(i
= 0 ; i
< nb_tracefile
; i
++) {
362 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
363 lttv_tracefile_context_add_hooks(*tfc
,
372 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
373 LttvHooks
*after_trace
,
374 LttvHooks
*after_tracefile
,
376 LttvHooksById
*event_by_id
)
378 guint i
, nb_tracefile
;
380 LttvTracefileContext
**tfc
;
382 nb_tracefile
= self
->tracefiles
->len
;
384 for(i
= 0 ; i
< nb_tracefile
; i
++) {
385 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
386 lttv_tracefile_context_remove_hooks(*tfc
,
392 lttv_hooks_call(after_trace
, self
);
395 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
396 LttvHooks
*before_tracefile
,
398 LttvHooksById
*event_by_id
)
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
));
415 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
416 LttvHooks
*after_tracefile
,
418 LttvHooksById
*event_by_id
)
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
);
430 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
434 lttv_hooks_call(after_tracefile
, self
);
439 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext
*tfc
,
441 LttvHooks
*event_by_id
)
444 h
= lttv_hooks_by_id_find(tfc
->event_by_id
, i
);
445 lttv_hooks_add_list(h
, event_by_id
);
448 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext
*tfc
,
451 lttv_hooks_by_id_remove(tfc
->event_by_id
, i
);
454 static LttvTracesetContext
*
455 new_traceset_context(LttvTracesetContext
*self
)
457 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
461 static LttvTraceContext
*
462 new_trace_context(LttvTracesetContext
*self
)
464 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
468 static LttvTracefileContext
*
469 new_tracefile_context(LttvTracesetContext
*self
)
471 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
476 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
478 /* Be careful of anything which would not work well with shallow copies */
483 traceset_context_finalize (LttvTracesetContext
*self
)
485 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
486 ->finalize(G_OBJECT(self
));
491 traceset_context_class_init (LttvTracesetContextClass
*klass
)
493 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
495 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
498 klass
->new_traceset_context
= new_traceset_context
;
499 klass
->new_trace_context
= new_trace_context
;
500 klass
->new_tracefile_context
= new_tracefile_context
;
505 lttv_traceset_context_get_type(void)
507 static GType 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
),
518 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
519 NULL
/* Value handling */
522 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
530 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
532 /* Be careful of anything which would not work well with shallow copies */
537 trace_context_finalize (LttvTraceContext
*self
)
539 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
540 finalize(G_OBJECT(self
));
545 trace_context_class_init (LttvTraceContextClass
*klass
)
547 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
549 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
554 lttv_trace_context_get_type(void)
556 static GType 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
),
567 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
568 NULL
/* Value handling */
571 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
579 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
581 /* Be careful of anything which would not work well with shallow copies */
586 tracefile_context_finalize (LttvTracefileContext
*self
)
588 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
589 ->finalize(G_OBJECT(self
));
594 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
596 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
598 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
603 lttv_tracefile_context_get_type(void)
605 static GType 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
),
616 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
617 NULL
/* Value handling */
620 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
628 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
629 g_assert(key
== value
);
630 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
635 // Test to see if pqueue is traversed in the right order.
636 static LttTime test_time
;
638 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
640 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
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
);
647 if(user_data
!= NULL
) {
648 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
649 g_assert(compare_tracefile(user_data
, value
) == 0);
651 g_assert(compare_tracefile(user_data
, value
) != 0);
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
;
658 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
665 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
666 LttvHooks
*before_traceset
,
667 LttvHooks
*before_trace
,
668 LttvHooks
*before_tracefile
,
670 LttvHooksById
*event_by_id
)
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
,
684 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
686 /* Note : a _middle must be preceded from a _seek or another middle */
687 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
690 const LttvTracesetContextPosition
*end_position
)
692 GTree
*pqueue
= self
->pqueue
;
694 LttvTracefileContext
*tfc
;
702 //enum read_state last_read_state = LAST_NONE;
704 gint last_ret
= 0; /* return value of the last hook list called */
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
713 g_tree_foreach(pqueue
, get_first
, &tfc
);
714 /* End of traceset : tfc is NULL */
715 if(unlikely(tfc
== NULL
))
721 * - the maximum number of events specified?
722 * - the end position ?
724 * then the read is finished. We leave the queue in the same state and
728 if(unlikely(last_ret
== TRUE
||
729 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
730 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
731 end_position
) == 0)||
732 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
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. */
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
);
747 g_tree_remove(pqueue
, tfc
);
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
);
757 e
= ltt_tracefile_get_event(tfc
->tf
);
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) */
764 tfc
->target_pid
= -1; /* unset target PID */
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
);
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
);
779 read_ret
= ltt_tracefile_read(tfc
->tf
);
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
);
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
);
794 //last_read_state = LAST_OK;
796 tfc
->timestamp
= ltt_time_infinite
;
798 if(read_ret
== ERANGE
) {
799 // last_read_state = LAST_EMPTY;
800 g_debug("End of trace");
802 g_error("Error happened in lttv_process_traceset_middle");
808 void lttv_process_traceset_end(LttvTracesetContext
*self
,
809 LttvHooks
*after_traceset
,
810 LttvHooks
*after_trace
,
811 LttvHooks
*after_tracefile
,
813 LttvHooksById
*event_by_id
)
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
,
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.
829 * Don't forget to empty the traceset pqueue before calling this.
831 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
833 guint i
, nb_tracefile
;
837 LttvTracefileContext
**tfc
;
839 nb_tracefile
= self
->tracefiles
->len
;
841 GTree
*pqueue
= self
->ts_context
->pqueue
;
843 for(i
= 0 ; i
< nb_tracefile
; i
++) {
844 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
846 g_tree_remove(pqueue
, *tfc
);
848 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
849 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
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
));
856 (*tfc
)->timestamp
= ltt_time_infinite
;
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
);
871 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
875 LttvTraceContext
*tc
;
877 //g_tree_destroy(self->pqueue);
878 //self->pqueue = g_tree_new(compare_tracefile);
880 nb_trace
= lttv_traceset_number(self
->ts
);
881 for(i
= 0 ; i
< nb_trace
; i
++) {
882 tc
= self
->traces
[i
];
883 lttv_process_trace_seek_time(tc
, start
);
888 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
889 const LttvTracesetContextPosition
*pos
)
892 /* If a position is set, seek the traceset to this position */
893 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
895 /* Test to see if the traces has been added to the trace set :
896 * It should NEVER happen. Clear all positions if a new trace comes in. */
897 /* FIXME I know this test is not optimal : should keep a number of
898 * tracefiles variable in the traceset.. eventually */
899 guint num_traces
= lttv_traceset_number(self
->ts
);
901 for(i
=0; i
<num_traces
;i
++) {
902 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
904 guint num_tracefiles
= tracefiles
->len
;
905 for(j
=0;j
<num_tracefiles
;j
++)
908 g_assert(tf_count
== pos
->tfcp
->len
);
911 //g_tree_destroy(self->pqueue);
912 //self->pqueue = g_tree_new(compare_tracefile);
914 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
915 LttvTracefileContextPosition
*tfcp
=
916 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
918 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
920 if(tfcp
->used
== TRUE
) {
921 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
923 tfcp
->tfc
->timestamp
=
924 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
925 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
926 ltt_time_infinite
) != 0);
927 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
930 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
935 test_time
.tv_sec
= 0;
936 test_time
.tv_nsec
= 0;
937 g_debug("test tree after seek_position");
938 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
947 #if 0 // pmf: temporary disable
949 find_field(LttEventType
*et
, const GQuark field
)
953 if(field
== 0) return NULL
;
955 f
= ltt_eventtype_field_by_name(et
, field
);
957 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
958 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
959 g_quark_to_string(ltt_eventtype_name(et
)));
966 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
968 return marker_get_info_from_id(t
, th
->id
);
972 int lttv_trace_find_hook(LttTrace
*t
, GQuark marker_name
,
973 GQuark fields
[], LttvHook h
, gpointer hook_data
, GArray
**trace_hooks
)
975 struct marker_info
*info
;
976 struct marker_field
*field
;
980 info
= marker_get_info_from_name(t
, marker_name
);
981 if(unlikely(info
== NULL
)) {
985 init_array_size
= (*trace_hooks
)->len
;
987 /* for each marker with the requested name */
993 marker_id
= marker_get_id_from_info(t
, info
);
996 tmpth
.id
= marker_id
;
997 tmpth
.hook_data
= hook_data
;
998 tmpth
.fields
= g_ptr_array_new();
1000 /* for each field requested */
1001 for(f
= fields
; f
&& *f
!= 0; f
++) {
1003 for_each_marker_field(marker_field
, info
) {
1004 if(marker_fieldfield
->name
== *f
) {
1006 g_ptr_array_add(tmpth
.fields
, marker_field
);
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
));
1020 /* all fields were found: add the tracehook to the array */
1021 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1024 } while(info
!= NULL
);
1026 /* Error if no new trace hook has been added */
1027 return (init_array_size
== (*trace_hooks
)->len
);
1030 void lttv_trace_hook_remove_all(GArray
**th
)
1033 for(i
=0; i
<th
->len
; i
++) {
1034 g_ptr_array_free(g_array_index(th
, LttvTraceHook
, i
).fields
, TRUE
);
1036 *th
= g_array_remove_range(*th
, 0, th
->len
);
1039 LttvTracesetContextPosition
*lttv_traceset_context_position_new(
1040 const LttvTracesetContext
*self
)
1042 guint num_traces
= lttv_traceset_number(self
->ts
);
1046 for(i
=0; i
<num_traces
;i
++) {
1047 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1049 guint num_tracefiles
= tracefiles
->len
;
1050 for(j
=0;j
<num_tracefiles
;j
++)
1053 LttvTracesetContextPosition
*pos
=
1054 g_new(LttvTracesetContextPosition
, 1);
1055 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1056 sizeof(LttvTracefileContextPosition
),
1058 g_array_set_size(pos
->tfcp
, tf_count
);
1059 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1060 LttvTracefileContextPosition
*tfcp
=
1061 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1062 tfcp
->event
= ltt_event_position_new();
1065 pos
->timestamp
= ltt_time_infinite
;
1069 /* Save all positions, the ones with infinite time will have NULL
1071 /* note : a position must be destroyed when a trace is added/removed from a
1073 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1074 LttvTracesetContextPosition
*pos
)
1077 guint num_traces
= lttv_traceset_number(self
->ts
);
1080 pos
->timestamp
= ltt_time_infinite
;
1082 for(i
=0; i
<num_traces
;i
++) {
1083 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1085 guint num_tracefiles
= tracefiles
->len
;
1087 for(j
=0;j
<num_tracefiles
;j
++) {
1088 g_assert(tf_count
< pos
->tfcp
->len
);
1089 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1090 LttvTracefileContext
*, j
);
1091 LttvTracefileContextPosition
*tfcp
=
1092 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1096 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1097 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1098 ltt_event_position(event
, tfcp
->event
);
1099 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1100 pos
->timestamp
= (*tfc
)->timestamp
;
1106 //g_array_append_val(pos->tfc, *tfc);
1107 //g_array_append_val(pos->ep, ep);
1114 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1118 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1119 LttvTracefileContextPosition
*tfcp
=
1120 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1121 g_free(tfcp
->event
);
1125 g_array_free(pos
->tfcp
, TRUE
);
1129 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1130 const LttvTracesetContextPosition
*src
)
1133 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1135 g_assert(src
->tfcp
->len
== src
->tfcp
->len
);
1137 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1139 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1141 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1143 dest_tfcp
->used
= src_tfcp
->used
;
1144 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1146 if(src_tfcp
->used
) {
1147 ltt_event_position_copy(
1152 dest
->timestamp
= src
->timestamp
;
1155 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1156 const LttvTracesetContextPosition
*pos
)
1161 if(pos
->tfcp
->len
== 0) {
1162 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1165 if(lttv_traceset_number(self
->ts
) == 0)
1168 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1169 LttvTracefileContextPosition
*tfcp
=
1170 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1172 if(tfcp
->used
== FALSE
) {
1173 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1177 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1180 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1182 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1186 if(ret
!= 0) return ret
;
1193 gint
lttv_traceset_context_pos_pos_compare(
1194 const LttvTracesetContextPosition
*pos1
,
1195 const LttvTracesetContextPosition
*pos2
)
1200 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1201 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1206 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1209 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1210 LttvTracefileContextPosition
*tfcp1
=
1211 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1213 if(tfcp1
->used
== TRUE
) {
1214 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1215 LttvTracefileContextPosition
*tfcp2
=
1216 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1218 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1219 if(tfcp2
->used
== TRUE
)
1220 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1224 if(ret
!= 0) return ret
;
1229 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1230 LttvTracefileContextPosition
*tfcp2
=
1231 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1233 if(tfcp1
->tfc
== tfcp2
->tfc
)
1234 if(tfcp2
->used
== TRUE
) ret
= 1;
1235 if(ret
!= 0) return ret
;
1243 LttTime
lttv_traceset_context_position_get_time(
1244 const LttvTracesetContextPosition
*pos
)
1246 return pos
->timestamp
;
1250 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1252 GTree
*pqueue
= self
->pqueue
;
1253 LttvTracefileContext
*tfc
= NULL
;
1255 g_tree_foreach(pqueue
, get_first
, &tfc
);
1260 /* lttv_process_traceset_synchronize_tracefiles
1262 * Use the sync_position field of the trace set context to synchronize each
1263 * tracefile with the previously saved position.
1265 * If no previous position has been saved, it simply does nothing.
1267 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1269 g_assert(lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
) == 0);
1275 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1277 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1280 struct seek_back_data
{
1281 guint first_event
; /* Index of the first event in the array : we will always
1282 overwrite at this position : this is a circular array.
1285 guint n
; /* number of events requested */
1286 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1287 LttvFilter
*filter1
;
1288 LttvFilter
*filter2
;
1289 LttvFilter
*filter3
;
1291 check_handler
*check
;
1292 gboolean
*stop_flag
;
1293 guint raw_event_count
;
1296 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1298 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1299 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1300 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1301 LttvTracesetContextPosition
*pos
;
1303 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1305 sd
->raw_event_count
++;
1307 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1308 !lttv_filter_tree_parse(sd
->filter1
->head
,
1309 ltt_tracefile_get_event(tfc
->tf
),
1315 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1316 !lttv_filter_tree_parse(sd
->filter2
->head
,
1317 ltt_tracefile_get_event(tfc
->tf
),
1323 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1324 !lttv_filter_tree_parse(sd
->filter3
->head
,
1325 ltt_tracefile_get_event(tfc
->tf
),
1332 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1335 lttv_traceset_context_position_save(tsc
, pos
);
1337 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1338 else sd
->first_event
++;
1340 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1345 /* Seek back n events back from the current position.
1348 * @self The trace set context
1349 * @n number of events to jump over
1350 * @first_offset The initial offset value used.
1351 * never put first_offset at ltt_time_zero.
1352 * @time_seeker Function pointer of the function to use to seek time :
1353 * either lttv_process_traceset_seek_time
1354 * or lttv_state_traceset_seek_time_closest
1355 * @filter The filter to call.
1357 * Return value : the number of events found (might be lower than the number
1358 * requested if beginning of traceset is reached).
1360 * The first search will go back first_offset and try to find the last n events
1361 * matching the filter. If there are not enough, it will try to go back from the
1362 * new trace point from first_offset*2, and so on, until beginning of trace or n
1365 * Note : this function does not take in account the LttvFilter : use the
1366 * similar function found in state.c instead.
1368 * Note2 : the caller must make sure that the LttvTracesetContext does not
1369 * contain any hook, as process_traceset_middle is used in this routine.
1371 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1372 guint n
, LttTime first_offset
,
1373 seek_time_fct time_seeker
,
1374 check_handler
*check
,
1375 gboolean
*stop_flag
,
1376 LttvFilter
*filter1
,
1377 LttvFilter
*filter2
,
1378 LttvFilter
*filter3
,
1381 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1382 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1385 LttvTracesetContextPosition
*next_iter_end_pos
=
1386 lttv_traceset_context_position_new(self
);
1387 LttvTracesetContextPosition
*end_pos
=
1388 lttv_traceset_context_position_new(self
);
1389 LttvTracesetContextPosition
*saved_pos
=
1390 lttv_traceset_context_position_new(self
);
1393 LttTime time_offset
;
1394 struct seek_back_data sd
;
1395 LttvHooks
*hooks
= lttv_hooks_new();
1398 sd
.events_found
= 0;
1399 sd
.array
= g_ptr_array_sized_new(n
);
1400 sd
.filter1
= filter1
;
1401 sd
.filter2
= filter2
;
1402 sd
.filter3
= filter3
;
1406 sd
.stop_flag
= stop_flag
;
1407 sd
.raw_event_count
= 0;
1408 g_ptr_array_set_size(sd
.array
, n
);
1410 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1413 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1414 lttv_traceset_context_position_save(self
, saved_pos
);
1415 /* Get the current time from which we will offset */
1416 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1417 /* the position saved might be end of traceset... */
1418 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1419 time
= self
->time_span
.end_time
;
1422 time_offset
= first_offset
;
1424 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1426 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1429 /* stop criteria : - n events found
1430 * - asked_time < beginning of trace */
1431 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) < 0) break;
1433 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1435 /* We must seek the traceset back to time - time_offset */
1436 /* this time becomes the new reference time */
1437 time
= ltt_time_sub(time
, time_offset
);
1440 time_seeker(self
, time
);
1441 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1442 /* Resync the time in case of a seek_closest */
1443 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1444 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1445 time
= self
->time_span
.end_time
;
1448 /* Process the traceset, calling a hook which adds events
1449 * to the array, overwriting the tail. It changes first_event and
1450 * events_found too. */
1451 /* We would like to have a clean context here : no other hook than our's */
1453 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1454 G_MAXUINT
, end_pos
);
1456 if(sd
.events_found
< n
) {
1457 if(sd
.first_event
> 0) {
1458 /* Save the first position */
1459 LttvTracesetContextPosition
*pos
=
1460 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1461 lttv_traceset_context_position_copy(saved_pos
, pos
);
1463 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1464 /* Change array size to n - events_found */
1465 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1466 LttvTracesetContextPosition
*pos
=
1467 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1468 lttv_traceset_context_position_destroy(pos
);
1470 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1473 } else break; /* Second end criterion : n events found */
1475 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1478 lttv_traceset_context_position_destroy(end_pos
);
1479 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1481 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1483 if(sd
.events_found
>= n
) {
1484 /* Seek the traceset to the first event in the circular array */
1485 LttvTracesetContextPosition
*pos
=
1486 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1488 g_assert(lttv_process_traceset_seek_position(self
, pos
) == 0);
1490 /* Will seek to the last saved position : in the worst case, it will be the
1491 * original position (if events_found is 0) */
1492 g_assert(lttv_process_traceset_seek_position(self
, saved_pos
) == 0);
1495 for(i
=0;i
<sd
.array
->len
;i
++) {
1496 LttvTracesetContextPosition
*pos
=
1497 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1498 lttv_traceset_context_position_destroy(pos
);
1500 g_ptr_array_free(sd
.array
, TRUE
);
1502 lttv_hooks_destroy(hooks
);
1504 lttv_traceset_context_position_destroy(saved_pos
);
1506 return sd
.events_found
;
1510 struct seek_forward_data
{
1511 guint event_count
; /* event counter */
1512 guint n
; /* requested number of events to jump over */
1513 LttvFilter
*filter1
;
1514 LttvFilter
*filter2
;
1515 LttvFilter
*filter3
;
1517 check_handler
*check
;
1518 gboolean
*stop_flag
;
1519 guint raw_event_count
; /* event counter */
1522 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1524 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1525 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1527 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1529 sd
->raw_event_count
++;
1531 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1532 !lttv_filter_tree_parse(sd
->filter1
->head
,
1533 ltt_tracefile_get_event(tfc
->tf
),
1539 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1540 !lttv_filter_tree_parse(sd
->filter2
->head
,
1541 ltt_tracefile_get_event(tfc
->tf
),
1547 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1548 !lttv_filter_tree_parse(sd
->filter3
->head
,
1549 ltt_tracefile_get_event(tfc
->tf
),
1557 if(sd
->event_count
>= sd
->n
)
1561 /* Seek back n events forward from the current position (1 to n)
1562 * 0 is ok too, but it will actually do nothing.
1565 * @self the trace set context
1566 * @n number of events to jump over
1567 * @filter filter to call.
1569 * returns : the number of events jumped over (may be less than requested if end
1570 * of traceset reached) */
1571 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1573 check_handler
*check
,
1574 gboolean
*stop_flag
,
1575 LttvFilter
*filter1
,
1576 LttvFilter
*filter2
,
1577 LttvFilter
*filter3
,
1580 struct seek_forward_data sd
;
1583 sd
.filter1
= filter1
;
1584 sd
.filter2
= filter2
;
1585 sd
.filter3
= filter3
;
1588 sd
.stop_flag
= stop_flag
;
1589 sd
.raw_event_count
= 0;
1591 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1593 LttvHooks
*hooks
= lttv_hooks_new();
1595 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1597 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1599 /* it will end on the end of traceset, or the fact that the
1600 * hook returns TRUE.
1602 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1605 /* Here, our position is either the end of traceset, or the exact position
1606 * after n events : leave it like this. This might be placed on an event that
1607 * will be filtered out, we don't care : all we know is that the following
1608 * event filtered in will be the right one. */
1610 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1612 lttv_hooks_destroy(hooks
);
1614 return sd
.event_count
;