1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 #include <lttv/lttv.h>
25 #include <lttv/tracecontext.h>
26 #include <ltt/event.h>
27 #include <ltt/facility.h>
28 #include <ltt/trace.h>
30 #include <lttv/filter.h>
33 #define min(a,b) (((a)<(b))?(a):(b))
36 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
40 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
41 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
43 if(likely(trace_a
!= trace_b
)) {
44 comparison
= ltt_time_compare(trace_a
->timestamp
, trace_b
->timestamp
);
45 if(unlikely(comparison
== 0)) {
46 if(trace_a
->index
< trace_b
->index
) comparison
= -1;
47 else if(trace_a
->index
> trace_b
->index
) comparison
= 1;
48 else if(trace_a
->t_context
->index
< trace_b
->t_context
->index
)
50 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
57 typedef struct _LttvTracefileContextPosition
{
58 LttEventPosition
*event
;
59 LttvTracefileContext
*tfc
;
60 gboolean used
; /* Tells if the tfc is at end of traceset position */
61 } LttvTracefileContextPosition
;
64 struct _LttvTracesetContextPosition
{
65 GArray
*tfcp
; /* Array of LttvTracefileContextPosition */
66 LttTime timestamp
; /* Current time at the saved position */
67 /* If ltt_time_infinite : no position is
68 * set, else, a position is set (may be end
69 * of trace, with ep->len == 0) */
72 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
74 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
78 void lttv_context_fini(LttvTracesetContext
*self
)
80 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
85 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
87 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
94 lttv_context_new_trace_context(LttvTracesetContext
*self
)
96 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
100 LttvTracefileContext
*
101 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
103 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
106 /****************************************************************************
107 * lttv_traceset_context_compute_time_span
109 * Keep the time span is sync with on the fly addition and removal of traces
110 * in a trace set. It must be called each time a trace is added/removed from
111 * the traceset. It could be more efficient to call it only once a bunch
112 * of traces are loaded, but the calculation is not long, so it's not
115 * Author : Xang Xiu Yang
116 ***************************************************************************/
117 static void lttv_traceset_context_compute_time_span(
118 LttvTracesetContext
*self
,
119 TimeInterval
*time_span
)
121 LttvTraceset
* traceset
= self
->ts
;
122 int numTraces
= lttv_traceset_number(traceset
);
125 LttvTraceContext
*tc
;
128 time_span
->start_time
.tv_sec
= 0;
129 time_span
->start_time
.tv_nsec
= 0;
130 time_span
->end_time
.tv_sec
= 0;
131 time_span
->end_time
.tv_nsec
= 0;
133 for(i
=0; i
<numTraces
;i
++){
134 tc
= self
->traces
[i
];
137 ltt_trace_time_span_get(trace
, &s
, &e
);
138 tc
->time_span
.start_time
= s
;
139 tc
->time_span
.end_time
= e
;
142 time_span
->start_time
= s
;
143 time_span
->end_time
= e
;
145 if(s
.tv_sec
< time_span
->start_time
.tv_sec
146 || (s
.tv_sec
== time_span
->start_time
.tv_sec
147 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
148 time_span
->start_time
= s
;
149 if(e
.tv_sec
> time_span
->end_time
.tv_sec
150 || (e
.tv_sec
== time_span
->end_time
.tv_sec
151 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
152 time_span
->end_time
= e
;
157 static void init_tracefile_context(LttTracefile
*tracefile
,
158 LttvTraceContext
*tc
)
160 LttvTracefileContext
*tfc
;
161 LttvTracesetContext
*tsc
= tc
->ts_context
;
163 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
165 tfc
->index
= tc
->tracefiles
->len
;
166 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
171 tfc
->event
= lttv_hooks_new();
172 tfc
->event_by_id
= lttv_hooks_by_id_new();
173 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
174 tfc
->target_pid
= -1;
179 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
183 LttvTraceContext
*tc
;
185 GData
**tracefiles_groups
;
187 struct compute_tracefile_group_args args
;
189 nb_trace
= lttv_traceset_number(ts
);
191 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
192 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
193 self
->ts_a
= lttv_traceset_attribute(ts
);
194 for(i
= 0 ; i
< nb_trace
; i
++) {
195 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
196 self
->traces
[i
] = tc
;
198 tc
->ts_context
= self
;
200 tc
->vt
= lttv_traceset_get(ts
, i
);
201 tc
->t
= lttv_trace(tc
->vt
);
202 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
203 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
204 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
205 sizeof(LttvTracefileContext
*), 10);
207 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
208 if(tracefiles_groups
!= NULL
) {
209 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
212 g_datalist_foreach(tracefiles_groups
,
213 (GDataForeachFunc
)compute_tracefile_group
,
218 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
219 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
220 nb_tracefile
= nb_control
+ nb_per_cpu
;
221 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
223 for(j
= 0 ; j
< nb_tracefile
; j
++) {
224 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
225 tc
->tracefiles
[j
] = tfc
;
230 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
233 tfc
->control
= FALSE
;
234 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
238 tfc
->e
= ltt_event_new();
239 tfc
->event
= lttv_hooks_new();
240 tfc
->event_by_id
= lttv_hooks_by_id_new();
241 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
246 self
->sync_position
= lttv_traceset_context_position_new(self
);
247 self
->pqueue
= g_tree_new(compare_tracefile
);
248 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
249 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
254 void fini(LttvTracesetContext
*self
)
256 guint i
, j
, nb_trace
, nb_tracefile
;
258 LttvTraceContext
*tc
;
260 LttvTracefileContext
**tfc
;
262 LttvTraceset
*ts
= self
->ts
;
264 g_tree_destroy(self
->pqueue
);
265 g_object_unref(self
->a
);
266 lttv_traceset_context_position_destroy(self
->sync_position
);
268 nb_trace
= lttv_traceset_number(ts
);
270 for(i
= 0 ; i
< nb_trace
; i
++) {
271 tc
= self
->traces
[i
];
273 g_object_unref(tc
->a
);
275 nb_tracefile
= tc
->tracefiles
->len
;
277 for(j
= 0 ; j
< nb_tracefile
; j
++) {
278 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
279 lttv_hooks_destroy((*tfc
)->event
);
280 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
281 g_object_unref((*tfc
)->a
);
282 g_object_unref(*tfc
);
284 g_array_free(tc
->tracefiles
, TRUE
);
287 g_free(self
->traces
);
291 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
292 LttvHooks
*before_traceset
,
293 LttvHooks
*before_trace
,
294 LttvHooks
*before_tracefile
,
296 LttvHooksById
*event_by_id
)
298 LttvTraceset
*ts
= self
->ts
;
302 LttvTraceContext
*tc
;
304 lttv_hooks_call(before_traceset
, self
);
306 nb_trace
= lttv_traceset_number(ts
);
308 for(i
= 0 ; i
< nb_trace
; i
++) {
309 tc
= self
->traces
[i
];
310 lttv_trace_context_add_hooks(tc
,
319 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
320 LttvHooks
*after_traceset
,
321 LttvHooks
*after_trace
,
322 LttvHooks
*after_tracefile
,
324 LttvHooksById
*event_by_id
)
327 LttvTraceset
*ts
= self
->ts
;
331 LttvTraceContext
*tc
;
333 nb_trace
= lttv_traceset_number(ts
);
335 for(i
= 0 ; i
< nb_trace
; i
++) {
336 tc
= self
->traces
[i
];
337 lttv_trace_context_remove_hooks(tc
,
344 lttv_hooks_call(after_traceset
, self
);
349 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
350 LttvHooks
*before_trace
,
351 LttvHooks
*before_tracefile
,
353 LttvHooksById
*event_by_id
)
355 guint i
, nb_tracefile
;
357 LttvTracefileContext
**tfc
;
359 lttv_hooks_call(before_trace
, self
);
361 nb_tracefile
= self
->tracefiles
->len
;
363 for(i
= 0 ; i
< nb_tracefile
; i
++) {
364 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
365 lttv_tracefile_context_add_hooks(*tfc
,
374 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
375 LttvHooks
*after_trace
,
376 LttvHooks
*after_tracefile
,
378 LttvHooksById
*event_by_id
)
380 guint i
, nb_tracefile
;
382 LttvTracefileContext
**tfc
;
384 nb_tracefile
= self
->tracefiles
->len
;
386 for(i
= 0 ; i
< nb_tracefile
; i
++) {
387 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
388 lttv_tracefile_context_remove_hooks(*tfc
,
394 lttv_hooks_call(after_trace
, self
);
397 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
398 LttvHooks
*before_tracefile
,
400 LttvHooksById
*event_by_id
)
406 lttv_hooks_call(before_tracefile
, self
);
407 lttv_hooks_add_list(self
->event
, event
);
408 if(event_by_id
!= NULL
) {
409 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
410 index
= g_array_index(event_by_id
->array
, guint
, i
);
411 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
412 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
417 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
418 LttvHooks
*after_tracefile
,
420 LttvHooksById
*event_by_id
)
426 lttv_hooks_remove_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_get(self
->event_by_id
, index
);
432 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
436 lttv_hooks_call(after_tracefile
, self
);
441 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext
*tfc
,
443 LttvHooks
*event_by_id
)
446 h
= lttv_hooks_by_id_find(tfc
->event_by_id
, i
);
447 lttv_hooks_add_list(h
, event_by_id
);
450 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext
*tfc
,
453 lttv_hooks_by_id_remove(tfc
->event_by_id
, i
);
456 static LttvTracesetContext
*
457 new_traceset_context(LttvTracesetContext
*self
)
459 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
463 static LttvTraceContext
*
464 new_trace_context(LttvTracesetContext
*self
)
466 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
470 static LttvTracefileContext
*
471 new_tracefile_context(LttvTracesetContext
*self
)
473 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
478 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
480 /* Be careful of anything which would not work well with shallow copies */
485 traceset_context_finalize (LttvTracesetContext
*self
)
487 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
488 ->finalize(G_OBJECT(self
));
493 traceset_context_class_init (LttvTracesetContextClass
*klass
)
495 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
497 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
500 klass
->new_traceset_context
= new_traceset_context
;
501 klass
->new_trace_context
= new_trace_context
;
502 klass
->new_tracefile_context
= new_tracefile_context
;
507 lttv_traceset_context_get_type(void)
509 static GType type
= 0;
511 static const GTypeInfo info
= {
512 sizeof (LttvTracesetContextClass
),
513 NULL
, /* base_init */
514 NULL
, /* base_finalize */
515 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
516 NULL
, /* class_finalize */
517 NULL
, /* class_data */
518 sizeof (LttvTracesetContext
),
520 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
521 NULL
/* Value handling */
524 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
532 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
534 /* Be careful of anything which would not work well with shallow copies */
539 trace_context_finalize (LttvTraceContext
*self
)
541 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
542 finalize(G_OBJECT(self
));
547 trace_context_class_init (LttvTraceContextClass
*klass
)
549 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
551 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
556 lttv_trace_context_get_type(void)
558 static GType type
= 0;
560 static const GTypeInfo info
= {
561 sizeof (LttvTraceContextClass
),
562 NULL
, /* base_init */
563 NULL
, /* base_finalize */
564 (GClassInitFunc
) trace_context_class_init
, /* class_init */
565 NULL
, /* class_finalize */
566 NULL
, /* class_data */
567 sizeof (LttvTraceContext
),
569 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
570 NULL
/* Value handling */
573 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
581 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
583 /* Be careful of anything which would not work well with shallow copies */
588 tracefile_context_finalize (LttvTracefileContext
*self
)
590 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
591 ->finalize(G_OBJECT(self
));
596 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
598 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
600 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
605 lttv_tracefile_context_get_type(void)
607 static GType type
= 0;
609 static const GTypeInfo info
= {
610 sizeof (LttvTracefileContextClass
),
611 NULL
, /* base_init */
612 NULL
, /* base_finalize */
613 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
614 NULL
, /* class_finalize */
615 NULL
, /* class_data */
616 sizeof (LttvTracefileContext
),
618 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
619 NULL
/* Value handling */
622 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
630 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
631 g_assert(key
== value
);
632 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
637 // Test to see if pqueue is traversed in the right order.
638 static LttTime test_time
;
640 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
642 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
644 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
645 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
646 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
647 tfc
->index
, tfc
->t_context
->index
);
649 if(user_data
!= NULL
) {
650 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
651 g_assert(compare_tracefile(user_data
, value
) == 0);
653 g_assert(compare_tracefile(user_data
, value
) != 0);
655 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
656 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
657 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
660 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
667 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
668 LttvHooks
*before_traceset
,
669 LttvHooks
*before_trace
,
670 LttvHooks
*before_tracefile
,
672 LttvHooksById
*event_by_id
)
675 /* simply add hooks in context. _before hooks are called by add_hooks. */
676 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
677 lttv_traceset_context_add_hooks(self
,
686 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
688 /* Note : a _middle must be preceded from a _seek or another middle */
689 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
692 const LttvTracesetContextPosition
*end_position
)
694 GTree
*pqueue
= self
->pqueue
;
696 guint fac_id
, ev_id
, id
;
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 fac_id
= ltt_event_facility_id(e
);
769 ev_id
= ltt_event_eventtype_id(e
);
770 id
= GET_HOOK_ID(fac_id
, ev_id
);
771 tfc
->target_pid
= -1; /* unset target PID */
773 * return values : 0 : continue read, 1 : go to next position and stop read,
774 * 2 : stay at the current position and stop read */
775 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
776 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
779 /* This is buggy : it won't work well with state computation */
780 if(unlikely(last_ret
== 2)) {
781 /* This is a case where we want to stay at this position and stop read. */
782 g_tree_insert(pqueue
, tfc
, tfc
);
786 read_ret
= ltt_tracefile_read(tfc
->tf
);
789 if(likely(!read_ret
)) {
790 //g_debug("An event is ready");
791 tfc
->timestamp
= ltt_event_time(e
);
792 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
793 g_tree_insert(pqueue
, tfc
, tfc
);
795 test_time
.tv_sec
= 0;
796 test_time
.tv_nsec
= 0;
797 g_debug("test tree after event ready");
798 g_tree_foreach(pqueue
, test_tree
, NULL
);
801 //last_read_state = LAST_OK;
803 tfc
->timestamp
= ltt_time_infinite
;
805 if(read_ret
== ERANGE
) {
806 // last_read_state = LAST_EMPTY;
807 g_debug("End of trace");
809 g_error("Error happened in lttv_process_traceset_middle");
815 void lttv_process_traceset_end(LttvTracesetContext
*self
,
816 LttvHooks
*after_traceset
,
817 LttvHooks
*after_trace
,
818 LttvHooks
*after_tracefile
,
820 LttvHooksById
*event_by_id
)
822 /* Remove hooks from context. _after hooks are called by remove_hooks. */
823 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
824 lttv_traceset_context_remove_hooks(self
,
832 /* Subtile modification :
833 * if tracefile has no event at or after the time requested, it is not put in
834 * the queue, as the next read would fail.
836 * Don't forget to empty the traceset pqueue before calling this.
838 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
840 guint i
, nb_tracefile
;
844 LttvTracefileContext
**tfc
;
846 nb_tracefile
= self
->tracefiles
->len
;
848 GTree
*pqueue
= self
->ts_context
->pqueue
;
850 for(i
= 0 ; i
< nb_tracefile
; i
++) {
851 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
853 g_tree_remove(pqueue
, *tfc
);
855 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
856 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
858 if(ret
== 0) { /* not ERANGE especially */
859 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
860 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
861 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
863 (*tfc
)->timestamp
= ltt_time_infinite
;
867 test_time
.tv_sec
= 0;
868 test_time
.tv_nsec
= 0;
869 g_debug("test tree after seek_time");
870 g_tree_foreach(pqueue
, test_tree
, NULL
);
878 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
882 LttvTraceContext
*tc
;
884 //g_tree_destroy(self->pqueue);
885 //self->pqueue = g_tree_new(compare_tracefile);
887 nb_trace
= lttv_traceset_number(self
->ts
);
888 for(i
= 0 ; i
< nb_trace
; i
++) {
889 tc
= self
->traces
[i
];
890 lttv_process_trace_seek_time(tc
, start
);
895 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
896 const LttvTracesetContextPosition
*pos
)
899 /* If a position is set, seek the traceset to this position */
900 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
902 /* Test to see if the traces has been added to the trace set :
903 * It should NEVER happen. Clear all positions if a new trace comes in. */
904 /* FIXME I know this test is not optimal : should keep a number of
905 * tracefiles variable in the traceset.. eventually */
906 guint num_traces
= lttv_traceset_number(self
->ts
);
908 for(i
=0; i
<num_traces
;i
++) {
909 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
911 guint num_tracefiles
= tracefiles
->len
;
912 for(j
=0;j
<num_tracefiles
;j
++)
915 g_assert(tf_count
== pos
->tfcp
->len
);
918 //g_tree_destroy(self->pqueue);
919 //self->pqueue = g_tree_new(compare_tracefile);
921 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
922 LttvTracefileContextPosition
*tfcp
=
923 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
925 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
927 if(tfcp
->used
== TRUE
) {
928 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
930 tfcp
->tfc
->timestamp
=
931 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
932 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
933 ltt_time_infinite
) != 0);
934 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
937 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
942 test_time
.tv_sec
= 0;
943 test_time
.tv_nsec
= 0;
944 g_debug("test tree after seek_position");
945 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
956 find_field(LttEventType
*et
, const GQuark field
)
960 if(field
== 0) return NULL
;
962 f
= ltt_eventtype_field_by_name(et
, field
);
964 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
965 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
966 g_quark_to_string(ltt_eventtype_name(et
)));
972 LttvTraceHookByFacility
*lttv_trace_hook_get_fac(LttvTraceHook
*th
,
975 return &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, facility_id
);
978 /* Get the first facility corresponding to the name. As the types must be
979 * compatible, it is relevant to use the field name and sizes of the first
980 * facility to create data structures and assume the data will be compatible
981 * thorough the trace */
982 LttvTraceHookByFacility
*lttv_trace_hook_get_first(LttvTraceHook
*th
)
984 g_assert(th
->fac_list
->len
> 0);
985 return g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0);
989 /* Returns 0 on success, -1 if fails. */
991 lttv_trace_find_hook(LttTrace
*t
, GQuark facility
, GQuark event
,
992 GQuark field1
, GQuark field2
, GQuark field3
, LttvHook h
, gpointer hook_data
,
997 LttEventType
*et
, *first_et
;
1001 guint i
, fac_id
, ev_id
;
1003 LttvTraceHookByFacility
*thf
, *first_thf
;
1005 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
1007 if(unlikely(facilities
== NULL
)) goto facility_error
;
1009 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
1010 sizeof(LttvTraceHookByFacility
),
1012 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
1014 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
1015 sizeof(LttvTraceHookByFacility
*),
1017 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
1019 fac_id
= g_array_index(facilities
, guint
, 0);
1020 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
1022 et
= ltt_facility_eventtype_get_by_name(f
, event
);
1023 if(unlikely(et
== NULL
)) goto event_error
;
1025 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
1026 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0) = thf
;
1028 ev_id
= ltt_eventtype_id(et
);
1031 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
1032 thf
->f1
= find_field(et
, field1
);
1033 thf
->f2
= find_field(et
, field2
);
1034 thf
->f3
= find_field(et
, field3
);
1035 thf
->hook_data
= hook_data
;
1040 /* Check for type compatibility too */
1041 for(i
=1;i
<facilities
->len
;i
++) {
1042 fac_id
= g_array_index(facilities
, guint
, i
);
1043 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
1045 et
= ltt_facility_eventtype_get_by_name(f
, event
);
1046 if(unlikely(et
== NULL
)) goto event_error
;
1048 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
1049 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
) = thf
;
1050 ev_id
= ltt_eventtype_id(et
);
1052 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
1053 thf
->f1
= find_field(et
, field1
);
1054 if(check_fields_compatibility(first_et
, et
,
1055 first_thf
->f1
, thf
->f1
))
1058 thf
->f2
= find_field(et
, field2
);
1059 if(check_fields_compatibility(first_et
, et
,
1060 first_thf
->f2
, thf
->f2
))
1063 thf
->f3
= find_field(et
, field3
);
1064 if(check_fields_compatibility(first_et
, et
,
1065 first_thf
->f3
, thf
->f3
))
1067 thf
->hook_data
= hook_data
;
1075 g_error("Event type does not exist for event %s",
1076 g_quark_to_string(event
));
1079 //Ignore this type of error : some facilities are not required.
1080 //g_error("No %s facility", g_quark_to_string(facility));
1083 g_array_free(th
->fac_index
, TRUE
);
1084 g_array_free(th
->fac_list
, TRUE
);
1085 th
->fac_index
= NULL
;
1086 th
->fac_list
= NULL
;
1090 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
1092 g_array_free(th
->fac_index
, TRUE
);
1093 g_array_free(th
->fac_list
, TRUE
);
1099 LttvTracesetContextPosition
*lttv_traceset_context_position_new(
1100 const LttvTracesetContext
*self
)
1102 guint num_traces
= lttv_traceset_number(self
->ts
);
1106 for(i
=0; i
<num_traces
;i
++) {
1107 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1109 guint num_tracefiles
= tracefiles
->len
;
1110 for(j
=0;j
<num_tracefiles
;j
++)
1113 LttvTracesetContextPosition
*pos
=
1114 g_new(LttvTracesetContextPosition
, 1);
1115 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1116 sizeof(LttvTracefileContextPosition
),
1118 g_array_set_size(pos
->tfcp
, tf_count
);
1119 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1120 LttvTracefileContextPosition
*tfcp
=
1121 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1122 tfcp
->event
= ltt_event_position_new();
1125 pos
->timestamp
= ltt_time_infinite
;
1129 /* Save all positions, the ones with infinite time will have NULL
1131 /* note : a position must be destroyed when a trace is added/removed from a
1133 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1134 LttvTracesetContextPosition
*pos
)
1137 guint num_traces
= lttv_traceset_number(self
->ts
);
1140 pos
->timestamp
= ltt_time_infinite
;
1142 for(i
=0; i
<num_traces
;i
++) {
1143 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1145 guint num_tracefiles
= tracefiles
->len
;
1147 for(j
=0;j
<num_tracefiles
;j
++) {
1148 g_assert(tf_count
< pos
->tfcp
->len
);
1149 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1150 LttvTracefileContext
*, j
);
1151 LttvTracefileContextPosition
*tfcp
=
1152 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1156 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1157 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1158 ltt_event_position(event
, tfcp
->event
);
1159 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1160 pos
->timestamp
= (*tfc
)->timestamp
;
1166 //g_array_append_val(pos->tfc, *tfc);
1167 //g_array_append_val(pos->ep, ep);
1174 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1178 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1179 LttvTracefileContextPosition
*tfcp
=
1180 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1181 g_free(tfcp
->event
);
1185 g_array_free(pos
->tfcp
, TRUE
);
1189 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1190 const LttvTracesetContextPosition
*src
)
1193 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1195 g_assert(src
->tfcp
->len
== src
->tfcp
->len
);
1197 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1199 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1201 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1203 dest_tfcp
->used
= src_tfcp
->used
;
1204 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1206 if(src_tfcp
->used
) {
1207 ltt_event_position_copy(
1212 dest
->timestamp
= src
->timestamp
;
1215 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1216 const LttvTracesetContextPosition
*pos
)
1221 if(pos
->tfcp
->len
== 0) {
1222 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1225 if(lttv_traceset_number(self
->ts
) == 0)
1228 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1229 LttvTracefileContextPosition
*tfcp
=
1230 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1232 if(tfcp
->used
== FALSE
) {
1233 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1237 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1240 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1242 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1246 if(ret
!= 0) return ret
;
1253 gint
lttv_traceset_context_pos_pos_compare(
1254 const LttvTracesetContextPosition
*pos1
,
1255 const LttvTracesetContextPosition
*pos2
)
1260 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1261 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1266 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1269 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1270 LttvTracefileContextPosition
*tfcp1
=
1271 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1273 if(tfcp1
->used
== TRUE
) {
1274 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1275 LttvTracefileContextPosition
*tfcp2
=
1276 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1278 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1279 if(tfcp2
->used
== TRUE
)
1280 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1284 if(ret
!= 0) return ret
;
1289 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1290 LttvTracefileContextPosition
*tfcp2
=
1291 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1293 if(tfcp1
->tfc
== tfcp2
->tfc
)
1294 if(tfcp2
->used
== TRUE
) ret
= 1;
1295 if(ret
!= 0) return ret
;
1303 LttTime
lttv_traceset_context_position_get_time(
1304 const LttvTracesetContextPosition
*pos
)
1306 return pos
->timestamp
;
1310 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1312 GTree
*pqueue
= self
->pqueue
;
1313 LttvTracefileContext
*tfc
= NULL
;
1315 g_tree_foreach(pqueue
, get_first
, &tfc
);
1320 /* lttv_process_traceset_synchronize_tracefiles
1322 * Use the sync_position field of the trace set context to synchronize each
1323 * tracefile with the previously saved position.
1325 * If no previous position has been saved, it simply does nothing.
1327 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1329 g_assert(lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
) == 0);
1335 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1337 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1340 struct seek_back_data
{
1341 guint first_event
; /* Index of the first event in the array : we will always
1342 overwrite at this position : this is a circular array.
1345 guint n
; /* number of events requested */
1346 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1347 LttvFilter
*filter1
;
1348 LttvFilter
*filter2
;
1349 LttvFilter
*filter3
;
1351 check_handler
*check
;
1352 gboolean
*stop_flag
;
1353 guint raw_event_count
;
1356 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1358 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1359 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1360 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1361 LttvTracesetContextPosition
*pos
;
1363 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1365 sd
->raw_event_count
++;
1367 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1368 !lttv_filter_tree_parse(sd
->filter1
->head
,
1369 ltt_tracefile_get_event(tfc
->tf
),
1375 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1376 !lttv_filter_tree_parse(sd
->filter2
->head
,
1377 ltt_tracefile_get_event(tfc
->tf
),
1383 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1384 !lttv_filter_tree_parse(sd
->filter3
->head
,
1385 ltt_tracefile_get_event(tfc
->tf
),
1392 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1395 lttv_traceset_context_position_save(tsc
, pos
);
1397 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1398 else sd
->first_event
++;
1400 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1405 /* Seek back n events back from the current position.
1408 * @self The trace set context
1409 * @n number of events to jump over
1410 * @first_offset The initial offset value used.
1411 * never put first_offset at ltt_time_zero.
1412 * @time_seeker Function pointer of the function to use to seek time :
1413 * either lttv_process_traceset_seek_time
1414 * or lttv_state_traceset_seek_time_closest
1415 * @filter The filter to call.
1417 * Return value : the number of events found (might be lower than the number
1418 * requested if beginning of traceset is reached).
1420 * The first search will go back first_offset and try to find the last n events
1421 * matching the filter. If there are not enough, it will try to go back from the
1422 * new trace point from first_offset*2, and so on, until beginning of trace or n
1425 * Note : this function does not take in account the LttvFilter : use the
1426 * similar function found in state.c instead.
1428 * Note2 : the caller must make sure that the LttvTracesetContext does not
1429 * contain any hook, as process_traceset_middle is used in this routine.
1431 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1432 guint n
, LttTime first_offset
,
1433 seek_time_fct time_seeker
,
1434 check_handler
*check
,
1435 gboolean
*stop_flag
,
1436 LttvFilter
*filter1
,
1437 LttvFilter
*filter2
,
1438 LttvFilter
*filter3
,
1441 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1442 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1445 LttvTracesetContextPosition
*next_iter_end_pos
=
1446 lttv_traceset_context_position_new(self
);
1447 LttvTracesetContextPosition
*end_pos
=
1448 lttv_traceset_context_position_new(self
);
1449 LttvTracesetContextPosition
*saved_pos
=
1450 lttv_traceset_context_position_new(self
);
1453 LttTime time_offset
;
1454 struct seek_back_data sd
;
1455 LttvHooks
*hooks
= lttv_hooks_new();
1458 sd
.events_found
= 0;
1459 sd
.array
= g_ptr_array_sized_new(n
);
1460 sd
.filter1
= filter1
;
1461 sd
.filter2
= filter2
;
1462 sd
.filter3
= filter3
;
1466 sd
.stop_flag
= stop_flag
;
1467 sd
.raw_event_count
= 0;
1468 g_ptr_array_set_size(sd
.array
, n
);
1470 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1473 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1474 lttv_traceset_context_position_save(self
, saved_pos
);
1475 /* Get the current time from which we will offset */
1476 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1477 /* the position saved might be end of traceset... */
1478 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1479 time
= self
->time_span
.end_time
;
1482 time_offset
= first_offset
;
1484 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1486 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1489 /* stop criteria : - n events found
1490 * - asked_time < beginning of trace */
1491 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) < 0) break;
1493 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1495 /* We must seek the traceset back to time - time_offset */
1496 /* this time becomes the new reference time */
1497 time
= ltt_time_sub(time
, time_offset
);
1500 time_seeker(self
, time
);
1501 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1502 /* Resync the time in case of a seek_closest */
1503 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1504 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1505 time
= self
->time_span
.end_time
;
1508 /* Process the traceset, calling a hook which adds events
1509 * to the array, overwriting the tail. It changes first_event and
1510 * events_found too. */
1511 /* We would like to have a clean context here : no other hook than our's */
1513 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1514 G_MAXUINT
, end_pos
);
1516 if(sd
.events_found
< n
) {
1517 if(sd
.first_event
> 0) {
1518 /* Save the first position */
1519 LttvTracesetContextPosition
*pos
=
1520 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1521 lttv_traceset_context_position_copy(saved_pos
, pos
);
1523 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1524 /* Change array size to n - events_found */
1525 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1526 LttvTracesetContextPosition
*pos
=
1527 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1528 lttv_traceset_context_position_destroy(pos
);
1530 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1533 } else break; /* Second end criterion : n events found */
1535 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1538 lttv_traceset_context_position_destroy(end_pos
);
1539 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1541 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1543 if(sd
.events_found
>= n
) {
1544 /* Seek the traceset to the first event in the circular array */
1545 LttvTracesetContextPosition
*pos
=
1546 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1548 g_assert(lttv_process_traceset_seek_position(self
, pos
) == 0);
1550 /* Will seek to the last saved position : in the worst case, it will be the
1551 * original position (if events_found is 0) */
1552 g_assert(lttv_process_traceset_seek_position(self
, saved_pos
) == 0);
1555 for(i
=0;i
<sd
.array
->len
;i
++) {
1556 LttvTracesetContextPosition
*pos
=
1557 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1558 lttv_traceset_context_position_destroy(pos
);
1560 g_ptr_array_free(sd
.array
, TRUE
);
1562 lttv_hooks_destroy(hooks
);
1564 lttv_traceset_context_position_destroy(saved_pos
);
1566 return sd
.events_found
;
1570 struct seek_forward_data
{
1571 guint event_count
; /* event counter */
1572 guint n
; /* requested number of events to jump over */
1573 LttvFilter
*filter1
;
1574 LttvFilter
*filter2
;
1575 LttvFilter
*filter3
;
1577 check_handler
*check
;
1578 gboolean
*stop_flag
;
1579 guint raw_event_count
; /* event counter */
1582 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1584 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1585 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1587 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1589 sd
->raw_event_count
++;
1591 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1592 !lttv_filter_tree_parse(sd
->filter1
->head
,
1593 ltt_tracefile_get_event(tfc
->tf
),
1599 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1600 !lttv_filter_tree_parse(sd
->filter2
->head
,
1601 ltt_tracefile_get_event(tfc
->tf
),
1607 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1608 !lttv_filter_tree_parse(sd
->filter3
->head
,
1609 ltt_tracefile_get_event(tfc
->tf
),
1617 if(sd
->event_count
>= sd
->n
)
1621 /* Seek back n events forward from the current position (1 to n)
1622 * 0 is ok too, but it will actually do nothing.
1625 * @self the trace set context
1626 * @n number of events to jump over
1627 * @filter filter to call.
1629 * returns : the number of events jumped over (may be less than requested if end
1630 * of traceset reached) */
1631 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1633 check_handler
*check
,
1634 gboolean
*stop_flag
,
1635 LttvFilter
*filter1
,
1636 LttvFilter
*filter2
,
1637 LttvFilter
*filter3
,
1640 struct seek_forward_data sd
;
1643 sd
.filter1
= filter1
;
1644 sd
.filter2
= filter2
;
1645 sd
.filter3
= filter3
;
1648 sd
.stop_flag
= stop_flag
;
1649 sd
.raw_event_count
= 0;
1651 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1653 LttvHooks
*hooks
= lttv_hooks_new();
1655 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1657 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1659 /* it will end on the end of traceset, or the fact that the
1660 * hook returns TRUE.
1662 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1665 /* Here, our position is either the end of traceset, or the exact position
1666 * after n events : leave it like this. This might be placed on an event that
1667 * will be filtered out, we don't care : all we know is that the following
1668 * event filtered in will be the right one. */
1670 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1672 lttv_hooks_destroy(hooks
);
1674 return sd
.event_count
;