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>
32 #include <babeltrace/context.h>
33 #include <babeltrace/iterator.h>
35 #include <babeltrace/ctf/events.h>
36 #include <babeltrace/ctf/iterator.h>
38 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
42 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
43 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
45 if(likely(trace_a
!= trace_b
)) {
46 comparison
= ltt_time_compare(trace_a
->timestamp
, trace_b
->timestamp
);
47 if(unlikely(comparison
== 0)) {
48 if(trace_a
->index
< trace_b
->index
) comparison
= -1;
49 else if(trace_a
->index
> trace_b
->index
) comparison
= 1;
50 else if(trace_a
->t_context
->index
< trace_b
->t_context
->index
)
52 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
59 typedef struct _LttvTracefileContextPosition
{
60 LttEventPosition
*event
;
61 LttvTracefileContext
*tfc
;
62 gboolean used
; /* Tells if the tfc is at end of traceset position */
63 } LttvTracefileContextPosition
;
66 struct _LttvTracesetContextPosition
{
67 GArray
*tfcp
; /* Array of LttvTracefileContextPosition */
68 LttTime timestamp
; /* Current time at the saved position */
69 /* If ltt_time_infinite : no position is
70 * set, else, a position is set (may be end
71 * of trace, with ep->len == 0) */
74 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
76 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
80 void lttv_context_fini(LttvTracesetContext
*self
)
82 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
87 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
89 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
96 lttv_context_new_trace_context(LttvTracesetContext
*self
)
98 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
102 LttvTracefileContext
*
103 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
105 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
108 /****************************************************************************
109 * lttv_traceset_context_compute_time_span
111 * Keep the time span in sync with on the fly addition and removal of traces
112 * in a trace set. It must be called each time a trace is added/removed from
113 * the traceset. It could be more efficient to call it only once a bunch
114 * of traces are loaded, but the calculation is not long, so it's not
117 * Author : Xang Xiu Yang
118 ***************************************************************************/
119 void lttv_traceset_context_compute_time_span(LttvTracesetContext
*self
,
120 TimeInterval
*time_span
)
122 LttvTraceset
* traceset
= self
->ts
;
123 int numTraces
= lttv_traceset_number(traceset
);
126 LttvTraceContext
*tc
;
129 time_span
->start_time
.tv_sec
= 0;
130 time_span
->start_time
.tv_nsec
= 0;
131 time_span
->end_time
.tv_sec
= 0;
132 time_span
->end_time
.tv_nsec
= 0;
134 for(i
=0; i
<numTraces
;i
++){
135 tc
= self
->traces
[i
];
138 ltt_trace_time_span_get(trace
, &s
, &e
);
139 tc
->time_span
.start_time
= s
;
140 tc
->time_span
.end_time
= e
;
143 time_span
->start_time
= s
;
144 time_span
->end_time
= e
;
146 if(s
.tv_sec
< time_span
->start_time
.tv_sec
147 || (s
.tv_sec
== time_span
->start_time
.tv_sec
148 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
149 time_span
->start_time
= s
;
150 if(e
.tv_sec
> time_span
->end_time
.tv_sec
151 || (e
.tv_sec
== time_span
->end_time
.tv_sec
152 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
153 time_span
->end_time
= e
;
158 static void init_tracefile_context(LttTracefile
*tracefile
,
159 LttvTraceContext
*tc
)
161 LttvTracefileContext
*tfc
;
162 LttvTracesetContext
*tsc
= tc
->ts_context
;
164 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
166 tfc
->index
= tc
->tracefiles
->len
;
167 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
172 tfc
->event
= lttv_hooks_new();
173 tfc
->event_by_id
= lttv_hooks_by_id_new();
174 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
175 tfc
->target_pid
= -1;
180 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
184 LttvTraceContext
*tc
;
186 GData
**tracefiles_groups
;
188 struct compute_tracefile_group_args args
;
190 struct bt_iter_pos begin_pos
;
192 nb_trace
= lttv_traceset_number(ts
);
194 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
195 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
196 self
->ts_a
= lttv_traceset_attribute(ts
);
198 begin_pos
.type
= BT_SEEK_BEGIN
;
200 self
->iter
= bt_ctf_iter_create(lttv_traceset_get_context(ts
),
203 self
->event_hooks
= lttv_hooks_new();
205 for(i
= 0 ; i
< nb_trace
; i
++) {
206 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
207 self
->traces
[i
] = tc
;
209 tc
->ts_context
= self
;
211 tc
->vt
= lttv_traceset_get(ts
, i
);
212 tc
->t
= lttv_trace(tc
->vt
);
213 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
214 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
215 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
216 sizeof(LttvTracefileContext
*), 10);
218 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
219 if(tracefiles_groups
!= NULL
) {
220 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
223 g_datalist_foreach(tracefiles_groups
,
224 (GDataForeachFunc
)compute_tracefile_group
,
231 self
->sync_position
= lttv_traceset_context_position_new(self
);
232 self
->pqueue
= g_tree_new(compare_tracefile
);
233 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
234 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
239 void fini(LttvTracesetContext
*self
)
241 guint i
, j
, nb_trace
, nb_tracefile
;
243 LttvTraceContext
*tc
;
245 LttvTracefileContext
**tfc
;
247 LttvTraceset
*ts
= self
->ts
;
249 g_tree_destroy(self
->pqueue
);
250 g_object_unref(self
->a
);
251 lttv_traceset_context_position_destroy(self
->sync_position
);
253 nb_trace
= lttv_traceset_number(ts
);
255 for(i
= 0 ; i
< nb_trace
; i
++) {
256 tc
= self
->traces
[i
];
258 g_object_unref(tc
->a
);
260 nb_tracefile
= tc
->tracefiles
->len
;
262 for(j
= 0 ; j
< nb_tracefile
; j
++) {
263 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
264 lttv_hooks_destroy((*tfc
)->event
);
265 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
266 g_object_unref((*tfc
)->a
);
267 g_object_unref(*tfc
);
269 g_array_free(tc
->tracefiles
, TRUE
);
272 g_free(self
->traces
);
276 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
277 LttvHooks
*before_traceset
,
278 LttvHooks
*before_trace
,
279 LttvHooks
*before_tracefile
,
281 LttvHooksByIdChannelArray
*event_by_id_channel
)
283 LttvTraceset
*ts
= self
->ts
;
287 LttvTraceContext
*tc
;
289 lttv_hooks_call(before_traceset
, self
);
291 lttv_hooks_add_list(self
->event_hooks
, event
);
293 nb_trace
= lttv_traceset_number(ts
);
295 for(i
= 0 ; i
< nb_trace
; i
++) {
296 tc
= self
->traces
[i
];
297 lttv_trace_context_add_hooks(tc
,
301 event_by_id_channel
);
306 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
307 LttvHooks
*after_traceset
,
308 LttvHooks
*after_trace
,
309 LttvHooks
*after_tracefile
,
311 LttvHooksByIdChannelArray
*event_by_id_channel
)
314 LttvTraceset
*ts
= self
->ts
;
318 LttvTraceContext
*tc
;
320 nb_trace
= lttv_traceset_number(ts
);
322 for(i
= 0 ; i
< nb_trace
; i
++) {
323 tc
= self
->traces
[i
];
324 lttv_trace_context_remove_hooks(tc
,
328 event_by_id_channel
);
331 lttv_hooks_call(after_traceset
, self
);
336 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
337 LttvHooks
*before_trace
,
338 LttvHooks
*before_tracefile
,
340 LttvHooksByIdChannelArray
*event_by_id_channel
)
342 guint i
, j
, nb_tracefile
;
343 LttvTracefileContext
**tfc
;
346 lttv_hooks_call(before_trace
, self
);
348 nb_tracefile
= self
->tracefiles
->len
;
350 for(i
= 0 ; i
< nb_tracefile
; i
++) {
351 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
353 lttv_tracefile_context_add_hooks(*tfc
,
357 if (event_by_id_channel
) {
358 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
359 LttvHooksByIdChannel
*hooks
=
360 &g_array_index(event_by_id_channel
->array
,
361 LttvHooksByIdChannel
, j
);
362 if (tf
->name
== hooks
->channel
)
363 lttv_tracefile_context_add_hooks(*tfc
,
374 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
375 LttvHooks
*after_trace
,
376 LttvHooks
*after_tracefile
,
378 LttvHooksByIdChannelArray
*event_by_id_channel
)
380 guint i
, j
, nb_tracefile
;
381 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
);
389 if (event_by_id_channel
) {
390 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
391 LttvHooksByIdChannel
*hooks
=
392 &g_array_index(event_by_id_channel
->array
,
393 LttvHooksByIdChannel
, j
);
394 if (tf
->name
== hooks
->channel
)
395 lttv_tracefile_context_remove_hooks(*tfc
,
401 lttv_tracefile_context_remove_hooks(*tfc
,
408 lttv_hooks_call(after_trace
, self
);
411 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
412 LttvHooks
*before_tracefile
,
414 LttvHooksById
*event_by_id
)
419 lttv_hooks_call(before_tracefile
, self
);
420 lttv_hooks_add_list(self
->event
, event
);
421 if(event_by_id
!= NULL
) {
422 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
423 index
= g_array_index(event_by_id
->array
, guint
, i
);
424 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
425 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
430 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
431 LttvHooks
*after_tracefile
,
433 LttvHooksById
*event_by_id
)
439 lttv_hooks_remove_list(self
->event
, event
);
440 if(event_by_id
!= NULL
) {
441 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
442 index
= g_array_index(event_by_id
->array
, guint
, i
);
443 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
445 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
449 lttv_hooks_call(after_tracefile
, self
);
452 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
454 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
458 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
460 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
464 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
466 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
470 static void traceset_context_instance_init(GTypeInstance
*instance
,
473 /* Be careful of anything which would not work well with shallow copies */
477 static void traceset_context_finalize(LttvTracesetContext
*self
)
479 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
480 ->finalize(G_OBJECT(self
));
484 static void traceset_context_class_init(LttvTracesetContextClass
*klass
)
486 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
488 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
491 klass
->new_traceset_context
= new_traceset_context
;
492 klass
->new_trace_context
= new_trace_context
;
493 klass
->new_tracefile_context
= new_tracefile_context
;
497 GType
lttv_traceset_context_get_type(void)
499 static GType type
= 0;
501 static const GTypeInfo info
= {
502 sizeof (LttvTracesetContextClass
),
503 NULL
, /* base_init */
504 NULL
, /* base_finalize */
505 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
506 NULL
, /* class_finalize */
507 NULL
, /* class_data */
508 sizeof (LttvTracesetContext
),
510 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
511 NULL
/* Value handling */
514 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
522 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
524 /* Be careful of anything which would not work well with shallow copies */
528 static void trace_context_finalize (LttvTraceContext
*self
)
530 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
531 finalize(G_OBJECT(self
));
535 static void trace_context_class_init (LttvTraceContextClass
*klass
)
537 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
539 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
543 GType
lttv_trace_context_get_type(void)
545 static GType type
= 0;
547 static const GTypeInfo info
= {
548 sizeof (LttvTraceContextClass
),
549 NULL
, /* base_init */
550 NULL
, /* base_finalize */
551 (GClassInitFunc
) trace_context_class_init
, /* class_init */
552 NULL
, /* class_finalize */
553 NULL
, /* class_data */
554 sizeof (LttvTraceContext
),
556 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
557 NULL
/* Value handling */
560 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
567 static void tracefile_context_instance_init (GTypeInstance
*instance
,
570 /* Be careful of anything which would not work well with shallow copies */
574 static void tracefile_context_finalize (LttvTracefileContext
*self
)
576 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
577 ->finalize(G_OBJECT(self
));
581 static void tracefile_context_class_init (LttvTracefileContextClass
*klass
)
583 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
585 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
589 GType
lttv_tracefile_context_get_type(void)
591 static GType type
= 0;
593 static const GTypeInfo info
= {
594 sizeof (LttvTracefileContextClass
),
595 NULL
, /* base_init */
596 NULL
, /* base_finalize */
597 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
598 NULL
, /* class_finalize */
599 NULL
, /* class_data */
600 sizeof (LttvTracefileContext
),
602 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
603 NULL
/* Value handling */
606 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
614 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
615 g_assert(key
== value
);
616 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
621 // Test to see if pqueue is traversed in the right order.
622 static LttTime test_time
;
624 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
626 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
628 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
629 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
630 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
631 tfc
->index
, tfc
->t_context
->index
);
633 if(user_data
!= NULL
) {
634 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
635 g_assert(compare_tracefile(user_data
, value
) == 0);
637 g_assert(compare_tracefile(user_data
, value
) != 0);
639 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
640 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
641 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
644 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
651 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
652 LttvHooks
*before_traceset
,
653 LttvHooks
*before_trace
,
654 LttvHooks
*before_tracefile
,
656 LttvHooksByIdChannelArray
*event_by_id_channel
)
659 /* simply add hooks in context. _before hooks are called by add_hooks. */
660 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
661 lttv_traceset_context_add_hooks(self
,
666 event_by_id_channel
);
670 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
672 /* Note : a _middle must be preceded from a _seek or another middle */
673 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
676 const LttvTracesetContextPosition
*end_position
)
681 struct bt_ctf_event
*event
;
685 if((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) {
689 if((event
= bt_ctf_iter_read_event(self
->iter
)) != NULL
) {
693 /* TODO ybrosseau: encapsulate the event into something */
694 lttv_hooks_call(self
->event_hooks
, event
);
696 if(bt_iter_next(bt_ctf_get_iter(self
->iter
)) < 0) {
697 printf("ERROR NEXT\n");
712 GTree
*pqueue
= self
->pqueue
;
714 LttvTracefileContext
*tfc
;
720 gboolean is_live
= FALSE
; /* set this flag if we detect a live trace */
724 //enum read_state last_read_state = LAST_NONE;
726 gint last_ret
= 0; /* return value of the last hook list called */
728 /* Get the next event from the pqueue, call its hooks,
729 reinsert in the pqueue the following event from the same tracefile
730 unless the tracefile is finished or the event is later than the
735 g_tree_foreach(pqueue
, get_first
, &tfc
);
736 /* End of traceset : tfc is NULL */
737 if(unlikely(tfc
== NULL
))
743 * - the maximum number of events specified?
744 * - the end position ?
746 * then the read is finished. We leave the queue in the same state and
749 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0) {
753 if(unlikely(last_ret
== TRUE
754 || ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
))
755 || (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
757 || ltt_time_compare(end
, tfc
->timestamp
) <= 0))
762 /* Get the tracefile with an event for the smallest time found. If two
763 or more tracefiles have events for the same time, hope that lookup
764 and remove are consistent. */
767 test_time
.tv_sec
= 0;
768 test_time
.tv_nsec
= 0;
769 g_debug("test tree before remove");
770 g_tree_foreach(pqueue
, test_tree
, tfc
);
772 g_tree_remove(pqueue
, tfc
);
775 test_time
.tv_sec
= 0;
776 test_time
.tv_nsec
= 0;
777 g_debug("test tree after remove");
778 g_tree_foreach(pqueue
, test_tree
, tfc
);
782 e
= ltt_tracefile_get_event(tfc
->tf
);
784 //if(last_read_state != LAST_EMPTY) {
785 /* Only call hooks if the last read has given an event or if we are at the
786 * first pass (not if last read returned end of tracefile) */
789 tfc
->target_pid
= -1; /* unset target PID */
791 * return values : 0 : continue read, 1 : go to next position and stop read,
792 * 2 : stay at the current position and stop read */
793 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
794 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
797 /* This is buggy : it won't work well with state computation */
798 if(unlikely(last_ret
== 2)) {
799 /* This is a case where we want to stay at this position and stop read. */
800 g_tree_insert(pqueue
, tfc
, tfc
);
805 read_ret
= ltt_tracefile_read(tfc
->tf
);
808 if(likely(!read_ret
)) {
809 //g_debug("An event is ready");
810 tfc
->timestamp
= ltt_event_time(e
);
813 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
814 g_tree_insert(pqueue
, tfc
, tfc
);
815 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0)
821 test_time
.tv_sec
= 0;
822 test_time
.tv_nsec
= 0;
823 g_debug("test tree after event ready");
824 g_tree_foreach(pqueue
, test_tree
, NULL
);
827 //last_read_state = LAST_OK;
829 tfc
->timestamp
= ltt_time_infinite
;
831 if(read_ret
== ERANGE
) {
832 // last_read_state = LAST_EMPTY;
833 g_debug("End of trace");
835 g_error("Error happened in lttv_process_traceset_middle");
839 if (unlikely((count
== 0) && is_live
)) {
845 #endif /* BABEL_CLEANUP */
849 void lttv_process_traceset_end(LttvTracesetContext
*self
,
850 LttvHooks
*after_traceset
,
851 LttvHooks
*after_trace
,
852 LttvHooks
*after_tracefile
,
854 LttvHooksByIdChannelArray
*event_by_id_channel
)
856 /* Remove hooks from context. _after hooks are called by remove_hooks. */
857 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
858 lttv_traceset_context_remove_hooks(self
,
863 event_by_id_channel
);
866 /* Subtile modification :
867 * if tracefile has no event at or after the time requested, it is not put in
868 * the queue, as the next read would fail.
870 * Don't forget to empty the traceset pqueue before calling this.
872 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
877 guint i
, nb_tracefile
;
881 LttvTracefileContext
**tfc
;
883 nb_tracefile
= self
->tracefiles
->len
;
885 GTree
*pqueue
= self
->ts_context
->pqueue
;
887 for(i
= 0 ; i
< nb_tracefile
; i
++) {
888 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
890 g_tree_remove(pqueue
, *tfc
);
892 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
893 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
895 if(ret
== 0) { /* not ERANGE especially */
896 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
897 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
898 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
900 (*tfc
)->timestamp
= ltt_time_infinite
;
904 test_time
.tv_sec
= 0;
905 test_time
.tv_nsec
= 0;
906 g_debug("test tree after seek_time");
907 g_tree_foreach(pqueue
, test_tree
, NULL
);
912 /****************************************************************************
913 * lttv_process_trace_update
915 * process the changes that occur in the trace. Use a regular file polling to
916 * monitor the tracefile.
918 * Return the number of tracefile updated
919 ***************************************************************************/
920 guint
lttv_process_trace_update(LttvTraceContext
*self
)
923 guint nb_tracefile
= 0;
925 LttTracefile
*tf
= 0;
926 LttvTracefileContext
**tfc
;
928 /* Skip non live traces */
929 if(self
->t
->is_live
) {
931 nb_tracefile
= ltt_trace_update(self
->t
);
933 /* Recreate the pqueue following an update*/
934 GTree
*pqueue
= self
->ts_context
->pqueue
;
936 for(i
= 0 ; i
< self
->tracefiles
->len
; i
++) {
937 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
939 if(g_tree_remove(pqueue
, *tfc
) == FALSE
) {
940 if(tf
->buf_index
!= NULL
) {
942 if(ltt_tracefile_read(tf
) == 0) {
944 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
945 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
950 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
956 //Update self time span
957 self
->time_span
.end_time
= LTT_TIME_MAX(self
->t
->live_safe_timestamp
,
958 self
->time_span
.end_time
);
959 //Update self tscontext time span
960 self
->ts_context
->time_span
.end_time
= LTT_TIME_MAX(self
->time_span
.end_time
,
961 self
->ts_context
->time_span
.end_time
);
967 /****************************************************************************
968 * lttv_process_traceset_update
970 * process the changes that occur in the traceset.
972 * Return the number of file presently monitor(open for writting). If 0, the
973 * current traceset probably received all the data.
974 ***************************************************************************/
975 guint
lttv_process_traceset_update(LttvTracesetContext
*self
)
979 guint open_counter
= 0;
981 nb_trace
= lttv_traceset_number(self
->ts
);
983 for(i
= 0 ; i
< nb_trace
; i
++) {
984 open_counter
+= lttv_process_trace_update(self
->traces
[i
]);
989 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
991 #ifdef WAIT_FOR_BABELTRACE_FIX_SEEK_ZERO
992 struct bt_iter_pos seekpos
;
994 seekpos
.type
= BT_SEEK_TIME
;
995 seekpos
.u
.seek_time
= ltt_time_to_uint64(start
);
996 ret
= bt_iter_set_pos(bt_ctf_get_iter(self
->iter
), &seekpos
);
998 printf("Seek by time error: %s,\n",strerror(-ret
));
1001 #warning Seek time disabled because of babeltrace bugs
1004 #ifdef BABEL_CLEANUP
1009 LttvTraceContext
*tc
;
1011 //g_tree_destroy(self->pqueue);
1012 //self->pqueue = g_tree_new(compare_tracefile);
1014 nb_trace
= lttv_traceset_number(self
->ts
);
1015 for(i
= 0 ; i
< nb_trace
; i
++) {
1016 tc
= self
->traces
[i
];
1017 lttv_process_trace_seek_time(tc
, start
);
1023 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
1024 const LttvTracesetContextPosition
*pos
)
1027 /* If a position is set, seek the traceset to this position */
1028 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
1030 /* Test to see if the traces has been added to the trace set :
1031 * It should NEVER happen. Clear all positions if a new trace comes in. */
1032 /* FIXME I know this test is not optimal : should keep a number of
1033 * tracefiles variable in the traceset.. eventually */
1034 guint num_traces
= lttv_traceset_number(self
->ts
);
1036 for(i
=0; i
<num_traces
;i
++) {
1037 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1039 guint num_tracefiles
= tracefiles
->len
;
1040 for(j
=0;j
<num_tracefiles
;j
++)
1043 g_assert(tf_count
== pos
->tfcp
->len
);
1046 //g_tree_destroy(self->pqueue);
1047 //self->pqueue = g_tree_new(compare_tracefile);
1049 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
1050 LttvTracefileContextPosition
*tfcp
=
1051 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1053 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
1055 if(tfcp
->used
== TRUE
) {
1056 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
1058 tfcp
->tfc
->timestamp
=
1059 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
1060 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
1061 ltt_time_infinite
) != 0);
1062 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
1065 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
1070 test_time
.tv_sec
= 0;
1071 test_time
.tv_nsec
= 0;
1072 g_debug("test tree after seek_position");
1073 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
1082 #if 0 // pmf: temporary disable
1084 find_field(LttEventType
*et
, const GQuark field
)
1088 if(field
== 0) return NULL
;
1090 f
= ltt_eventtype_field_by_name(et
, field
);
1092 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
1093 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
1094 g_quark_to_string(ltt_eventtype_name(et
)));
1101 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
1103 return marker_get_info_from_id(th
->mdata
, th
->id
);
1106 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
1107 GQuark fields
[], LttvHook h
, gpointer hook_data
,
1108 GArray
**trace_hooks
)
1110 struct marker_info
*info
;
1112 int init_array_size
;
1114 struct marker_data
*mdata
;
1116 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
1117 if (unlikely(!group
|| group
->len
== 0)) {
1118 g_info("No channel for marker named %s.%s found",
1119 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1123 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
1124 info
= marker_get_info_from_name(mdata
, event_name
);
1125 if(unlikely(info
== NULL
)) {
1126 g_info("No marker named %s.%s found",
1127 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1131 init_array_size
= (*trace_hooks
)->len
;
1133 /* for each marker with the requested name */
1135 LttvTraceHook tmpth
;
1138 struct marker_field
*marker_field
;
1140 marker_id
= marker_get_id_from_info(mdata
, info
);
1143 tmpth
.mdata
= mdata
;
1144 tmpth
.channel
= channel_name
;
1145 tmpth
.id
= marker_id
;
1146 tmpth
.hook_data
= hook_data
;
1147 tmpth
.fields
= g_ptr_array_new();
1149 /* for each field requested */
1150 for(f
= fields
; f
&& *f
!= 0; f
++) {
1152 for_each_marker_field(marker_field
, info
) {
1153 if(marker_field
->name
== *f
) {
1155 g_ptr_array_add(tmpth
.fields
, marker_field
);
1160 /* Did not find the one of the fields in this instance of the
1161 marker. Print a warning and skip this marker completely.
1162 Still iterate on other markers with same name. */
1163 g_ptr_array_free(tmpth
.fields
, TRUE
);
1164 g_info("Field %s cannot be found in marker %s.%s",
1165 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1166 g_quark_to_string(event_name
));
1170 /* all fields were found: add the tracehook to the array */
1171 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1174 } while(info
!= NULL
);
1176 /* Error if no new trace hook has been added */
1177 if (init_array_size
== (*trace_hooks
)->len
) {
1178 g_info("No marker of name %s.%s has all requested fields",
1179 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1185 void lttv_trace_hook_remove_all(GArray
**th
)
1188 for(i
=0; i
<(*th
)->len
; i
++) {
1189 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1192 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1195 LttvTracesetContextPosition
*
1196 lttv_traceset_context_position_new(const LttvTracesetContext
*self
)
1198 guint num_traces
= lttv_traceset_number(self
->ts
);
1202 for(i
=0; i
<num_traces
;i
++) {
1203 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1205 guint num_tracefiles
= tracefiles
->len
;
1206 for(j
=0;j
<num_tracefiles
;j
++)
1209 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
, 1);
1210 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1211 sizeof(LttvTracefileContextPosition
),
1213 g_array_set_size(pos
->tfcp
, tf_count
);
1214 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1215 LttvTracefileContextPosition
*tfcp
=
1216 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1217 tfcp
->event
= ltt_event_position_new();
1220 pos
->timestamp
= ltt_time_infinite
;
1224 /* Save all positions, the ones with infinite time will have NULL
1226 /* note : a position must be destroyed when a trace is added/removed from a
1228 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1229 LttvTracesetContextPosition
*pos
)
1232 guint num_traces
= lttv_traceset_number(self
->ts
);
1235 pos
->timestamp
= ltt_time_infinite
;
1237 for(i
=0; i
<num_traces
;i
++) {
1238 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1240 guint num_tracefiles
= tracefiles
->len
;
1242 for(j
=0;j
<num_tracefiles
;j
++) {
1243 g_assert(tf_count
< pos
->tfcp
->len
);
1244 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1245 LttvTracefileContext
*, j
);
1246 LttvTracefileContextPosition
*tfcp
=
1247 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1251 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1252 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1253 ltt_event_position(event
, tfcp
->event
);
1254 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1255 pos
->timestamp
= (*tfc
)->timestamp
;
1261 //g_array_append_val(pos->tfc, *tfc);
1262 //g_array_append_val(pos->ep, ep);
1269 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1273 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1274 LttvTracefileContextPosition
*tfcp
=
1275 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1276 g_free(tfcp
->event
);
1280 g_array_free(pos
->tfcp
, TRUE
);
1284 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1285 const LttvTracesetContextPosition
*src
)
1288 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1290 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1292 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1294 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1296 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1298 dest_tfcp
->used
= src_tfcp
->used
;
1299 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1301 if(src_tfcp
->used
) {
1302 ltt_event_position_copy(
1307 dest
->timestamp
= src
->timestamp
;
1310 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1311 const LttvTracesetContextPosition
*pos
)
1316 if(pos
->tfcp
->len
== 0) {
1317 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1320 if(lttv_traceset_number(self
->ts
) == 0)
1323 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1324 LttvTracefileContextPosition
*tfcp
=
1325 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1327 if(tfcp
->used
== FALSE
) {
1328 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1332 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1335 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1337 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1341 if(ret
!= 0) return ret
;
1349 lttv_traceset_context_pos_pos_compare(const LttvTracesetContextPosition
*pos1
,
1350 const LttvTracesetContextPosition
*pos2
)
1355 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1356 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1361 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1364 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1365 LttvTracefileContextPosition
*tfcp1
=
1366 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1368 if(tfcp1
->used
== TRUE
) {
1369 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1370 LttvTracefileContextPosition
*tfcp2
=
1371 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1373 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1374 if(tfcp2
->used
== TRUE
)
1375 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1379 if(ret
!= 0) return ret
;
1384 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1385 LttvTracefileContextPosition
*tfcp2
=
1386 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1388 if(tfcp1
->tfc
== tfcp2
->tfc
)
1389 if(tfcp2
->used
== TRUE
) ret
= 1;
1390 if(ret
!= 0) return ret
;
1399 lttv_traceset_context_position_get_time(const LttvTracesetContextPosition
*pos
)
1401 return pos
->timestamp
;
1405 LttvTracefileContext
*
1406 lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1408 GTree
*pqueue
= self
->pqueue
;
1409 LttvTracefileContext
*tfc
= NULL
;
1411 g_tree_foreach(pqueue
, get_first
, &tfc
);
1416 /* lttv_process_traceset_synchronize_tracefiles
1418 * Use the sync_position field of the trace set context to synchronize each
1419 * tracefile with the previously saved position.
1421 * If no previous position has been saved, it simply does nothing.
1423 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1427 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1428 g_assert_cmpint(retval
, ==, 0);
1434 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1436 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1439 struct seek_back_data
{
1440 guint first_event
; /* Index of the first event in the array : we will always
1441 overwrite at this position : this is a circular array.
1444 guint n
; /* number of events requested */
1445 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1446 LttvFilter
*filter1
;
1447 LttvFilter
*filter2
;
1448 LttvFilter
*filter3
;
1450 check_handler
*check
;
1451 gboolean
*stop_flag
;
1452 guint raw_event_count
;
1455 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1457 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1458 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1459 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1460 LttvTracesetContextPosition
*pos
;
1462 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1464 sd
->raw_event_count
++;
1466 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1467 !lttv_filter_tree_parse(sd
->filter1
->head
,
1468 ltt_tracefile_get_event(tfc
->tf
),
1474 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1475 !lttv_filter_tree_parse(sd
->filter2
->head
,
1476 ltt_tracefile_get_event(tfc
->tf
),
1482 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1483 !lttv_filter_tree_parse(sd
->filter3
->head
,
1484 ltt_tracefile_get_event(tfc
->tf
),
1491 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1494 lttv_traceset_context_position_save(tsc
, pos
);
1496 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1497 else sd
->first_event
++;
1499 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1504 /* Seek back n events back from the current position.
1507 * @self The trace set context
1508 * @n number of events to jump over
1509 * @first_offset The initial offset value used.
1510 * never put first_offset at ltt_time_zero.
1511 * @time_seeker Function pointer of the function to use to seek time :
1512 * either lttv_process_traceset_seek_time
1513 * or lttv_state_traceset_seek_time_closest
1514 * @filter The filter to call.
1516 * Return value : the number of events found (might be lower than the number
1517 * requested if beginning of traceset is reached).
1519 * The first search will go back first_offset and try to find the last n events
1520 * matching the filter. If there are not enough, it will try to go back from the
1521 * new trace point from first_offset*2, and so on, until beginning of trace or n
1524 * Note : this function does not take in account the LttvFilter : use the
1525 * similar function found in state.c instead.
1527 * Note2 : the caller must make sure that the LttvTracesetContext does not
1528 * contain any hook, as process_traceset_middle is used in this routine.
1530 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1531 guint n
, LttTime first_offset
,
1532 seek_time_fct time_seeker
,
1533 check_handler
*check
,
1534 gboolean
*stop_flag
,
1535 LttvFilter
*filter1
,
1536 LttvFilter
*filter2
,
1537 LttvFilter
*filter3
,
1540 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1541 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1544 LttvTracesetContextPosition
*next_iter_end_pos
=
1545 lttv_traceset_context_position_new(self
);
1546 LttvTracesetContextPosition
*end_pos
=
1547 lttv_traceset_context_position_new(self
);
1548 LttvTracesetContextPosition
*saved_pos
=
1549 lttv_traceset_context_position_new(self
);
1552 LttTime time_offset
;
1553 struct seek_back_data sd
;
1554 LttvHooks
*hooks
= lttv_hooks_new();
1558 sd
.events_found
= 0;
1559 sd
.array
= g_ptr_array_sized_new(n
);
1560 sd
.filter1
= filter1
;
1561 sd
.filter2
= filter2
;
1562 sd
.filter3
= filter3
;
1566 sd
.stop_flag
= stop_flag
;
1567 sd
.raw_event_count
= 0;
1568 g_ptr_array_set_size(sd
.array
, n
);
1570 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1573 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1574 lttv_traceset_context_position_save(self
, saved_pos
);
1575 /* Get the current time from which we will offset */
1576 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1577 /* the position saved might be end of traceset... */
1578 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1579 time
= self
->time_span
.end_time
;
1581 time_offset
= first_offset
;
1583 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1585 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1588 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1590 /* We must seek the traceset back to time - time_offset */
1591 /* this time becomes the new reference time */
1592 if(ltt_time_compare(time
, time_offset
) > 0)
1593 time
= ltt_time_sub(time
, time_offset
);
1595 time
= self
->time_span
.start_time
;
1598 time_seeker(self
, time
);
1599 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1600 /* Resync the time in case of a seek_closest */
1601 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1602 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1603 time
= self
->time_span
.end_time
;
1606 /* Process the traceset, calling a hook which adds events
1607 * to the array, overwriting the tail. It changes first_event and
1608 * events_found too. */
1609 /* We would like to have a clean context here : no other hook than our's */
1611 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1612 G_MAXUINT
, end_pos
);
1614 /* stop criteria : - n events found
1615 * - asked_time < beginning of trace */
1616 if(sd
.events_found
< n
) {
1617 if(sd
.first_event
> 0) {
1618 /* Save the first position */
1619 LttvTracesetContextPosition
*pos
=
1620 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1621 lttv_traceset_context_position_copy(saved_pos
, pos
);
1623 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1624 /* Change array size to n - events_found */
1625 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1626 LttvTracesetContextPosition
*pos
=
1627 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1628 lttv_traceset_context_position_destroy(pos
);
1630 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1634 * Did not fill our event list and started before the beginning of the
1635 * trace. There is no hope to fill it then.
1636 * It is OK to compare with trace start time here because we explicitely
1637 * seeked by time (not by position), so we cannot miss multiple event
1638 * happening exactly at trace start.
1640 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) == 0)
1643 } else break; /* Second end criterion : n events found */
1645 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1648 lttv_traceset_context_position_destroy(end_pos
);
1649 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1651 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1653 if(sd
.events_found
>= n
) {
1654 /* Seek the traceset to the first event in the circular array */
1655 LttvTracesetContextPosition
*pos
=
1656 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1658 retval
= lttv_process_traceset_seek_position(self
, pos
);
1659 g_assert_cmpint(retval
, ==, 0);
1661 /* Will seek to the last saved position : in the worst case, it will be the
1662 * original position (if events_found is 0) */
1663 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1664 g_assert_cmpint(retval
, ==, 0);
1667 for(i
=0;i
<sd
.array
->len
;i
++) {
1668 LttvTracesetContextPosition
*pos
=
1669 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1670 lttv_traceset_context_position_destroy(pos
);
1672 g_ptr_array_free(sd
.array
, TRUE
);
1674 lttv_hooks_destroy(hooks
);
1676 lttv_traceset_context_position_destroy(saved_pos
);
1678 return sd
.events_found
;
1682 struct seek_forward_data
{
1683 guint event_count
; /* event counter */
1684 guint n
; /* requested number of events to jump over */
1685 LttvFilter
*filter1
;
1686 LttvFilter
*filter2
;
1687 LttvFilter
*filter3
;
1689 check_handler
*check
;
1690 gboolean
*stop_flag
;
1691 guint raw_event_count
; /* event counter */
1694 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1696 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1697 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1699 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1701 sd
->raw_event_count
++;
1703 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1704 !lttv_filter_tree_parse(sd
->filter1
->head
,
1705 ltt_tracefile_get_event(tfc
->tf
),
1711 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1712 !lttv_filter_tree_parse(sd
->filter2
->head
,
1713 ltt_tracefile_get_event(tfc
->tf
),
1719 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1720 !lttv_filter_tree_parse(sd
->filter3
->head
,
1721 ltt_tracefile_get_event(tfc
->tf
),
1729 if(sd
->event_count
>= sd
->n
)
1734 /* Seek back n events forward from the current position (1 to n)
1735 * 0 is ok too, but it will actually do nothing.
1738 * @self the trace set context
1739 * @n number of events to jump over
1740 * @filter filter to call.
1742 * returns : the number of events jumped over (may be less than requested if end
1743 * of traceset reached) */
1744 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1746 check_handler
*check
,
1747 gboolean
*stop_flag
,
1748 LttvFilter
*filter1
,
1749 LttvFilter
*filter2
,
1750 LttvFilter
*filter3
,
1753 struct seek_forward_data sd
;
1756 sd
.filter1
= filter1
;
1757 sd
.filter2
= filter2
;
1758 sd
.filter3
= filter3
;
1761 sd
.stop_flag
= stop_flag
;
1762 sd
.raw_event_count
= 0;
1764 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1766 LttvHooks
*hooks
= lttv_hooks_new();
1768 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1770 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1772 /* it will end on the end of traceset, or the fact that the
1773 * hook returns TRUE.
1775 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1778 /* Here, our position is either the end of traceset, or the exact position
1779 * after n events : leave it like this. This might be placed on an event that
1780 * will be filtered out, we don't care : all we know is that the following
1781 * event filtered in will be the right one. */
1783 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1785 lttv_hooks_destroy(hooks
);
1787 return sd
.event_count
;