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
)
1290 g_assert(lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
) == 0);
1296 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1298 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1301 struct seek_back_data
{
1302 guint first_event
; /* Index of the first event in the array : we will always
1303 overwrite at this position : this is a circular array.
1306 guint n
; /* number of events requested */
1307 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1308 LttvFilter
*filter1
;
1309 LttvFilter
*filter2
;
1310 LttvFilter
*filter3
;
1312 check_handler
*check
;
1313 gboolean
*stop_flag
;
1314 guint raw_event_count
;
1317 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1319 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1320 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1321 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1322 LttvTracesetContextPosition
*pos
;
1324 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1326 sd
->raw_event_count
++;
1328 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1329 !lttv_filter_tree_parse(sd
->filter1
->head
,
1330 ltt_tracefile_get_event(tfc
->tf
),
1336 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1337 !lttv_filter_tree_parse(sd
->filter2
->head
,
1338 ltt_tracefile_get_event(tfc
->tf
),
1344 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1345 !lttv_filter_tree_parse(sd
->filter3
->head
,
1346 ltt_tracefile_get_event(tfc
->tf
),
1353 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1356 lttv_traceset_context_position_save(tsc
, pos
);
1358 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1359 else sd
->first_event
++;
1361 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1366 /* Seek back n events back from the current position.
1369 * @self The trace set context
1370 * @n number of events to jump over
1371 * @first_offset The initial offset value used.
1372 * never put first_offset at ltt_time_zero.
1373 * @time_seeker Function pointer of the function to use to seek time :
1374 * either lttv_process_traceset_seek_time
1375 * or lttv_state_traceset_seek_time_closest
1376 * @filter The filter to call.
1378 * Return value : the number of events found (might be lower than the number
1379 * requested if beginning of traceset is reached).
1381 * The first search will go back first_offset and try to find the last n events
1382 * matching the filter. If there are not enough, it will try to go back from the
1383 * new trace point from first_offset*2, and so on, until beginning of trace or n
1386 * Note : this function does not take in account the LttvFilter : use the
1387 * similar function found in state.c instead.
1389 * Note2 : the caller must make sure that the LttvTracesetContext does not
1390 * contain any hook, as process_traceset_middle is used in this routine.
1392 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1393 guint n
, LttTime first_offset
,
1394 seek_time_fct time_seeker
,
1395 check_handler
*check
,
1396 gboolean
*stop_flag
,
1397 LttvFilter
*filter1
,
1398 LttvFilter
*filter2
,
1399 LttvFilter
*filter3
,
1402 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1403 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1406 LttvTracesetContextPosition
*next_iter_end_pos
=
1407 lttv_traceset_context_position_new(self
);
1408 LttvTracesetContextPosition
*end_pos
=
1409 lttv_traceset_context_position_new(self
);
1410 LttvTracesetContextPosition
*saved_pos
=
1411 lttv_traceset_context_position_new(self
);
1414 LttTime time_offset
;
1415 struct seek_back_data sd
;
1416 LttvHooks
*hooks
= lttv_hooks_new();
1419 sd
.events_found
= 0;
1420 sd
.array
= g_ptr_array_sized_new(n
);
1421 sd
.filter1
= filter1
;
1422 sd
.filter2
= filter2
;
1423 sd
.filter3
= filter3
;
1427 sd
.stop_flag
= stop_flag
;
1428 sd
.raw_event_count
= 0;
1429 g_ptr_array_set_size(sd
.array
, n
);
1431 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1434 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1435 lttv_traceset_context_position_save(self
, saved_pos
);
1436 /* Get the current time from which we will offset */
1437 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1438 /* the position saved might be end of traceset... */
1439 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1440 time
= self
->time_span
.end_time
;
1443 time_offset
= first_offset
;
1445 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1447 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1450 /* stop criteria : - n events found
1451 * - asked_time < beginning of trace */
1452 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) < 0) break;
1454 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1456 /* We must seek the traceset back to time - time_offset */
1457 /* this time becomes the new reference time */
1458 time
= ltt_time_sub(time
, time_offset
);
1461 time_seeker(self
, time
);
1462 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1463 /* Resync the time in case of a seek_closest */
1464 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1465 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1466 time
= self
->time_span
.end_time
;
1469 /* Process the traceset, calling a hook which adds events
1470 * to the array, overwriting the tail. It changes first_event and
1471 * events_found too. */
1472 /* We would like to have a clean context here : no other hook than our's */
1474 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1475 G_MAXUINT
, end_pos
);
1477 if(sd
.events_found
< n
) {
1478 if(sd
.first_event
> 0) {
1479 /* Save the first position */
1480 LttvTracesetContextPosition
*pos
=
1481 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1482 lttv_traceset_context_position_copy(saved_pos
, pos
);
1484 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1485 /* Change array size to n - events_found */
1486 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1487 LttvTracesetContextPosition
*pos
=
1488 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1489 lttv_traceset_context_position_destroy(pos
);
1491 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1494 } else break; /* Second end criterion : n events found */
1496 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1499 lttv_traceset_context_position_destroy(end_pos
);
1500 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1502 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1504 if(sd
.events_found
>= n
) {
1505 /* Seek the traceset to the first event in the circular array */
1506 LttvTracesetContextPosition
*pos
=
1507 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1509 g_assert(lttv_process_traceset_seek_position(self
, pos
) == 0);
1511 /* Will seek to the last saved position : in the worst case, it will be the
1512 * original position (if events_found is 0) */
1513 g_assert(lttv_process_traceset_seek_position(self
, saved_pos
) == 0);
1516 for(i
=0;i
<sd
.array
->len
;i
++) {
1517 LttvTracesetContextPosition
*pos
=
1518 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1519 lttv_traceset_context_position_destroy(pos
);
1521 g_ptr_array_free(sd
.array
, TRUE
);
1523 lttv_hooks_destroy(hooks
);
1525 lttv_traceset_context_position_destroy(saved_pos
);
1527 return sd
.events_found
;
1531 struct seek_forward_data
{
1532 guint event_count
; /* event counter */
1533 guint n
; /* requested number of events to jump over */
1534 LttvFilter
*filter1
;
1535 LttvFilter
*filter2
;
1536 LttvFilter
*filter3
;
1538 check_handler
*check
;
1539 gboolean
*stop_flag
;
1540 guint raw_event_count
; /* event counter */
1543 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1545 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1546 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1548 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1550 sd
->raw_event_count
++;
1552 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1553 !lttv_filter_tree_parse(sd
->filter1
->head
,
1554 ltt_tracefile_get_event(tfc
->tf
),
1560 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1561 !lttv_filter_tree_parse(sd
->filter2
->head
,
1562 ltt_tracefile_get_event(tfc
->tf
),
1568 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1569 !lttv_filter_tree_parse(sd
->filter3
->head
,
1570 ltt_tracefile_get_event(tfc
->tf
),
1578 if(sd
->event_count
>= sd
->n
)
1583 /* Seek back n events forward from the current position (1 to n)
1584 * 0 is ok too, but it will actually do nothing.
1587 * @self the trace set context
1588 * @n number of events to jump over
1589 * @filter filter to call.
1591 * returns : the number of events jumped over (may be less than requested if end
1592 * of traceset reached) */
1593 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1595 check_handler
*check
,
1596 gboolean
*stop_flag
,
1597 LttvFilter
*filter1
,
1598 LttvFilter
*filter2
,
1599 LttvFilter
*filter3
,
1602 struct seek_forward_data sd
;
1605 sd
.filter1
= filter1
;
1606 sd
.filter2
= filter2
;
1607 sd
.filter3
= filter3
;
1610 sd
.stop_flag
= stop_flag
;
1611 sd
.raw_event_count
= 0;
1613 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1615 LttvHooks
*hooks
= lttv_hooks_new();
1617 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1619 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1621 /* it will end on the end of traceset, or the fact that the
1622 * hook returns TRUE.
1624 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1627 /* Here, our position is either the end of traceset, or the exact position
1628 * after n events : leave it like this. This might be placed on an event that
1629 * will be filtered out, we don't care : all we know is that the following
1630 * event filtered in will be the right one. */
1632 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1634 lttv_hooks_destroy(hooks
);
1636 return sd
.event_count
;