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
);
226 tfc
->control
= FALSE
;
227 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
231 tfc
->e
= ltt_event_new();
232 tfc
->event
= lttv_hooks_new();
233 tfc
->event_by_id
= lttv_hooks_by_id_new();
234 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
239 self
->sync_position
= lttv_traceset_context_position_new(self
);
240 self
->pqueue
= g_tree_new(compare_tracefile
);
241 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
242 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
247 void fini(LttvTracesetContext
*self
)
249 guint i
, j
, nb_trace
, nb_tracefile
;
251 LttvTraceContext
*tc
;
253 LttvTracefileContext
**tfc
;
255 LttvTraceset
*ts
= self
->ts
;
257 g_tree_destroy(self
->pqueue
);
258 g_object_unref(self
->a
);
259 lttv_traceset_context_position_destroy(self
->sync_position
);
261 nb_trace
= lttv_traceset_number(ts
);
263 for(i
= 0 ; i
< nb_trace
; i
++) {
264 tc
= self
->traces
[i
];
266 g_object_unref(tc
->a
);
268 nb_tracefile
= tc
->tracefiles
->len
;
270 for(j
= 0 ; j
< nb_tracefile
; j
++) {
271 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
272 lttv_hooks_destroy((*tfc
)->event
);
273 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
274 g_object_unref((*tfc
)->a
);
275 g_object_unref(*tfc
);
277 g_array_free(tc
->tracefiles
, TRUE
);
280 g_free(self
->traces
);
284 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
285 LttvHooks
*before_traceset
,
286 LttvHooks
*before_trace
,
287 LttvHooks
*before_tracefile
,
289 LttvHooksByIdChannelArray
*event_by_id_channel
)
291 LttvTraceset
*ts
= self
->ts
;
295 LttvTraceContext
*tc
;
297 lttv_hooks_call(before_traceset
, self
);
299 nb_trace
= lttv_traceset_number(ts
);
301 for(i
= 0 ; i
< nb_trace
; i
++) {
302 tc
= self
->traces
[i
];
303 lttv_trace_context_add_hooks(tc
,
307 event_by_id_channel
);
312 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
313 LttvHooks
*after_traceset
,
314 LttvHooks
*after_trace
,
315 LttvHooks
*after_tracefile
,
317 LttvHooksByIdChannelArray
*event_by_id_channel
)
320 LttvTraceset
*ts
= self
->ts
;
324 LttvTraceContext
*tc
;
326 nb_trace
= lttv_traceset_number(ts
);
328 for(i
= 0 ; i
< nb_trace
; i
++) {
329 tc
= self
->traces
[i
];
330 lttv_trace_context_remove_hooks(tc
,
334 event_by_id_channel
);
337 lttv_hooks_call(after_traceset
, self
);
342 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
343 LttvHooks
*before_trace
,
344 LttvHooks
*before_tracefile
,
346 LttvHooksByIdChannelArray
*event_by_id_channel
)
348 guint i
, j
, nb_tracefile
;
349 LttvTracefileContext
**tfc
;
352 lttv_hooks_call(before_trace
, self
);
354 nb_tracefile
= self
->tracefiles
->len
;
356 for(i
= 0 ; i
< nb_tracefile
; i
++) {
357 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
359 lttv_tracefile_context_add_hooks(*tfc
,
363 if (event_by_id_channel
) {
364 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
365 LttvHooksByIdChannel
*hooks
=
366 &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
=
398 &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
*new_traceset_context(LttvTracesetContext
*self
)
460 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
464 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
466 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
470 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
472 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
476 static void traceset_context_instance_init(GTypeInstance
*instance
,
479 /* Be careful of anything which would not work well with shallow copies */
483 static void traceset_context_finalize(LttvTracesetContext
*self
)
485 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
486 ->finalize(G_OBJECT(self
));
490 static void traceset_context_class_init(LttvTracesetContextClass
*klass
)
492 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
494 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
497 klass
->new_traceset_context
= new_traceset_context
;
498 klass
->new_trace_context
= new_trace_context
;
499 klass
->new_tracefile_context
= new_tracefile_context
;
503 GType
lttv_traceset_context_get_type(void)
505 static GType type
= 0;
507 static const GTypeInfo info
= {
508 sizeof (LttvTracesetContextClass
),
509 NULL
, /* base_init */
510 NULL
, /* base_finalize */
511 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
512 NULL
, /* class_finalize */
513 NULL
, /* class_data */
514 sizeof (LttvTracesetContext
),
516 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
517 NULL
/* Value handling */
520 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
528 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
530 /* Be careful of anything which would not work well with shallow copies */
534 static void trace_context_finalize (LttvTraceContext
*self
)
536 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
537 finalize(G_OBJECT(self
));
541 static void trace_context_class_init (LttvTraceContextClass
*klass
)
543 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
545 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
549 GType
lttv_trace_context_get_type(void)
551 static GType type
= 0;
553 static const GTypeInfo info
= {
554 sizeof (LttvTraceContextClass
),
555 NULL
, /* base_init */
556 NULL
, /* base_finalize */
557 (GClassInitFunc
) trace_context_class_init
, /* class_init */
558 NULL
, /* class_finalize */
559 NULL
, /* class_data */
560 sizeof (LttvTraceContext
),
562 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
563 NULL
/* Value handling */
566 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
573 static void tracefile_context_instance_init (GTypeInstance
*instance
,
576 /* Be careful of anything which would not work well with shallow copies */
580 static void tracefile_context_finalize (LttvTracefileContext
*self
)
582 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
583 ->finalize(G_OBJECT(self
));
587 static void tracefile_context_class_init (LttvTracefileContextClass
*klass
)
589 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
591 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
595 GType
lttv_tracefile_context_get_type(void)
597 static GType type
= 0;
599 static const GTypeInfo info
= {
600 sizeof (LttvTracefileContextClass
),
601 NULL
, /* base_init */
602 NULL
, /* base_finalize */
603 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
604 NULL
, /* class_finalize */
605 NULL
, /* class_data */
606 sizeof (LttvTracefileContext
),
608 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
609 NULL
/* Value handling */
612 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
620 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
621 g_assert(key
== value
);
622 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
627 // Test to see if pqueue is traversed in the right order.
628 static LttTime test_time
;
630 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
632 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
634 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
635 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
636 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
637 tfc
->index
, tfc
->t_context
->index
);
639 if(user_data
!= NULL
) {
640 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
641 g_assert(compare_tracefile(user_data
, value
) == 0);
643 g_assert(compare_tracefile(user_data
, value
) != 0);
645 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
646 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
647 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
650 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
657 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
658 LttvHooks
*before_traceset
,
659 LttvHooks
*before_trace
,
660 LttvHooks
*before_tracefile
,
662 LttvHooksByIdChannelArray
*event_by_id_channel
)
665 /* simply add hooks in context. _before hooks are called by add_hooks. */
666 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
667 lttv_traceset_context_add_hooks(self
,
672 event_by_id_channel
);
676 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
678 /* Note : a _middle must be preceded from a _seek or another middle */
679 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
682 const LttvTracesetContextPosition
*end_position
)
684 GTree
*pqueue
= self
->pqueue
;
686 LttvTracefileContext
*tfc
;
694 //enum read_state last_read_state = LAST_NONE;
696 gint last_ret
= 0; /* return value of the last hook list called */
698 /* Get the next event from the pqueue, call its hooks,
699 reinsert in the pqueue the following event from the same tracefile
700 unless the tracefile is finished or the event is later than the
705 g_tree_foreach(pqueue
, get_first
, &tfc
);
706 /* End of traceset : tfc is NULL */
707 if(unlikely(tfc
== NULL
))
713 * - the maximum number of events specified?
714 * - the end position ?
716 * then the read is finished. We leave the queue in the same state and
720 if(unlikely(last_ret
== TRUE
721 || ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
))
722 || (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
724 || ltt_time_compare(end
, tfc
->timestamp
) <= 0))
729 /* Get the tracefile with an event for the smallest time found. If two
730 or more tracefiles have events for the same time, hope that lookup
731 and remove are consistent. */
734 test_time
.tv_sec
= 0;
735 test_time
.tv_nsec
= 0;
736 g_debug("test tree before remove");
737 g_tree_foreach(pqueue
, test_tree
, tfc
);
739 g_tree_remove(pqueue
, tfc
);
742 test_time
.tv_sec
= 0;
743 test_time
.tv_nsec
= 0;
744 g_debug("test tree after remove");
745 g_tree_foreach(pqueue
, test_tree
, tfc
);
749 e
= ltt_tracefile_get_event(tfc
->tf
);
751 //if(last_read_state != LAST_EMPTY) {
752 /* Only call hooks if the last read has given an event or if we are at the
753 * first pass (not if last read returned end of tracefile) */
756 tfc
->target_pid
= -1; /* unset target PID */
758 * return values : 0 : continue read, 1 : go to next position and stop read,
759 * 2 : stay at the current position and stop read */
760 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
761 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
764 /* This is buggy : it won't work well with state computation */
765 if(unlikely(last_ret
== 2)) {
766 /* This is a case where we want to stay at this position and stop read. */
767 g_tree_insert(pqueue
, tfc
, tfc
);
771 read_ret
= ltt_tracefile_read(tfc
->tf
);
774 if(likely(!read_ret
)) {
775 //g_debug("An event is ready");
776 tfc
->timestamp
= ltt_event_time(e
);
777 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
778 g_tree_insert(pqueue
, tfc
, tfc
);
780 test_time
.tv_sec
= 0;
781 test_time
.tv_nsec
= 0;
782 g_debug("test tree after event ready");
783 g_tree_foreach(pqueue
, test_tree
, NULL
);
786 //last_read_state = LAST_OK;
788 tfc
->timestamp
= ltt_time_infinite
;
790 if(read_ret
== ERANGE
) {
791 // last_read_state = LAST_EMPTY;
792 g_debug("End of trace");
794 g_error("Error happened in lttv_process_traceset_middle");
800 void lttv_process_traceset_end(LttvTracesetContext
*self
,
801 LttvHooks
*after_traceset
,
802 LttvHooks
*after_trace
,
803 LttvHooks
*after_tracefile
,
805 LttvHooksByIdChannelArray
*event_by_id_channel
)
807 /* Remove hooks from context. _after hooks are called by remove_hooks. */
808 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
809 lttv_traceset_context_remove_hooks(self
,
814 event_by_id_channel
);
817 /* Subtile modification :
818 * if tracefile has no event at or after the time requested, it is not put in
819 * the queue, as the next read would fail.
821 * Don't forget to empty the traceset pqueue before calling this.
823 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
825 guint i
, nb_tracefile
;
829 LttvTracefileContext
**tfc
;
831 nb_tracefile
= self
->tracefiles
->len
;
833 GTree
*pqueue
= self
->ts_context
->pqueue
;
835 for(i
= 0 ; i
< nb_tracefile
; i
++) {
836 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
838 g_tree_remove(pqueue
, *tfc
);
840 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
841 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
843 if(ret
== 0) { /* not ERANGE especially */
844 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
845 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
846 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
848 (*tfc
)->timestamp
= ltt_time_infinite
;
852 test_time
.tv_sec
= 0;
853 test_time
.tv_nsec
= 0;
854 g_debug("test tree after seek_time");
855 g_tree_foreach(pqueue
, test_tree
, NULL
);
860 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
864 LttvTraceContext
*tc
;
866 //g_tree_destroy(self->pqueue);
867 //self->pqueue = g_tree_new(compare_tracefile);
869 nb_trace
= lttv_traceset_number(self
->ts
);
870 for(i
= 0 ; i
< nb_trace
; i
++) {
871 tc
= self
->traces
[i
];
872 lttv_process_trace_seek_time(tc
, start
);
877 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
878 const LttvTracesetContextPosition
*pos
)
881 /* If a position is set, seek the traceset to this position */
882 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
884 /* Test to see if the traces has been added to the trace set :
885 * It should NEVER happen. Clear all positions if a new trace comes in. */
886 /* FIXME I know this test is not optimal : should keep a number of
887 * tracefiles variable in the traceset.. eventually */
888 guint num_traces
= lttv_traceset_number(self
->ts
);
890 for(i
=0; i
<num_traces
;i
++) {
891 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
893 guint num_tracefiles
= tracefiles
->len
;
894 for(j
=0;j
<num_tracefiles
;j
++)
897 g_assert(tf_count
== pos
->tfcp
->len
);
900 //g_tree_destroy(self->pqueue);
901 //self->pqueue = g_tree_new(compare_tracefile);
903 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
904 LttvTracefileContextPosition
*tfcp
=
905 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
907 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
909 if(tfcp
->used
== TRUE
) {
910 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
912 tfcp
->tfc
->timestamp
=
913 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
914 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
915 ltt_time_infinite
) != 0);
916 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
919 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
924 test_time
.tv_sec
= 0;
925 test_time
.tv_nsec
= 0;
926 g_debug("test tree after seek_position");
927 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
936 #if 0 // pmf: temporary disable
938 find_field(LttEventType
*et
, const GQuark field
)
942 if(field
== 0) return NULL
;
944 f
= ltt_eventtype_field_by_name(et
, field
);
946 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
947 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
948 g_quark_to_string(ltt_eventtype_name(et
)));
955 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
957 return marker_get_info_from_id(th
->mdata
, th
->id
);
960 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
961 GQuark fields
[], LttvHook h
, gpointer hook_data
,
962 GArray
**trace_hooks
)
964 struct marker_info
*info
;
968 struct marker_data
*mdata
;
970 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
971 if (unlikely(!group
|| group
->len
== 0)) {
972 g_info("No channel for marker named %s.%s found",
973 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
977 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
978 info
= marker_get_info_from_name(mdata
, event_name
);
979 if(unlikely(info
== NULL
)) {
980 g_info("No marker named %s.%s found",
981 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
985 init_array_size
= (*trace_hooks
)->len
;
987 /* for each marker with the requested name */
992 struct marker_field
*marker_field
;
994 marker_id
= marker_get_id_from_info(mdata
, info
);
998 tmpth
.channel
= channel_name
;
999 tmpth
.id
= marker_id
;
1000 tmpth
.hook_data
= hook_data
;
1001 tmpth
.fields
= g_ptr_array_new();
1003 /* for each field requested */
1004 for(f
= fields
; f
&& *f
!= 0; f
++) {
1006 for_each_marker_field(marker_field
, info
) {
1007 if(marker_field
->name
== *f
) {
1009 g_ptr_array_add(tmpth
.fields
, marker_field
);
1014 /* Did not find the one of the fields in this instance of the
1015 marker. Print a warning and skip this marker completely.
1016 Still iterate on other markers with same name. */
1017 g_ptr_array_free(tmpth
.fields
, TRUE
);
1018 g_info("Field %s cannot be found in marker %s.%s",
1019 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1020 g_quark_to_string(event_name
));
1024 /* all fields were found: add the tracehook to the array */
1025 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1028 } while(info
!= NULL
);
1030 /* Error if no new trace hook has been added */
1031 if (init_array_size
== (*trace_hooks
)->len
) {
1032 g_info("No marker of name %s.%s has all requested fields",
1033 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1039 void lttv_trace_hook_remove_all(GArray
**th
)
1042 for(i
=0; i
<(*th
)->len
; i
++) {
1043 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1046 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1049 LttvTracesetContextPosition
*
1050 lttv_traceset_context_position_new(const LttvTracesetContext
*self
)
1052 guint num_traces
= lttv_traceset_number(self
->ts
);
1056 for(i
=0; i
<num_traces
;i
++) {
1057 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1059 guint num_tracefiles
= tracefiles
->len
;
1060 for(j
=0;j
<num_tracefiles
;j
++)
1063 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
, 1);
1064 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1065 sizeof(LttvTracefileContextPosition
),
1067 g_array_set_size(pos
->tfcp
, tf_count
);
1068 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1069 LttvTracefileContextPosition
*tfcp
=
1070 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1071 tfcp
->event
= ltt_event_position_new();
1074 pos
->timestamp
= ltt_time_infinite
;
1078 /* Save all positions, the ones with infinite time will have NULL
1080 /* note : a position must be destroyed when a trace is added/removed from a
1082 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1083 LttvTracesetContextPosition
*pos
)
1086 guint num_traces
= lttv_traceset_number(self
->ts
);
1089 pos
->timestamp
= ltt_time_infinite
;
1091 for(i
=0; i
<num_traces
;i
++) {
1092 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1094 guint num_tracefiles
= tracefiles
->len
;
1096 for(j
=0;j
<num_tracefiles
;j
++) {
1097 g_assert(tf_count
< pos
->tfcp
->len
);
1098 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1099 LttvTracefileContext
*, j
);
1100 LttvTracefileContextPosition
*tfcp
=
1101 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1105 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1106 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1107 ltt_event_position(event
, tfcp
->event
);
1108 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1109 pos
->timestamp
= (*tfc
)->timestamp
;
1115 //g_array_append_val(pos->tfc, *tfc);
1116 //g_array_append_val(pos->ep, ep);
1123 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1127 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1128 LttvTracefileContextPosition
*tfcp
=
1129 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1130 g_free(tfcp
->event
);
1134 g_array_free(pos
->tfcp
, TRUE
);
1138 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1139 const LttvTracesetContextPosition
*src
)
1142 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1144 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1146 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1148 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1150 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1152 dest_tfcp
->used
= src_tfcp
->used
;
1153 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1155 if(src_tfcp
->used
) {
1156 ltt_event_position_copy(
1161 dest
->timestamp
= src
->timestamp
;
1164 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1165 const LttvTracesetContextPosition
*pos
)
1170 if(pos
->tfcp
->len
== 0) {
1171 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1174 if(lttv_traceset_number(self
->ts
) == 0)
1177 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1178 LttvTracefileContextPosition
*tfcp
=
1179 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1181 if(tfcp
->used
== FALSE
) {
1182 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1186 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1189 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1191 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1195 if(ret
!= 0) return ret
;
1203 lttv_traceset_context_pos_pos_compare(const LttvTracesetContextPosition
*pos1
,
1204 const LttvTracesetContextPosition
*pos2
)
1209 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1210 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1215 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1218 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1219 LttvTracefileContextPosition
*tfcp1
=
1220 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1222 if(tfcp1
->used
== TRUE
) {
1223 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1224 LttvTracefileContextPosition
*tfcp2
=
1225 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1227 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1228 if(tfcp2
->used
== TRUE
)
1229 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1233 if(ret
!= 0) return ret
;
1238 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1239 LttvTracefileContextPosition
*tfcp2
=
1240 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1242 if(tfcp1
->tfc
== tfcp2
->tfc
)
1243 if(tfcp2
->used
== TRUE
) ret
= 1;
1244 if(ret
!= 0) return ret
;
1253 lttv_traceset_context_position_get_time(const LttvTracesetContextPosition
*pos
)
1255 return pos
->timestamp
;
1259 LttvTracefileContext
*
1260 lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1262 GTree
*pqueue
= self
->pqueue
;
1263 LttvTracefileContext
*tfc
= NULL
;
1265 g_tree_foreach(pqueue
, get_first
, &tfc
);
1270 /* lttv_process_traceset_synchronize_tracefiles
1272 * Use the sync_position field of the trace set context to synchronize each
1273 * tracefile with the previously saved position.
1275 * If no previous position has been saved, it simply does nothing.
1277 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1281 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1282 g_assert_cmpint(retval
, ==, 0);
1288 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1290 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1293 struct seek_back_data
{
1294 guint first_event
; /* Index of the first event in the array : we will always
1295 overwrite at this position : this is a circular array.
1298 guint n
; /* number of events requested */
1299 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1300 LttvFilter
*filter1
;
1301 LttvFilter
*filter2
;
1302 LttvFilter
*filter3
;
1304 check_handler
*check
;
1305 gboolean
*stop_flag
;
1306 guint raw_event_count
;
1309 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1311 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1312 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1313 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1314 LttvTracesetContextPosition
*pos
;
1316 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1318 sd
->raw_event_count
++;
1320 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1321 !lttv_filter_tree_parse(sd
->filter1
->head
,
1322 ltt_tracefile_get_event(tfc
->tf
),
1328 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1329 !lttv_filter_tree_parse(sd
->filter2
->head
,
1330 ltt_tracefile_get_event(tfc
->tf
),
1336 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1337 !lttv_filter_tree_parse(sd
->filter3
->head
,
1338 ltt_tracefile_get_event(tfc
->tf
),
1345 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1348 lttv_traceset_context_position_save(tsc
, pos
);
1350 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1351 else sd
->first_event
++;
1353 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1358 /* Seek back n events back from the current position.
1361 * @self The trace set context
1362 * @n number of events to jump over
1363 * @first_offset The initial offset value used.
1364 * never put first_offset at ltt_time_zero.
1365 * @time_seeker Function pointer of the function to use to seek time :
1366 * either lttv_process_traceset_seek_time
1367 * or lttv_state_traceset_seek_time_closest
1368 * @filter The filter to call.
1370 * Return value : the number of events found (might be lower than the number
1371 * requested if beginning of traceset is reached).
1373 * The first search will go back first_offset and try to find the last n events
1374 * matching the filter. If there are not enough, it will try to go back from the
1375 * new trace point from first_offset*2, and so on, until beginning of trace or n
1378 * Note : this function does not take in account the LttvFilter : use the
1379 * similar function found in state.c instead.
1381 * Note2 : the caller must make sure that the LttvTracesetContext does not
1382 * contain any hook, as process_traceset_middle is used in this routine.
1384 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1385 guint n
, LttTime first_offset
,
1386 seek_time_fct time_seeker
,
1387 check_handler
*check
,
1388 gboolean
*stop_flag
,
1389 LttvFilter
*filter1
,
1390 LttvFilter
*filter2
,
1391 LttvFilter
*filter3
,
1394 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1395 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1398 LttvTracesetContextPosition
*next_iter_end_pos
=
1399 lttv_traceset_context_position_new(self
);
1400 LttvTracesetContextPosition
*end_pos
=
1401 lttv_traceset_context_position_new(self
);
1402 LttvTracesetContextPosition
*saved_pos
=
1403 lttv_traceset_context_position_new(self
);
1406 LttTime time_offset
;
1407 struct seek_back_data sd
;
1408 LttvHooks
*hooks
= lttv_hooks_new();
1412 sd
.events_found
= 0;
1413 sd
.array
= g_ptr_array_sized_new(n
);
1414 sd
.filter1
= filter1
;
1415 sd
.filter2
= filter2
;
1416 sd
.filter3
= filter3
;
1420 sd
.stop_flag
= stop_flag
;
1421 sd
.raw_event_count
= 0;
1422 g_ptr_array_set_size(sd
.array
, n
);
1424 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1427 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1428 lttv_traceset_context_position_save(self
, saved_pos
);
1429 /* Get the current time from which we will offset */
1430 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1431 /* the position saved might be end of traceset... */
1432 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1433 time
= self
->time_span
.end_time
;
1435 time_offset
= first_offset
;
1437 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1439 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1442 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1444 /* We must seek the traceset back to time - time_offset */
1445 /* this time becomes the new reference time */
1446 if(ltt_time_compare(time
, time_offset
) > 0)
1447 time
= ltt_time_sub(time
, time_offset
);
1449 time
= self
->time_span
.start_time
;
1452 time_seeker(self
, time
);
1453 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1454 /* Resync the time in case of a seek_closest */
1455 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1456 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1457 time
= self
->time_span
.end_time
;
1460 /* Process the traceset, calling a hook which adds events
1461 * to the array, overwriting the tail. It changes first_event and
1462 * events_found too. */
1463 /* We would like to have a clean context here : no other hook than our's */
1465 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1466 G_MAXUINT
, end_pos
);
1468 /* stop criteria : - n events found
1469 * - asked_time < beginning of trace */
1470 if(sd
.events_found
< n
) {
1471 if(sd
.first_event
> 0) {
1472 /* Save the first position */
1473 LttvTracesetContextPosition
*pos
=
1474 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1475 lttv_traceset_context_position_copy(saved_pos
, pos
);
1477 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1478 /* Change array size to n - events_found */
1479 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1480 LttvTracesetContextPosition
*pos
=
1481 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1482 lttv_traceset_context_position_destroy(pos
);
1484 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1488 * Did not fill our event list and started before the beginning of the
1489 * trace. There is no hope to fill it then.
1490 * It is OK to compare with trace start time here because we explicitely
1491 * seeked by time (not by position), so we cannot miss multiple event
1492 * happening exactly at trace start.
1494 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) == 0)
1497 } else break; /* Second end criterion : n events found */
1499 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1502 lttv_traceset_context_position_destroy(end_pos
);
1503 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1505 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1507 if(sd
.events_found
>= n
) {
1508 /* Seek the traceset to the first event in the circular array */
1509 LttvTracesetContextPosition
*pos
=
1510 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1512 retval
= lttv_process_traceset_seek_position(self
, pos
);
1513 g_assert_cmpint(retval
, ==, 0);
1515 /* Will seek to the last saved position : in the worst case, it will be the
1516 * original position (if events_found is 0) */
1517 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1518 g_assert_cmpint(retval
, ==, 0);
1521 for(i
=0;i
<sd
.array
->len
;i
++) {
1522 LttvTracesetContextPosition
*pos
=
1523 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1524 lttv_traceset_context_position_destroy(pos
);
1526 g_ptr_array_free(sd
.array
, TRUE
);
1528 lttv_hooks_destroy(hooks
);
1530 lttv_traceset_context_position_destroy(saved_pos
);
1532 return sd
.events_found
;
1536 struct seek_forward_data
{
1537 guint event_count
; /* event counter */
1538 guint n
; /* requested number of events to jump over */
1539 LttvFilter
*filter1
;
1540 LttvFilter
*filter2
;
1541 LttvFilter
*filter3
;
1543 check_handler
*check
;
1544 gboolean
*stop_flag
;
1545 guint raw_event_count
; /* event counter */
1548 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1550 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1551 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1553 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1555 sd
->raw_event_count
++;
1557 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1558 !lttv_filter_tree_parse(sd
->filter1
->head
,
1559 ltt_tracefile_get_event(tfc
->tf
),
1565 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1566 !lttv_filter_tree_parse(sd
->filter2
->head
,
1567 ltt_tracefile_get_event(tfc
->tf
),
1573 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1574 !lttv_filter_tree_parse(sd
->filter3
->head
,
1575 ltt_tracefile_get_event(tfc
->tf
),
1583 if(sd
->event_count
>= sd
->n
)
1588 /* Seek back n events forward from the current position (1 to n)
1589 * 0 is ok too, but it will actually do nothing.
1592 * @self the trace set context
1593 * @n number of events to jump over
1594 * @filter filter to call.
1596 * returns : the number of events jumped over (may be less than requested if end
1597 * of traceset reached) */
1598 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1600 check_handler
*check
,
1601 gboolean
*stop_flag
,
1602 LttvFilter
*filter1
,
1603 LttvFilter
*filter2
,
1604 LttvFilter
*filter3
,
1607 struct seek_forward_data sd
;
1610 sd
.filter1
= filter1
;
1611 sd
.filter2
= filter2
;
1612 sd
.filter3
= filter3
;
1615 sd
.stop_flag
= stop_flag
;
1616 sd
.raw_event_count
= 0;
1618 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1620 LttvHooks
*hooks
= lttv_hooks_new();
1622 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1624 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1626 /* it will end on the end of traceset, or the fact that the
1627 * hook returns TRUE.
1629 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1632 /* Here, our position is either the end of traceset, or the exact position
1633 * after n events : leave it like this. This might be placed on an event that
1634 * will be filtered out, we don't care : all we know is that the following
1635 * event filtered in will be the right one. */
1637 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1639 lttv_hooks_destroy(hooks
);
1641 return sd
.event_count
;