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 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
35 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
36 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
38 if(likely(trace_a
!= trace_b
)) {
39 comparison
= ltt_time_compare(trace_a
->timestamp
, trace_b
->timestamp
);
40 if(unlikely(comparison
== 0)) {
41 if(trace_a
->index
< trace_b
->index
) comparison
= -1;
42 else if(trace_a
->index
> trace_b
->index
) comparison
= 1;
43 else if(trace_a
->t_context
->index
< trace_b
->t_context
->index
)
45 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
52 typedef struct _LttvTracefileContextPosition
{
53 LttEventPosition
*event
;
54 LttvTracefileContext
*tfc
;
55 gboolean used
; /* Tells if the tfc is at end of traceset position */
56 } LttvTracefileContextPosition
;
59 struct _LttvTracesetContextPosition
{
60 GArray
*tfcp
; /* Array of LttvTracefileContextPosition */
61 LttTime timestamp
; /* Current time at the saved position */
62 /* If ltt_time_infinite : no position is
63 * set, else, a position is set (may be end
64 * of trace, with ep->len == 0) */
67 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
69 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
73 void lttv_context_fini(LttvTracesetContext
*self
)
75 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
80 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
82 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
89 lttv_context_new_trace_context(LttvTracesetContext
*self
)
91 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
95 LttvTracefileContext
*
96 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
98 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
101 /****************************************************************************
102 * lttv_traceset_context_compute_time_span
104 * Keep the time span in sync with on the fly addition and removal of traces
105 * in a trace set. It must be called each time a trace is added/removed from
106 * the traceset. It could be more efficient to call it only once a bunch
107 * of traces are loaded, but the calculation is not long, so it's not
110 * Author : Xang Xiu Yang
111 ***************************************************************************/
112 static void lttv_traceset_context_compute_time_span(
113 LttvTracesetContext
*self
,
114 TimeInterval
*time_span
)
116 LttvTraceset
* traceset
= self
->ts
;
117 int numTraces
= lttv_traceset_number(traceset
);
120 LttvTraceContext
*tc
;
123 time_span
->start_time
.tv_sec
= 0;
124 time_span
->start_time
.tv_nsec
= 0;
125 time_span
->end_time
.tv_sec
= 0;
126 time_span
->end_time
.tv_nsec
= 0;
128 for(i
=0; i
<numTraces
;i
++){
129 tc
= self
->traces
[i
];
132 ltt_trace_time_span_get(trace
, &s
, &e
);
133 tc
->time_span
.start_time
= s
;
134 tc
->time_span
.end_time
= e
;
137 time_span
->start_time
= s
;
138 time_span
->end_time
= e
;
140 if(s
.tv_sec
< time_span
->start_time
.tv_sec
141 || (s
.tv_sec
== time_span
->start_time
.tv_sec
142 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
143 time_span
->start_time
= s
;
144 if(e
.tv_sec
> time_span
->end_time
.tv_sec
145 || (e
.tv_sec
== time_span
->end_time
.tv_sec
146 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
147 time_span
->end_time
= e
;
152 static void init_tracefile_context(LttTracefile
*tracefile
,
153 LttvTraceContext
*tc
)
155 LttvTracefileContext
*tfc
;
156 LttvTracesetContext
*tsc
= tc
->ts_context
;
158 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
160 tfc
->index
= tc
->tracefiles
->len
;
161 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
166 tfc
->event
= lttv_hooks_new();
167 tfc
->event_by_id
= lttv_hooks_by_id_new();
168 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
169 tfc
->target_pid
= -1;
174 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
178 LttvTraceContext
*tc
;
180 GData
**tracefiles_groups
;
182 struct compute_tracefile_group_args args
;
184 nb_trace
= lttv_traceset_number(ts
);
186 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
187 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
188 self
->ts_a
= lttv_traceset_attribute(ts
);
189 for(i
= 0 ; i
< nb_trace
; i
++) {
190 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
191 self
->traces
[i
] = tc
;
193 tc
->ts_context
= self
;
195 tc
->vt
= lttv_traceset_get(ts
, i
);
196 tc
->t
= lttv_trace(tc
->vt
);
197 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
198 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
199 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
200 sizeof(LttvTracefileContext
*), 10);
202 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
203 if(tracefiles_groups
!= NULL
) {
204 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
207 g_datalist_foreach(tracefiles_groups
,
208 (GDataForeachFunc
)compute_tracefile_group
,
213 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
214 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
215 nb_tracefile
= nb_control
+ nb_per_cpu
;
216 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
218 for(j
= 0 ; j
< nb_tracefile
; j
++) {
219 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
220 tc
->tracefiles
[j
] = tfc
;
225 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
228 tfc
->control
= FALSE
;
229 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
233 tfc
->e
= ltt_event_new();
234 tfc
->event
= lttv_hooks_new();
235 tfc
->event_by_id
= lttv_hooks_by_id_new();
236 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
241 self
->sync_position
= lttv_traceset_context_position_new(self
);
242 self
->pqueue
= g_tree_new(compare_tracefile
);
243 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
244 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
249 void fini(LttvTracesetContext
*self
)
251 guint i
, j
, nb_trace
, nb_tracefile
;
253 LttvTraceContext
*tc
;
255 LttvTracefileContext
**tfc
;
257 LttvTraceset
*ts
= self
->ts
;
259 g_tree_destroy(self
->pqueue
);
260 g_object_unref(self
->a
);
261 lttv_traceset_context_position_destroy(self
->sync_position
);
263 nb_trace
= lttv_traceset_number(ts
);
265 for(i
= 0 ; i
< nb_trace
; i
++) {
266 tc
= self
->traces
[i
];
268 g_object_unref(tc
->a
);
270 nb_tracefile
= tc
->tracefiles
->len
;
272 for(j
= 0 ; j
< nb_tracefile
; j
++) {
273 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
274 lttv_hooks_destroy((*tfc
)->event
);
275 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
276 g_object_unref((*tfc
)->a
);
277 g_object_unref(*tfc
);
279 g_array_free(tc
->tracefiles
, TRUE
);
282 g_free(self
->traces
);
286 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
287 LttvHooks
*before_traceset
,
288 LttvHooks
*before_trace
,
289 LttvHooks
*before_tracefile
,
291 LttvHooksByIdChannelArray
*event_by_id_channel
)
293 LttvTraceset
*ts
= self
->ts
;
297 LttvTraceContext
*tc
;
299 lttv_hooks_call(before_traceset
, self
);
301 nb_trace
= lttv_traceset_number(ts
);
303 for(i
= 0 ; i
< nb_trace
; i
++) {
304 tc
= self
->traces
[i
];
305 lttv_trace_context_add_hooks(tc
,
309 event_by_id_channel
);
314 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
315 LttvHooks
*after_traceset
,
316 LttvHooks
*after_trace
,
317 LttvHooks
*after_tracefile
,
319 LttvHooksByIdChannelArray
*event_by_id_channel
)
322 LttvTraceset
*ts
= self
->ts
;
326 LttvTraceContext
*tc
;
328 nb_trace
= lttv_traceset_number(ts
);
330 for(i
= 0 ; i
< nb_trace
; i
++) {
331 tc
= self
->traces
[i
];
332 lttv_trace_context_remove_hooks(tc
,
336 event_by_id_channel
);
339 lttv_hooks_call(after_traceset
, self
);
344 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
345 LttvHooks
*before_trace
,
346 LttvHooks
*before_tracefile
,
348 LttvHooksByIdChannelArray
*event_by_id_channel
)
350 guint i
, j
, nb_tracefile
;
351 LttvTracefileContext
**tfc
;
354 lttv_hooks_call(before_trace
, self
);
356 nb_tracefile
= self
->tracefiles
->len
;
358 for(i
= 0 ; i
< nb_tracefile
; i
++) {
359 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
361 lttv_tracefile_context_add_hooks(*tfc
,
365 if (event_by_id_channel
) {
366 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
367 LttvHooksByIdChannel
*hooks
= &g_array_index(event_by_id_channel
->array
,
368 LttvHooksByIdChannel
, j
);
369 if (tf
->name
== hooks
->channel
)
370 lttv_tracefile_context_add_hooks(*tfc
,
381 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
382 LttvHooks
*after_trace
,
383 LttvHooks
*after_tracefile
,
385 LttvHooksByIdChannelArray
*event_by_id_channel
)
387 guint i
, j
, nb_tracefile
;
388 LttvTracefileContext
**tfc
;
391 nb_tracefile
= self
->tracefiles
->len
;
393 for(i
= 0 ; i
< nb_tracefile
; i
++) {
394 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
396 if (event_by_id_channel
) {
397 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
398 LttvHooksByIdChannel
*hooks
= &g_array_index(event_by_id_channel
->array
,
399 LttvHooksByIdChannel
, j
);
400 if (tf
->name
== hooks
->channel
)
401 lttv_tracefile_context_remove_hooks(*tfc
,
407 lttv_tracefile_context_remove_hooks(*tfc
,
414 lttv_hooks_call(after_trace
, self
);
417 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
418 LttvHooks
*before_tracefile
,
420 LttvHooksById
*event_by_id
)
425 lttv_hooks_call(before_tracefile
, self
);
426 lttv_hooks_add_list(self
->event
, event
);
427 if(event_by_id
!= NULL
) {
428 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
429 index
= g_array_index(event_by_id
->array
, guint
, i
);
430 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
431 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
436 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
437 LttvHooks
*after_tracefile
,
439 LttvHooksById
*event_by_id
)
445 lttv_hooks_remove_list(self
->event
, event
);
446 if(event_by_id
!= NULL
) {
447 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
448 index
= g_array_index(event_by_id
->array
, guint
, i
);
449 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
451 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
455 lttv_hooks_call(after_tracefile
, self
);
458 static LttvTracesetContext
*
459 new_traceset_context(LttvTracesetContext
*self
)
461 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
465 static LttvTraceContext
*
466 new_trace_context(LttvTracesetContext
*self
)
468 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
472 static LttvTracefileContext
*
473 new_tracefile_context(LttvTracesetContext
*self
)
475 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
480 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
482 /* Be careful of anything which would not work well with shallow copies */
487 traceset_context_finalize (LttvTracesetContext
*self
)
489 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
490 ->finalize(G_OBJECT(self
));
495 traceset_context_class_init (LttvTracesetContextClass
*klass
)
497 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
499 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
502 klass
->new_traceset_context
= new_traceset_context
;
503 klass
->new_trace_context
= new_trace_context
;
504 klass
->new_tracefile_context
= new_tracefile_context
;
509 lttv_traceset_context_get_type(void)
511 static GType type
= 0;
513 static const GTypeInfo info
= {
514 sizeof (LttvTracesetContextClass
),
515 NULL
, /* base_init */
516 NULL
, /* base_finalize */
517 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
518 NULL
, /* class_finalize */
519 NULL
, /* class_data */
520 sizeof (LttvTracesetContext
),
522 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
523 NULL
/* Value handling */
526 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
534 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
536 /* Be careful of anything which would not work well with shallow copies */
541 trace_context_finalize (LttvTraceContext
*self
)
543 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
544 finalize(G_OBJECT(self
));
549 trace_context_class_init (LttvTraceContextClass
*klass
)
551 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
553 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
558 lttv_trace_context_get_type(void)
560 static GType type
= 0;
562 static const GTypeInfo info
= {
563 sizeof (LttvTraceContextClass
),
564 NULL
, /* base_init */
565 NULL
, /* base_finalize */
566 (GClassInitFunc
) trace_context_class_init
, /* class_init */
567 NULL
, /* class_finalize */
568 NULL
, /* class_data */
569 sizeof (LttvTraceContext
),
571 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
572 NULL
/* Value handling */
575 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
583 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
585 /* Be careful of anything which would not work well with shallow copies */
590 tracefile_context_finalize (LttvTracefileContext
*self
)
592 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
593 ->finalize(G_OBJECT(self
));
598 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
600 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
602 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
607 lttv_tracefile_context_get_type(void)
609 static GType type
= 0;
611 static const GTypeInfo info
= {
612 sizeof (LttvTracefileContextClass
),
613 NULL
, /* base_init */
614 NULL
, /* base_finalize */
615 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
616 NULL
, /* class_finalize */
617 NULL
, /* class_data */
618 sizeof (LttvTracefileContext
),
620 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
621 NULL
/* Value handling */
624 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
632 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
633 g_assert(key
== value
);
634 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
639 // Test to see if pqueue is traversed in the right order.
640 static LttTime test_time
;
642 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
644 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
646 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
647 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
648 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
649 tfc
->index
, tfc
->t_context
->index
);
651 if(user_data
!= NULL
) {
652 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
653 g_assert(compare_tracefile(user_data
, value
) == 0);
655 g_assert(compare_tracefile(user_data
, value
) != 0);
657 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
658 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
659 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
662 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
669 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
670 LttvHooks
*before_traceset
,
671 LttvHooks
*before_trace
,
672 LttvHooks
*before_tracefile
,
674 LttvHooksByIdChannelArray
*event_by_id_channel
)
677 /* simply add hooks in context. _before hooks are called by add_hooks. */
678 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
679 lttv_traceset_context_add_hooks(self
,
684 event_by_id_channel
);
688 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
690 /* Note : a _middle must be preceded from a _seek or another middle */
691 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
694 const LttvTracesetContextPosition
*end_position
)
696 GTree
*pqueue
= self
->pqueue
;
698 LttvTracefileContext
*tfc
;
706 //enum read_state last_read_state = LAST_NONE;
708 gint last_ret
= 0; /* return value of the last hook list called */
710 /* Get the next event from the pqueue, call its hooks,
711 reinsert in the pqueue the following event from the same tracefile
712 unless the tracefile is finished or the event is later than the
717 g_tree_foreach(pqueue
, get_first
, &tfc
);
718 /* End of traceset : tfc is NULL */
719 if(unlikely(tfc
== NULL
))
725 * - the maximum number of events specified?
726 * - the end position ?
728 * then the read is finished. We leave the queue in the same state and
732 if(unlikely(last_ret
== TRUE
||
733 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
734 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
735 end_position
) == 0)||
736 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
741 /* Get the tracefile with an event for the smallest time found. If two
742 or more tracefiles have events for the same time, hope that lookup
743 and remove are consistent. */
746 test_time
.tv_sec
= 0;
747 test_time
.tv_nsec
= 0;
748 g_debug("test tree before remove");
749 g_tree_foreach(pqueue
, test_tree
, tfc
);
751 g_tree_remove(pqueue
, tfc
);
754 test_time
.tv_sec
= 0;
755 test_time
.tv_nsec
= 0;
756 g_debug("test tree after remove");
757 g_tree_foreach(pqueue
, test_tree
, tfc
);
761 e
= ltt_tracefile_get_event(tfc
->tf
);
763 //if(last_read_state != LAST_EMPTY) {
764 /* Only call hooks if the last read has given an event or if we are at the
765 * first pass (not if last read returned end of tracefile) */
768 tfc
->target_pid
= -1; /* unset target PID */
770 * return values : 0 : continue read, 1 : go to next position and stop read,
771 * 2 : stay at the current position and stop read */
772 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
773 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
776 /* This is buggy : it won't work well with state computation */
777 if(unlikely(last_ret
== 2)) {
778 /* This is a case where we want to stay at this position and stop read. */
779 g_tree_insert(pqueue
, tfc
, tfc
);
783 read_ret
= ltt_tracefile_read(tfc
->tf
);
786 if(likely(!read_ret
)) {
787 //g_debug("An event is ready");
788 tfc
->timestamp
= ltt_event_time(e
);
789 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
790 g_tree_insert(pqueue
, tfc
, tfc
);
792 test_time
.tv_sec
= 0;
793 test_time
.tv_nsec
= 0;
794 g_debug("test tree after event ready");
795 g_tree_foreach(pqueue
, test_tree
, NULL
);
798 //last_read_state = LAST_OK;
800 tfc
->timestamp
= ltt_time_infinite
;
802 if(read_ret
== ERANGE
) {
803 // last_read_state = LAST_EMPTY;
804 g_debug("End of trace");
806 g_error("Error happened in lttv_process_traceset_middle");
812 void lttv_process_traceset_end(LttvTracesetContext
*self
,
813 LttvHooks
*after_traceset
,
814 LttvHooks
*after_trace
,
815 LttvHooks
*after_tracefile
,
817 LttvHooksByIdChannelArray
*event_by_id_channel
)
819 /* Remove hooks from context. _after hooks are called by remove_hooks. */
820 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
821 lttv_traceset_context_remove_hooks(self
,
826 event_by_id_channel
);
829 /* Subtile modification :
830 * if tracefile has no event at or after the time requested, it is not put in
831 * the queue, as the next read would fail.
833 * Don't forget to empty the traceset pqueue before calling this.
835 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
837 guint i
, nb_tracefile
;
841 LttvTracefileContext
**tfc
;
843 nb_tracefile
= self
->tracefiles
->len
;
845 GTree
*pqueue
= self
->ts_context
->pqueue
;
847 for(i
= 0 ; i
< nb_tracefile
; i
++) {
848 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
850 g_tree_remove(pqueue
, *tfc
);
852 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
853 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
855 if(ret
== 0) { /* not ERANGE especially */
856 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
857 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
858 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
860 (*tfc
)->timestamp
= ltt_time_infinite
;
864 test_time
.tv_sec
= 0;
865 test_time
.tv_nsec
= 0;
866 g_debug("test tree after seek_time");
867 g_tree_foreach(pqueue
, test_tree
, NULL
);
872 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
876 LttvTraceContext
*tc
;
878 //g_tree_destroy(self->pqueue);
879 //self->pqueue = g_tree_new(compare_tracefile);
881 nb_trace
= lttv_traceset_number(self
->ts
);
882 for(i
= 0 ; i
< nb_trace
; i
++) {
883 tc
= self
->traces
[i
];
884 lttv_process_trace_seek_time(tc
, start
);
889 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
890 const LttvTracesetContextPosition
*pos
)
893 /* If a position is set, seek the traceset to this position */
894 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
896 /* Test to see if the traces has been added to the trace set :
897 * It should NEVER happen. Clear all positions if a new trace comes in. */
898 /* FIXME I know this test is not optimal : should keep a number of
899 * tracefiles variable in the traceset.. eventually */
900 guint num_traces
= lttv_traceset_number(self
->ts
);
902 for(i
=0; i
<num_traces
;i
++) {
903 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
905 guint num_tracefiles
= tracefiles
->len
;
906 for(j
=0;j
<num_tracefiles
;j
++)
909 g_assert(tf_count
== pos
->tfcp
->len
);
912 //g_tree_destroy(self->pqueue);
913 //self->pqueue = g_tree_new(compare_tracefile);
915 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
916 LttvTracefileContextPosition
*tfcp
=
917 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
919 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
921 if(tfcp
->used
== TRUE
) {
922 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
924 tfcp
->tfc
->timestamp
=
925 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
926 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
927 ltt_time_infinite
) != 0);
928 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
931 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
936 test_time
.tv_sec
= 0;
937 test_time
.tv_nsec
= 0;
938 g_debug("test tree after seek_position");
939 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
948 #if 0 // pmf: temporary disable
950 find_field(LttEventType
*et
, const GQuark field
)
954 if(field
== 0) return NULL
;
956 f
= ltt_eventtype_field_by_name(et
, field
);
958 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
959 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
960 g_quark_to_string(ltt_eventtype_name(et
)));
967 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
969 return marker_get_info_from_id(th
->mdata
, th
->id
);
972 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
973 GQuark fields
[], LttvHook h
, gpointer hook_data
, GArray
**trace_hooks
)
975 struct marker_info
*info
;
979 struct marker_data
*mdata
;
981 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
982 if (unlikely(!group
|| group
->len
== 0)) {
983 g_info("No channel for marker named %s.%s found",
984 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
988 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
989 info
= marker_get_info_from_name(mdata
, event_name
);
990 if(unlikely(info
== NULL
)) {
991 g_info("No marker named %s.%s found",
992 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
996 init_array_size
= (*trace_hooks
)->len
;
998 /* for each marker with the requested name */
1000 LttvTraceHook tmpth
;
1003 struct marker_field
*marker_field
;
1005 marker_id
= marker_get_id_from_info(mdata
, info
);
1008 tmpth
.mdata
= mdata
;
1009 tmpth
.channel
= channel_name
;
1010 tmpth
.id
= marker_id
;
1011 tmpth
.hook_data
= hook_data
;
1012 tmpth
.fields
= g_ptr_array_new();
1014 /* for each field requested */
1015 for(f
= fields
; f
&& *f
!= 0; f
++) {
1017 for_each_marker_field(marker_field
, info
) {
1018 if(marker_field
->name
== *f
) {
1020 g_ptr_array_add(tmpth
.fields
, marker_field
);
1025 /* Did not find the one of the fields in this instance of the
1026 marker. Print a warning and skip this marker completely.
1027 Still iterate on other markers with same name. */
1028 g_ptr_array_free(tmpth
.fields
, TRUE
);
1029 g_info("Field %s cannot be found in marker %s.%s",
1030 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1031 g_quark_to_string(event_name
));
1035 /* all fields were found: add the tracehook to the array */
1036 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1039 } while(info
!= NULL
);
1041 /* Error if no new trace hook has been added */
1042 if (init_array_size
== (*trace_hooks
)->len
) {
1043 g_info("No marker of name %s.%s has all requested fields",
1044 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1050 void lttv_trace_hook_remove_all(GArray
**th
)
1053 for(i
=0; i
<(*th
)->len
; i
++) {
1054 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1057 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1060 LttvTracesetContextPosition
*lttv_traceset_context_position_new(
1061 const LttvTracesetContext
*self
)
1063 guint num_traces
= lttv_traceset_number(self
->ts
);
1067 for(i
=0; i
<num_traces
;i
++) {
1068 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1070 guint num_tracefiles
= tracefiles
->len
;
1071 for(j
=0;j
<num_tracefiles
;j
++)
1074 LttvTracesetContextPosition
*pos
=
1075 g_new(LttvTracesetContextPosition
, 1);
1076 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1077 sizeof(LttvTracefileContextPosition
),
1079 g_array_set_size(pos
->tfcp
, tf_count
);
1080 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1081 LttvTracefileContextPosition
*tfcp
=
1082 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1083 tfcp
->event
= ltt_event_position_new();
1086 pos
->timestamp
= ltt_time_infinite
;
1090 /* Save all positions, the ones with infinite time will have NULL
1092 /* note : a position must be destroyed when a trace is added/removed from a
1094 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1095 LttvTracesetContextPosition
*pos
)
1098 guint num_traces
= lttv_traceset_number(self
->ts
);
1101 pos
->timestamp
= ltt_time_infinite
;
1103 for(i
=0; i
<num_traces
;i
++) {
1104 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1106 guint num_tracefiles
= tracefiles
->len
;
1108 for(j
=0;j
<num_tracefiles
;j
++) {
1109 g_assert(tf_count
< pos
->tfcp
->len
);
1110 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1111 LttvTracefileContext
*, j
);
1112 LttvTracefileContextPosition
*tfcp
=
1113 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1117 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1118 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1119 ltt_event_position(event
, tfcp
->event
);
1120 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1121 pos
->timestamp
= (*tfc
)->timestamp
;
1127 //g_array_append_val(pos->tfc, *tfc);
1128 //g_array_append_val(pos->ep, ep);
1135 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1139 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1140 LttvTracefileContextPosition
*tfcp
=
1141 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1142 g_free(tfcp
->event
);
1146 g_array_free(pos
->tfcp
, TRUE
);
1150 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1151 const LttvTracesetContextPosition
*src
)
1154 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1156 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1158 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1160 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1162 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1164 dest_tfcp
->used
= src_tfcp
->used
;
1165 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1167 if(src_tfcp
->used
) {
1168 ltt_event_position_copy(
1173 dest
->timestamp
= src
->timestamp
;
1176 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1177 const LttvTracesetContextPosition
*pos
)
1182 if(pos
->tfcp
->len
== 0) {
1183 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1186 if(lttv_traceset_number(self
->ts
) == 0)
1189 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1190 LttvTracefileContextPosition
*tfcp
=
1191 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1193 if(tfcp
->used
== FALSE
) {
1194 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1198 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1201 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1203 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1207 if(ret
!= 0) return ret
;
1214 gint
lttv_traceset_context_pos_pos_compare(
1215 const LttvTracesetContextPosition
*pos1
,
1216 const LttvTracesetContextPosition
*pos2
)
1221 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1222 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1227 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1230 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1231 LttvTracefileContextPosition
*tfcp1
=
1232 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1234 if(tfcp1
->used
== TRUE
) {
1235 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1236 LttvTracefileContextPosition
*tfcp2
=
1237 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1239 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1240 if(tfcp2
->used
== TRUE
)
1241 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1245 if(ret
!= 0) return ret
;
1250 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1251 LttvTracefileContextPosition
*tfcp2
=
1252 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1254 if(tfcp1
->tfc
== tfcp2
->tfc
)
1255 if(tfcp2
->used
== TRUE
) ret
= 1;
1256 if(ret
!= 0) return ret
;
1264 LttTime
lttv_traceset_context_position_get_time(
1265 const LttvTracesetContextPosition
*pos
)
1267 return pos
->timestamp
;
1271 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1273 GTree
*pqueue
= self
->pqueue
;
1274 LttvTracefileContext
*tfc
= NULL
;
1276 g_tree_foreach(pqueue
, get_first
, &tfc
);
1281 /* lttv_process_traceset_synchronize_tracefiles
1283 * Use the sync_position field of the trace set context to synchronize each
1284 * tracefile with the previously saved position.
1286 * If no previous position has been saved, it simply does nothing.
1288 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1292 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1293 g_assert_cmpint(retval
, ==, 0);
1299 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1301 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1304 struct seek_back_data
{
1305 guint first_event
; /* Index of the first event in the array : we will always
1306 overwrite at this position : this is a circular array.
1309 guint n
; /* number of events requested */
1310 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1311 LttvFilter
*filter1
;
1312 LttvFilter
*filter2
;
1313 LttvFilter
*filter3
;
1315 check_handler
*check
;
1316 gboolean
*stop_flag
;
1317 guint raw_event_count
;
1320 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1322 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1323 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1324 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1325 LttvTracesetContextPosition
*pos
;
1327 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1329 sd
->raw_event_count
++;
1331 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1332 !lttv_filter_tree_parse(sd
->filter1
->head
,
1333 ltt_tracefile_get_event(tfc
->tf
),
1339 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1340 !lttv_filter_tree_parse(sd
->filter2
->head
,
1341 ltt_tracefile_get_event(tfc
->tf
),
1347 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1348 !lttv_filter_tree_parse(sd
->filter3
->head
,
1349 ltt_tracefile_get_event(tfc
->tf
),
1356 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1359 lttv_traceset_context_position_save(tsc
, pos
);
1361 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1362 else sd
->first_event
++;
1364 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1369 /* Seek back n events back from the current position.
1372 * @self The trace set context
1373 * @n number of events to jump over
1374 * @first_offset The initial offset value used.
1375 * never put first_offset at ltt_time_zero.
1376 * @time_seeker Function pointer of the function to use to seek time :
1377 * either lttv_process_traceset_seek_time
1378 * or lttv_state_traceset_seek_time_closest
1379 * @filter The filter to call.
1381 * Return value : the number of events found (might be lower than the number
1382 * requested if beginning of traceset is reached).
1384 * The first search will go back first_offset and try to find the last n events
1385 * matching the filter. If there are not enough, it will try to go back from the
1386 * new trace point from first_offset*2, and so on, until beginning of trace or n
1389 * Note : this function does not take in account the LttvFilter : use the
1390 * similar function found in state.c instead.
1392 * Note2 : the caller must make sure that the LttvTracesetContext does not
1393 * contain any hook, as process_traceset_middle is used in this routine.
1395 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1396 guint n
, LttTime first_offset
,
1397 seek_time_fct time_seeker
,
1398 check_handler
*check
,
1399 gboolean
*stop_flag
,
1400 LttvFilter
*filter1
,
1401 LttvFilter
*filter2
,
1402 LttvFilter
*filter3
,
1405 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1406 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1409 LttvTracesetContextPosition
*next_iter_end_pos
=
1410 lttv_traceset_context_position_new(self
);
1411 LttvTracesetContextPosition
*end_pos
=
1412 lttv_traceset_context_position_new(self
);
1413 LttvTracesetContextPosition
*saved_pos
=
1414 lttv_traceset_context_position_new(self
);
1417 LttTime time_offset
;
1418 struct seek_back_data sd
;
1419 LttvHooks
*hooks
= lttv_hooks_new();
1423 sd
.events_found
= 0;
1424 sd
.array
= g_ptr_array_sized_new(n
);
1425 sd
.filter1
= filter1
;
1426 sd
.filter2
= filter2
;
1427 sd
.filter3
= filter3
;
1431 sd
.stop_flag
= stop_flag
;
1432 sd
.raw_event_count
= 0;
1433 g_ptr_array_set_size(sd
.array
, n
);
1435 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1438 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1439 lttv_traceset_context_position_save(self
, saved_pos
);
1440 /* Get the current time from which we will offset */
1441 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1442 /* the position saved might be end of traceset... */
1443 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1444 time
= self
->time_span
.end_time
;
1447 time_offset
= first_offset
;
1449 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1451 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1454 /* stop criteria : - n events found
1455 * - asked_time < beginning of trace */
1456 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) < 0) break;
1458 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1460 /* We must seek the traceset back to time - time_offset */
1461 /* this time becomes the new reference time */
1462 time
= ltt_time_sub(time
, time_offset
);
1465 time_seeker(self
, time
);
1466 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1467 /* Resync the time in case of a seek_closest */
1468 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1469 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1470 time
= self
->time_span
.end_time
;
1473 /* Process the traceset, calling a hook which adds events
1474 * to the array, overwriting the tail. It changes first_event and
1475 * events_found too. */
1476 /* We would like to have a clean context here : no other hook than our's */
1478 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1479 G_MAXUINT
, end_pos
);
1481 if(sd
.events_found
< n
) {
1482 if(sd
.first_event
> 0) {
1483 /* Save the first position */
1484 LttvTracesetContextPosition
*pos
=
1485 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1486 lttv_traceset_context_position_copy(saved_pos
, pos
);
1488 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1489 /* Change array size to n - events_found */
1490 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1491 LttvTracesetContextPosition
*pos
=
1492 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1493 lttv_traceset_context_position_destroy(pos
);
1495 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1498 } else break; /* Second end criterion : n events found */
1500 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1503 lttv_traceset_context_position_destroy(end_pos
);
1504 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1506 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1508 if(sd
.events_found
>= n
) {
1509 /* Seek the traceset to the first event in the circular array */
1510 LttvTracesetContextPosition
*pos
=
1511 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1513 retval
= lttv_process_traceset_seek_position(self
, pos
);
1514 g_assert_cmpint(retval
, ==, 0);
1516 /* Will seek to the last saved position : in the worst case, it will be the
1517 * original position (if events_found is 0) */
1518 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1519 g_assert_cmpint(retval
, ==, 0);
1522 for(i
=0;i
<sd
.array
->len
;i
++) {
1523 LttvTracesetContextPosition
*pos
=
1524 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1525 lttv_traceset_context_position_destroy(pos
);
1527 g_ptr_array_free(sd
.array
, TRUE
);
1529 lttv_hooks_destroy(hooks
);
1531 lttv_traceset_context_position_destroy(saved_pos
);
1533 return sd
.events_found
;
1537 struct seek_forward_data
{
1538 guint event_count
; /* event counter */
1539 guint n
; /* requested number of events to jump over */
1540 LttvFilter
*filter1
;
1541 LttvFilter
*filter2
;
1542 LttvFilter
*filter3
;
1544 check_handler
*check
;
1545 gboolean
*stop_flag
;
1546 guint raw_event_count
; /* event counter */
1549 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1551 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1552 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1554 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1556 sd
->raw_event_count
++;
1558 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1559 !lttv_filter_tree_parse(sd
->filter1
->head
,
1560 ltt_tracefile_get_event(tfc
->tf
),
1566 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1567 !lttv_filter_tree_parse(sd
->filter2
->head
,
1568 ltt_tracefile_get_event(tfc
->tf
),
1574 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1575 !lttv_filter_tree_parse(sd
->filter3
->head
,
1576 ltt_tracefile_get_event(tfc
->tf
),
1584 if(sd
->event_count
>= sd
->n
)
1589 /* Seek back n events forward from the current position (1 to n)
1590 * 0 is ok too, but it will actually do nothing.
1593 * @self the trace set context
1594 * @n number of events to jump over
1595 * @filter filter to call.
1597 * returns : the number of events jumped over (may be less than requested if end
1598 * of traceset reached) */
1599 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1601 check_handler
*check
,
1602 gboolean
*stop_flag
,
1603 LttvFilter
*filter1
,
1604 LttvFilter
*filter2
,
1605 LttvFilter
*filter3
,
1608 struct seek_forward_data sd
;
1611 sd
.filter1
= filter1
;
1612 sd
.filter2
= filter2
;
1613 sd
.filter3
= filter3
;
1616 sd
.stop_flag
= stop_flag
;
1617 sd
.raw_event_count
= 0;
1619 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1621 LttvHooks
*hooks
= lttv_hooks_new();
1623 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1625 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1627 /* it will end on the end of traceset, or the fact that the
1628 * hook returns TRUE.
1630 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1633 /* Here, our position is either the end of traceset, or the exact position
1634 * after n events : leave it like this. This might be placed on an event that
1635 * will be filtered out, we don't care : all we know is that the following
1636 * event filtered in will be the right one. */
1638 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1640 lttv_hooks_destroy(hooks
);
1642 return sd
.event_count
;