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 void lttv_traceset_context_compute_time_span(LttvTracesetContext
*self
,
113 TimeInterval
*time_span
)
115 LttvTraceset
* traceset
= self
->ts
;
116 int numTraces
= lttv_traceset_number(traceset
);
119 LttvTraceContext
*tc
;
122 time_span
->start_time
.tv_sec
= 0;
123 time_span
->start_time
.tv_nsec
= 0;
124 time_span
->end_time
.tv_sec
= 0;
125 time_span
->end_time
.tv_nsec
= 0;
127 for(i
=0; i
<numTraces
;i
++){
128 tc
= self
->traces
[i
];
131 ltt_trace_time_span_get(trace
, &s
, &e
);
132 tc
->time_span
.start_time
= s
;
133 tc
->time_span
.end_time
= e
;
136 time_span
->start_time
= s
;
137 time_span
->end_time
= e
;
139 if(s
.tv_sec
< time_span
->start_time
.tv_sec
140 || (s
.tv_sec
== time_span
->start_time
.tv_sec
141 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
142 time_span
->start_time
= s
;
143 if(e
.tv_sec
> time_span
->end_time
.tv_sec
144 || (e
.tv_sec
== time_span
->end_time
.tv_sec
145 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
146 time_span
->end_time
= e
;
151 static void init_tracefile_context(LttTracefile
*tracefile
,
152 LttvTraceContext
*tc
)
154 LttvTracefileContext
*tfc
;
155 LttvTracesetContext
*tsc
= tc
->ts_context
;
157 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
159 tfc
->index
= tc
->tracefiles
->len
;
160 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
165 tfc
->event
= lttv_hooks_new();
166 tfc
->event_by_id
= lttv_hooks_by_id_new();
167 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
168 tfc
->target_pid
= -1;
173 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
177 LttvTraceContext
*tc
;
179 GData
**tracefiles_groups
;
181 struct compute_tracefile_group_args args
;
183 nb_trace
= lttv_traceset_number(ts
);
185 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
186 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
187 self
->ts_a
= lttv_traceset_attribute(ts
);
188 for(i
= 0 ; i
< nb_trace
; i
++) {
189 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
190 self
->traces
[i
] = tc
;
192 tc
->ts_context
= self
;
194 tc
->vt
= lttv_traceset_get(ts
, i
);
195 tc
->t
= lttv_trace(tc
->vt
);
196 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
197 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
198 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
199 sizeof(LttvTracefileContext
*), 10);
201 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
202 if(tracefiles_groups
!= NULL
) {
203 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
206 g_datalist_foreach(tracefiles_groups
,
207 (GDataForeachFunc
)compute_tracefile_group
,
212 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
213 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
214 nb_tracefile
= nb_control
+ nb_per_cpu
;
215 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
217 for(j
= 0 ; j
< nb_tracefile
; j
++) {
218 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
219 tc
->tracefiles
[j
] = tfc
;
224 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
227 tfc
->control
= FALSE
;
228 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
232 tfc
->e
= ltt_event_new();
233 tfc
->event
= lttv_hooks_new();
234 tfc
->event_by_id
= lttv_hooks_by_id_new();
235 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
240 self
->sync_position
= lttv_traceset_context_position_new(self
);
241 self
->pqueue
= g_tree_new(compare_tracefile
);
242 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
243 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
248 void fini(LttvTracesetContext
*self
)
250 guint i
, j
, nb_trace
, nb_tracefile
;
252 LttvTraceContext
*tc
;
254 LttvTracefileContext
**tfc
;
256 LttvTraceset
*ts
= self
->ts
;
258 g_tree_destroy(self
->pqueue
);
259 g_object_unref(self
->a
);
260 lttv_traceset_context_position_destroy(self
->sync_position
);
262 nb_trace
= lttv_traceset_number(ts
);
264 for(i
= 0 ; i
< nb_trace
; i
++) {
265 tc
= self
->traces
[i
];
267 g_object_unref(tc
->a
);
269 nb_tracefile
= tc
->tracefiles
->len
;
271 for(j
= 0 ; j
< nb_tracefile
; j
++) {
272 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
273 lttv_hooks_destroy((*tfc
)->event
);
274 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
275 g_object_unref((*tfc
)->a
);
276 g_object_unref(*tfc
);
278 g_array_free(tc
->tracefiles
, TRUE
);
281 g_free(self
->traces
);
285 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
286 LttvHooks
*before_traceset
,
287 LttvHooks
*before_trace
,
288 LttvHooks
*before_tracefile
,
290 LttvHooksByIdChannelArray
*event_by_id_channel
)
292 LttvTraceset
*ts
= self
->ts
;
296 LttvTraceContext
*tc
;
298 lttv_hooks_call(before_traceset
, self
);
300 nb_trace
= lttv_traceset_number(ts
);
302 for(i
= 0 ; i
< nb_trace
; i
++) {
303 tc
= self
->traces
[i
];
304 lttv_trace_context_add_hooks(tc
,
308 event_by_id_channel
);
313 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
314 LttvHooks
*after_traceset
,
315 LttvHooks
*after_trace
,
316 LttvHooks
*after_tracefile
,
318 LttvHooksByIdChannelArray
*event_by_id_channel
)
321 LttvTraceset
*ts
= self
->ts
;
325 LttvTraceContext
*tc
;
327 nb_trace
= lttv_traceset_number(ts
);
329 for(i
= 0 ; i
< nb_trace
; i
++) {
330 tc
= self
->traces
[i
];
331 lttv_trace_context_remove_hooks(tc
,
335 event_by_id_channel
);
338 lttv_hooks_call(after_traceset
, self
);
343 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
344 LttvHooks
*before_trace
,
345 LttvHooks
*before_tracefile
,
347 LttvHooksByIdChannelArray
*event_by_id_channel
)
349 guint i
, j
, nb_tracefile
;
350 LttvTracefileContext
**tfc
;
353 lttv_hooks_call(before_trace
, self
);
355 nb_tracefile
= self
->tracefiles
->len
;
357 for(i
= 0 ; i
< nb_tracefile
; i
++) {
358 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
360 lttv_tracefile_context_add_hooks(*tfc
,
364 if (event_by_id_channel
) {
365 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
366 LttvHooksByIdChannel
*hooks
= &g_array_index(event_by_id_channel
->array
,
367 LttvHooksByIdChannel
, j
);
368 if (tf
->name
== hooks
->channel
)
369 lttv_tracefile_context_add_hooks(*tfc
,
380 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
381 LttvHooks
*after_trace
,
382 LttvHooks
*after_tracefile
,
384 LttvHooksByIdChannelArray
*event_by_id_channel
)
386 guint i
, j
, nb_tracefile
;
387 LttvTracefileContext
**tfc
;
390 nb_tracefile
= self
->tracefiles
->len
;
392 for(i
= 0 ; i
< nb_tracefile
; i
++) {
393 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
395 if (event_by_id_channel
) {
396 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
397 LttvHooksByIdChannel
*hooks
= &g_array_index(event_by_id_channel
->array
,
398 LttvHooksByIdChannel
, j
);
399 if (tf
->name
== hooks
->channel
)
400 lttv_tracefile_context_remove_hooks(*tfc
,
406 lttv_tracefile_context_remove_hooks(*tfc
,
413 lttv_hooks_call(after_trace
, self
);
416 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
417 LttvHooks
*before_tracefile
,
419 LttvHooksById
*event_by_id
)
424 lttv_hooks_call(before_tracefile
, self
);
425 lttv_hooks_add_list(self
->event
, event
);
426 if(event_by_id
!= NULL
) {
427 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
428 index
= g_array_index(event_by_id
->array
, guint
, i
);
429 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
430 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
435 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
436 LttvHooks
*after_tracefile
,
438 LttvHooksById
*event_by_id
)
444 lttv_hooks_remove_list(self
->event
, event
);
445 if(event_by_id
!= NULL
) {
446 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
447 index
= g_array_index(event_by_id
->array
, guint
, i
);
448 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
450 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
454 lttv_hooks_call(after_tracefile
, self
);
457 static LttvTracesetContext
*
458 new_traceset_context(LttvTracesetContext
*self
)
460 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
464 static LttvTraceContext
*
465 new_trace_context(LttvTracesetContext
*self
)
467 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
471 static LttvTracefileContext
*
472 new_tracefile_context(LttvTracesetContext
*self
)
474 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
479 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
481 /* Be careful of anything which would not work well with shallow copies */
486 traceset_context_finalize (LttvTracesetContext
*self
)
488 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
489 ->finalize(G_OBJECT(self
));
494 traceset_context_class_init (LttvTracesetContextClass
*klass
)
496 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
498 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
501 klass
->new_traceset_context
= new_traceset_context
;
502 klass
->new_trace_context
= new_trace_context
;
503 klass
->new_tracefile_context
= new_tracefile_context
;
508 lttv_traceset_context_get_type(void)
510 static GType type
= 0;
512 static const GTypeInfo info
= {
513 sizeof (LttvTracesetContextClass
),
514 NULL
, /* base_init */
515 NULL
, /* base_finalize */
516 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
517 NULL
, /* class_finalize */
518 NULL
, /* class_data */
519 sizeof (LttvTracesetContext
),
521 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
522 NULL
/* Value handling */
525 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
533 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
535 /* Be careful of anything which would not work well with shallow copies */
540 trace_context_finalize (LttvTraceContext
*self
)
542 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
543 finalize(G_OBJECT(self
));
548 trace_context_class_init (LttvTraceContextClass
*klass
)
550 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
552 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
557 lttv_trace_context_get_type(void)
559 static GType type
= 0;
561 static const GTypeInfo info
= {
562 sizeof (LttvTraceContextClass
),
563 NULL
, /* base_init */
564 NULL
, /* base_finalize */
565 (GClassInitFunc
) trace_context_class_init
, /* class_init */
566 NULL
, /* class_finalize */
567 NULL
, /* class_data */
568 sizeof (LttvTraceContext
),
570 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
571 NULL
/* Value handling */
574 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
582 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
584 /* Be careful of anything which would not work well with shallow copies */
589 tracefile_context_finalize (LttvTracefileContext
*self
)
591 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
592 ->finalize(G_OBJECT(self
));
597 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
599 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
601 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
606 lttv_tracefile_context_get_type(void)
608 static GType type
= 0;
610 static const GTypeInfo info
= {
611 sizeof (LttvTracefileContextClass
),
612 NULL
, /* base_init */
613 NULL
, /* base_finalize */
614 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
615 NULL
, /* class_finalize */
616 NULL
, /* class_data */
617 sizeof (LttvTracefileContext
),
619 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
620 NULL
/* Value handling */
623 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
631 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
632 g_assert(key
== value
);
633 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
638 // Test to see if pqueue is traversed in the right order.
639 static LttTime test_time
;
641 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
643 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
645 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
646 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
647 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
648 tfc
->index
, tfc
->t_context
->index
);
650 if(user_data
!= NULL
) {
651 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
652 g_assert(compare_tracefile(user_data
, value
) == 0);
654 g_assert(compare_tracefile(user_data
, value
) != 0);
656 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
657 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
658 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
661 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
668 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
669 LttvHooks
*before_traceset
,
670 LttvHooks
*before_trace
,
671 LttvHooks
*before_tracefile
,
673 LttvHooksByIdChannelArray
*event_by_id_channel
)
676 /* simply add hooks in context. _before hooks are called by add_hooks. */
677 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
678 lttv_traceset_context_add_hooks(self
,
683 event_by_id_channel
);
687 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
689 /* Note : a _middle must be preceded from a _seek or another middle */
690 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
693 const LttvTracesetContextPosition
*end_position
)
695 GTree
*pqueue
= self
->pqueue
;
697 LttvTracefileContext
*tfc
;
705 //enum read_state last_read_state = LAST_NONE;
707 gint last_ret
= 0; /* return value of the last hook list called */
709 /* Get the next event from the pqueue, call its hooks,
710 reinsert in the pqueue the following event from the same tracefile
711 unless the tracefile is finished or the event is later than the
716 g_tree_foreach(pqueue
, get_first
, &tfc
);
717 /* End of traceset : tfc is NULL */
718 if(unlikely(tfc
== NULL
))
724 * - the maximum number of events specified?
725 * - the end position ?
727 * then the read is finished. We leave the queue in the same state and
731 if(unlikely(last_ret
== TRUE
||
732 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
733 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
734 end_position
) == 0)||
735 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
740 /* Get the tracefile with an event for the smallest time found. If two
741 or more tracefiles have events for the same time, hope that lookup
742 and remove are consistent. */
745 test_time
.tv_sec
= 0;
746 test_time
.tv_nsec
= 0;
747 g_debug("test tree before remove");
748 g_tree_foreach(pqueue
, test_tree
, tfc
);
750 g_tree_remove(pqueue
, tfc
);
753 test_time
.tv_sec
= 0;
754 test_time
.tv_nsec
= 0;
755 g_debug("test tree after remove");
756 g_tree_foreach(pqueue
, test_tree
, tfc
);
760 e
= ltt_tracefile_get_event(tfc
->tf
);
762 //if(last_read_state != LAST_EMPTY) {
763 /* Only call hooks if the last read has given an event or if we are at the
764 * first pass (not if last read returned end of tracefile) */
767 tfc
->target_pid
= -1; /* unset target PID */
769 * return values : 0 : continue read, 1 : go to next position and stop read,
770 * 2 : stay at the current position and stop read */
771 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
772 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
775 /* This is buggy : it won't work well with state computation */
776 if(unlikely(last_ret
== 2)) {
777 /* This is a case where we want to stay at this position and stop read. */
778 g_tree_insert(pqueue
, tfc
, tfc
);
782 read_ret
= ltt_tracefile_read(tfc
->tf
);
785 if(likely(!read_ret
)) {
786 //g_debug("An event is ready");
787 tfc
->timestamp
= ltt_event_time(e
);
788 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
789 g_tree_insert(pqueue
, tfc
, tfc
);
791 test_time
.tv_sec
= 0;
792 test_time
.tv_nsec
= 0;
793 g_debug("test tree after event ready");
794 g_tree_foreach(pqueue
, test_tree
, NULL
);
797 //last_read_state = LAST_OK;
799 tfc
->timestamp
= ltt_time_infinite
;
801 if(read_ret
== ERANGE
) {
802 // last_read_state = LAST_EMPTY;
803 g_debug("End of trace");
805 g_error("Error happened in lttv_process_traceset_middle");
811 void lttv_process_traceset_end(LttvTracesetContext
*self
,
812 LttvHooks
*after_traceset
,
813 LttvHooks
*after_trace
,
814 LttvHooks
*after_tracefile
,
816 LttvHooksByIdChannelArray
*event_by_id_channel
)
818 /* Remove hooks from context. _after hooks are called by remove_hooks. */
819 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
820 lttv_traceset_context_remove_hooks(self
,
825 event_by_id_channel
);
828 /* Subtile modification :
829 * if tracefile has no event at or after the time requested, it is not put in
830 * the queue, as the next read would fail.
832 * Don't forget to empty the traceset pqueue before calling this.
834 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
836 guint i
, nb_tracefile
;
840 LttvTracefileContext
**tfc
;
842 nb_tracefile
= self
->tracefiles
->len
;
844 GTree
*pqueue
= self
->ts_context
->pqueue
;
846 for(i
= 0 ; i
< nb_tracefile
; i
++) {
847 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
849 g_tree_remove(pqueue
, *tfc
);
851 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
852 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
854 if(ret
== 0) { /* not ERANGE especially */
855 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
856 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
857 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
859 (*tfc
)->timestamp
= ltt_time_infinite
;
863 test_time
.tv_sec
= 0;
864 test_time
.tv_nsec
= 0;
865 g_debug("test tree after seek_time");
866 g_tree_foreach(pqueue
, test_tree
, NULL
);
871 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
875 LttvTraceContext
*tc
;
877 //g_tree_destroy(self->pqueue);
878 //self->pqueue = g_tree_new(compare_tracefile);
880 nb_trace
= lttv_traceset_number(self
->ts
);
881 for(i
= 0 ; i
< nb_trace
; i
++) {
882 tc
= self
->traces
[i
];
883 lttv_process_trace_seek_time(tc
, start
);
888 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
889 const LttvTracesetContextPosition
*pos
)
892 /* If a position is set, seek the traceset to this position */
893 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
895 /* Test to see if the traces has been added to the trace set :
896 * It should NEVER happen. Clear all positions if a new trace comes in. */
897 /* FIXME I know this test is not optimal : should keep a number of
898 * tracefiles variable in the traceset.. eventually */
899 guint num_traces
= lttv_traceset_number(self
->ts
);
901 for(i
=0; i
<num_traces
;i
++) {
902 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
904 guint num_tracefiles
= tracefiles
->len
;
905 for(j
=0;j
<num_tracefiles
;j
++)
908 g_assert(tf_count
== pos
->tfcp
->len
);
911 //g_tree_destroy(self->pqueue);
912 //self->pqueue = g_tree_new(compare_tracefile);
914 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
915 LttvTracefileContextPosition
*tfcp
=
916 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
918 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
920 if(tfcp
->used
== TRUE
) {
921 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
923 tfcp
->tfc
->timestamp
=
924 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
925 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
926 ltt_time_infinite
) != 0);
927 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
930 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
935 test_time
.tv_sec
= 0;
936 test_time
.tv_nsec
= 0;
937 g_debug("test tree after seek_position");
938 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
947 #if 0 // pmf: temporary disable
949 find_field(LttEventType
*et
, const GQuark field
)
953 if(field
== 0) return NULL
;
955 f
= ltt_eventtype_field_by_name(et
, field
);
957 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
958 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
959 g_quark_to_string(ltt_eventtype_name(et
)));
966 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
968 return marker_get_info_from_id(th
->mdata
, th
->id
);
971 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
972 GQuark fields
[], LttvHook h
, gpointer hook_data
, GArray
**trace_hooks
)
974 struct marker_info
*info
;
978 struct marker_data
*mdata
;
980 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
981 if (unlikely(!group
|| group
->len
== 0)) {
982 g_info("No channel for marker named %s.%s found",
983 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
987 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
988 info
= marker_get_info_from_name(mdata
, event_name
);
989 if(unlikely(info
== NULL
)) {
990 g_info("No marker named %s.%s found",
991 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
995 init_array_size
= (*trace_hooks
)->len
;
997 /* for each marker with the requested name */
1002 struct marker_field
*marker_field
;
1004 marker_id
= marker_get_id_from_info(mdata
, info
);
1007 tmpth
.mdata
= mdata
;
1008 tmpth
.channel
= channel_name
;
1009 tmpth
.id
= marker_id
;
1010 tmpth
.hook_data
= hook_data
;
1011 tmpth
.fields
= g_ptr_array_new();
1013 /* for each field requested */
1014 for(f
= fields
; f
&& *f
!= 0; f
++) {
1016 for_each_marker_field(marker_field
, info
) {
1017 if(marker_field
->name
== *f
) {
1019 g_ptr_array_add(tmpth
.fields
, marker_field
);
1024 /* Did not find the one of the fields in this instance of the
1025 marker. Print a warning and skip this marker completely.
1026 Still iterate on other markers with same name. */
1027 g_ptr_array_free(tmpth
.fields
, TRUE
);
1028 g_info("Field %s cannot be found in marker %s.%s",
1029 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1030 g_quark_to_string(event_name
));
1034 /* all fields were found: add the tracehook to the array */
1035 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1038 } while(info
!= NULL
);
1040 /* Error if no new trace hook has been added */
1041 if (init_array_size
== (*trace_hooks
)->len
) {
1042 g_info("No marker of name %s.%s has all requested fields",
1043 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1049 void lttv_trace_hook_remove_all(GArray
**th
)
1052 for(i
=0; i
<(*th
)->len
; i
++) {
1053 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1056 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1059 LttvTracesetContextPosition
*lttv_traceset_context_position_new(
1060 const LttvTracesetContext
*self
)
1062 guint num_traces
= lttv_traceset_number(self
->ts
);
1066 for(i
=0; i
<num_traces
;i
++) {
1067 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1069 guint num_tracefiles
= tracefiles
->len
;
1070 for(j
=0;j
<num_tracefiles
;j
++)
1073 LttvTracesetContextPosition
*pos
=
1074 g_new(LttvTracesetContextPosition
, 1);
1075 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1076 sizeof(LttvTracefileContextPosition
),
1078 g_array_set_size(pos
->tfcp
, tf_count
);
1079 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1080 LttvTracefileContextPosition
*tfcp
=
1081 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1082 tfcp
->event
= ltt_event_position_new();
1085 pos
->timestamp
= ltt_time_infinite
;
1089 /* Save all positions, the ones with infinite time will have NULL
1091 /* note : a position must be destroyed when a trace is added/removed from a
1093 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1094 LttvTracesetContextPosition
*pos
)
1097 guint num_traces
= lttv_traceset_number(self
->ts
);
1100 pos
->timestamp
= ltt_time_infinite
;
1102 for(i
=0; i
<num_traces
;i
++) {
1103 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1105 guint num_tracefiles
= tracefiles
->len
;
1107 for(j
=0;j
<num_tracefiles
;j
++) {
1108 g_assert(tf_count
< pos
->tfcp
->len
);
1109 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1110 LttvTracefileContext
*, j
);
1111 LttvTracefileContextPosition
*tfcp
=
1112 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1116 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1117 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1118 ltt_event_position(event
, tfcp
->event
);
1119 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1120 pos
->timestamp
= (*tfc
)->timestamp
;
1126 //g_array_append_val(pos->tfc, *tfc);
1127 //g_array_append_val(pos->ep, ep);
1134 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1138 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1139 LttvTracefileContextPosition
*tfcp
=
1140 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1141 g_free(tfcp
->event
);
1145 g_array_free(pos
->tfcp
, TRUE
);
1149 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1150 const LttvTracesetContextPosition
*src
)
1153 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1155 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1157 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1159 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1161 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1163 dest_tfcp
->used
= src_tfcp
->used
;
1164 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1166 if(src_tfcp
->used
) {
1167 ltt_event_position_copy(
1172 dest
->timestamp
= src
->timestamp
;
1175 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1176 const LttvTracesetContextPosition
*pos
)
1181 if(pos
->tfcp
->len
== 0) {
1182 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1185 if(lttv_traceset_number(self
->ts
) == 0)
1188 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1189 LttvTracefileContextPosition
*tfcp
=
1190 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1192 if(tfcp
->used
== FALSE
) {
1193 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1197 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1200 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1202 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1206 if(ret
!= 0) return ret
;
1213 gint
lttv_traceset_context_pos_pos_compare(
1214 const LttvTracesetContextPosition
*pos1
,
1215 const LttvTracesetContextPosition
*pos2
)
1220 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1221 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1226 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1229 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1230 LttvTracefileContextPosition
*tfcp1
=
1231 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1233 if(tfcp1
->used
== TRUE
) {
1234 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1235 LttvTracefileContextPosition
*tfcp2
=
1236 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1238 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1239 if(tfcp2
->used
== TRUE
)
1240 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1244 if(ret
!= 0) return ret
;
1249 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1250 LttvTracefileContextPosition
*tfcp2
=
1251 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1253 if(tfcp1
->tfc
== tfcp2
->tfc
)
1254 if(tfcp2
->used
== TRUE
) ret
= 1;
1255 if(ret
!= 0) return ret
;
1263 LttTime
lttv_traceset_context_position_get_time(
1264 const LttvTracesetContextPosition
*pos
)
1266 return pos
->timestamp
;
1270 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1272 GTree
*pqueue
= self
->pqueue
;
1273 LttvTracefileContext
*tfc
= NULL
;
1275 g_tree_foreach(pqueue
, get_first
, &tfc
);
1280 /* lttv_process_traceset_synchronize_tracefiles
1282 * Use the sync_position field of the trace set context to synchronize each
1283 * tracefile with the previously saved position.
1285 * If no previous position has been saved, it simply does nothing.
1287 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1291 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1292 g_assert_cmpint(retval
, ==, 0);
1298 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1300 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1303 struct seek_back_data
{
1304 guint first_event
; /* Index of the first event in the array : we will always
1305 overwrite at this position : this is a circular array.
1308 guint n
; /* number of events requested */
1309 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1310 LttvFilter
*filter1
;
1311 LttvFilter
*filter2
;
1312 LttvFilter
*filter3
;
1314 check_handler
*check
;
1315 gboolean
*stop_flag
;
1316 guint raw_event_count
;
1319 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1321 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1322 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1323 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1324 LttvTracesetContextPosition
*pos
;
1326 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1328 sd
->raw_event_count
++;
1330 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1331 !lttv_filter_tree_parse(sd
->filter1
->head
,
1332 ltt_tracefile_get_event(tfc
->tf
),
1338 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1339 !lttv_filter_tree_parse(sd
->filter2
->head
,
1340 ltt_tracefile_get_event(tfc
->tf
),
1346 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1347 !lttv_filter_tree_parse(sd
->filter3
->head
,
1348 ltt_tracefile_get_event(tfc
->tf
),
1355 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1358 lttv_traceset_context_position_save(tsc
, pos
);
1360 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1361 else sd
->first_event
++;
1363 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1368 /* Seek back n events back from the current position.
1371 * @self The trace set context
1372 * @n number of events to jump over
1373 * @first_offset The initial offset value used.
1374 * never put first_offset at ltt_time_zero.
1375 * @time_seeker Function pointer of the function to use to seek time :
1376 * either lttv_process_traceset_seek_time
1377 * or lttv_state_traceset_seek_time_closest
1378 * @filter The filter to call.
1380 * Return value : the number of events found (might be lower than the number
1381 * requested if beginning of traceset is reached).
1383 * The first search will go back first_offset and try to find the last n events
1384 * matching the filter. If there are not enough, it will try to go back from the
1385 * new trace point from first_offset*2, and so on, until beginning of trace or n
1388 * Note : this function does not take in account the LttvFilter : use the
1389 * similar function found in state.c instead.
1391 * Note2 : the caller must make sure that the LttvTracesetContext does not
1392 * contain any hook, as process_traceset_middle is used in this routine.
1394 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1395 guint n
, LttTime first_offset
,
1396 seek_time_fct time_seeker
,
1397 check_handler
*check
,
1398 gboolean
*stop_flag
,
1399 LttvFilter
*filter1
,
1400 LttvFilter
*filter2
,
1401 LttvFilter
*filter3
,
1404 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1405 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1408 LttvTracesetContextPosition
*next_iter_end_pos
=
1409 lttv_traceset_context_position_new(self
);
1410 LttvTracesetContextPosition
*end_pos
=
1411 lttv_traceset_context_position_new(self
);
1412 LttvTracesetContextPosition
*saved_pos
=
1413 lttv_traceset_context_position_new(self
);
1416 LttTime time_offset
;
1417 struct seek_back_data sd
;
1418 LttvHooks
*hooks
= lttv_hooks_new();
1422 sd
.events_found
= 0;
1423 sd
.array
= g_ptr_array_sized_new(n
);
1424 sd
.filter1
= filter1
;
1425 sd
.filter2
= filter2
;
1426 sd
.filter3
= filter3
;
1430 sd
.stop_flag
= stop_flag
;
1431 sd
.raw_event_count
= 0;
1432 g_ptr_array_set_size(sd
.array
, n
);
1434 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1437 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1438 lttv_traceset_context_position_save(self
, saved_pos
);
1439 /* Get the current time from which we will offset */
1440 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1441 /* the position saved might be end of traceset... */
1442 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1443 time
= self
->time_span
.end_time
;
1445 time_offset
= first_offset
;
1447 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1449 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1452 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1454 /* We must seek the traceset back to time - time_offset */
1455 /* this time becomes the new reference time */
1456 if(ltt_time_compare(time
, time_offset
) > 0)
1457 time
= ltt_time_sub(time
, time_offset
);
1459 time
= self
->time_span
.start_time
;
1462 time_seeker(self
, time
);
1463 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1464 /* Resync the time in case of a seek_closest */
1465 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1466 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1467 time
= self
->time_span
.end_time
;
1470 /* Process the traceset, calling a hook which adds events
1471 * to the array, overwriting the tail. It changes first_event and
1472 * events_found too. */
1473 /* We would like to have a clean context here : no other hook than our's */
1475 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1476 G_MAXUINT
, end_pos
);
1478 /* stop criteria : - n events found
1479 * - asked_time < beginning of trace */
1480 if(sd
.events_found
< n
) {
1481 if(sd
.first_event
> 0) {
1482 /* Save the first position */
1483 LttvTracesetContextPosition
*pos
=
1484 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1485 lttv_traceset_context_position_copy(saved_pos
, pos
);
1487 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1488 /* Change array size to n - events_found */
1489 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1490 LttvTracesetContextPosition
*pos
=
1491 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1492 lttv_traceset_context_position_destroy(pos
);
1494 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1498 * Did not fill our event list and started before the beginning of the
1499 * trace. There is no hope to fill it then.
1500 * It is OK to compare with trace start time here because we explicitely
1501 * seeked by time (not by position), so we cannot miss multiple event
1502 * happening exactly at trace start.
1504 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) == 0)
1507 } else break; /* Second end criterion : n events found */
1509 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1512 lttv_traceset_context_position_destroy(end_pos
);
1513 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1515 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1517 if(sd
.events_found
>= n
) {
1518 /* Seek the traceset to the first event in the circular array */
1519 LttvTracesetContextPosition
*pos
=
1520 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1522 retval
= lttv_process_traceset_seek_position(self
, pos
);
1523 g_assert_cmpint(retval
, ==, 0);
1525 /* Will seek to the last saved position : in the worst case, it will be the
1526 * original position (if events_found is 0) */
1527 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1528 g_assert_cmpint(retval
, ==, 0);
1531 for(i
=0;i
<sd
.array
->len
;i
++) {
1532 LttvTracesetContextPosition
*pos
=
1533 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1534 lttv_traceset_context_position_destroy(pos
);
1536 g_ptr_array_free(sd
.array
, TRUE
);
1538 lttv_hooks_destroy(hooks
);
1540 lttv_traceset_context_position_destroy(saved_pos
);
1542 return sd
.events_found
;
1546 struct seek_forward_data
{
1547 guint event_count
; /* event counter */
1548 guint n
; /* requested number of events to jump over */
1549 LttvFilter
*filter1
;
1550 LttvFilter
*filter2
;
1551 LttvFilter
*filter3
;
1553 check_handler
*check
;
1554 gboolean
*stop_flag
;
1555 guint raw_event_count
; /* event counter */
1558 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1560 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1561 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1563 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1565 sd
->raw_event_count
++;
1567 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1568 !lttv_filter_tree_parse(sd
->filter1
->head
,
1569 ltt_tracefile_get_event(tfc
->tf
),
1575 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1576 !lttv_filter_tree_parse(sd
->filter2
->head
,
1577 ltt_tracefile_get_event(tfc
->tf
),
1583 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1584 !lttv_filter_tree_parse(sd
->filter3
->head
,
1585 ltt_tracefile_get_event(tfc
->tf
),
1593 if(sd
->event_count
>= sd
->n
)
1598 /* Seek back n events forward from the current position (1 to n)
1599 * 0 is ok too, but it will actually do nothing.
1602 * @self the trace set context
1603 * @n number of events to jump over
1604 * @filter filter to call.
1606 * returns : the number of events jumped over (may be less than requested if end
1607 * of traceset reached) */
1608 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1610 check_handler
*check
,
1611 gboolean
*stop_flag
,
1612 LttvFilter
*filter1
,
1613 LttvFilter
*filter2
,
1614 LttvFilter
*filter3
,
1617 struct seek_forward_data sd
;
1620 sd
.filter1
= filter1
;
1621 sd
.filter2
= filter2
;
1622 sd
.filter3
= filter3
;
1625 sd
.stop_flag
= stop_flag
;
1626 sd
.raw_event_count
= 0;
1628 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1630 LttvHooks
*hooks
= lttv_hooks_new();
1632 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1634 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1636 /* it will end on the end of traceset, or the fact that the
1637 * hook returns TRUE.
1639 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1642 /* Here, our position is either the end of traceset, or the exact position
1643 * after n events : leave it like this. This might be placed on an event that
1644 * will be filtered out, we don't care : all we know is that the following
1645 * event filtered in will be the right one. */
1647 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1649 lttv_hooks_destroy(hooks
);
1651 return sd
.event_count
;