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 #include <lttv/event.h>
33 #include <babeltrace/context.h>
34 #include <babeltrace/iterator.h>
36 #include <babeltrace/ctf/events.h>
37 #include <babeltrace/ctf/iterator.h>
39 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
43 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
44 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
46 if(likely(trace_a
!= trace_b
)) {
47 comparison
= ltt_time_compare(trace_a
->timestamp
, trace_b
->timestamp
);
48 if(unlikely(comparison
== 0)) {
49 if(trace_a
->index
< trace_b
->index
) comparison
= -1;
50 else if(trace_a
->index
> trace_b
->index
) comparison
= 1;
51 else if(trace_a
->t_context
->index
< trace_b
->t_context
->index
)
53 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
60 typedef struct _LttvTracefileContextPosition
{
61 LttEventPosition
*event
;
62 LttvTracefileContext
*tfc
;
63 gboolean used
; /* Tells if the tfc is at end of traceset position */
64 } LttvTracefileContextPosition
;
67 struct _LttvTracesetContextPosition
{
68 GArray
*tfcp
; /* Array of LttvTracefileContextPosition */
69 LttTime timestamp
; /* Current time at the saved position */
70 /* If ltt_time_infinite : no position is
71 * set, else, a position is set (may be end
72 * of trace, with ep->len == 0) */
75 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
77 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
81 void lttv_context_fini(LttvTracesetContext
*self
)
83 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
88 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
90 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
97 lttv_context_new_trace_context(LttvTracesetContext
*self
)
99 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
103 LttvTracefileContext
*
104 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
106 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
109 /****************************************************************************
110 * lttv_traceset_context_compute_time_span
112 * Keep the time span in sync with on the fly addition and removal of traces
113 * in a trace set. It must be called each time a trace is added/removed from
114 * the traceset. It could be more efficient to call it only once a bunch
115 * of traces are loaded, but the calculation is not long, so it's not
118 * Author : Xang Xiu Yang
119 ***************************************************************************/
120 void lttv_traceset_context_compute_time_span(LttvTracesetContext
*self
,
121 TimeInterval
*time_span
)
123 //todo mdenis: adapt to babeltrace
125 LttvTraceset
* traceset
= self
->ts
;
126 int numTraces
= lttv_traceset_number(traceset
);
129 LttvTraceContext
*tc
;
132 time_span
->start_time
.tv_sec
= 0;
133 time_span
->start_time
.tv_nsec
= 0;
134 time_span
->end_time
.tv_sec
= 0;
135 time_span
->end_time
.tv_nsec
= 0;
137 for(i
=0; i
<numTraces
;i
++){
138 tc
= self
->traces
[i
];
142 ltt_trace_time_span_get(trace
, &s
, &e
);
143 tc
->time_span
.start_time
= s
;
144 tc
->time_span
.end_time
= e
;
147 time_span
->start_time
= s
;
148 time_span
->end_time
= e
;
150 if(s
.tv_sec
< time_span
->start_time
.tv_sec
151 || (s
.tv_sec
== time_span
->start_time
.tv_sec
152 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
153 time_span
->start_time
= s
;
154 if(e
.tv_sec
> time_span
->end_time
.tv_sec
155 || (e
.tv_sec
== time_span
->end_time
.tv_sec
156 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
157 time_span
->end_time
= e
;
163 static void init_tracefile_context(LttTracefile
*tracefile
,
164 LttvTraceContext
*tc
)
166 LttvTracefileContext
*tfc
;
167 LttvTracesetContext
*tsc
= tc
->ts_context
;
169 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
171 tfc
->index
= tc
->tracefiles
->len
;
172 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
177 tfc
->event
= lttv_hooks_new();
178 tfc
->event_by_id
= lttv_hooks_by_id_new();
179 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
180 tfc
->target_pid
= -1;
185 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
189 LttvTraceContext
*tc
;
191 GData
**tracefiles_groups
;
193 struct compute_tracefile_group_args args
;
195 struct bt_iter_pos begin_pos
;
197 nb_trace
= lttv_traceset_number(ts
);
199 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
200 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
201 self
->ts_a
= lttv_traceset_attribute(ts
);
203 begin_pos
.type
= BT_SEEK_BEGIN
;
205 self
->iter
= bt_ctf_iter_create(lttv_traceset_get_context(ts
),
208 self
->event_hooks
= lttv_hooks_new();
209 for(i
= 0 ; i
< nb_trace
; i
++) {
210 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
211 self
->traces
[i
] = tc
;
213 tc
->ts_context
= self
;
215 tc
->vt
= lttv_traceset_get(ts
, i
);
217 tc
->t
= lttv_trace(tc
->vt
);
219 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
220 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
221 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
222 sizeof(LttvTracefileContext
*), 10);
225 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
226 if(tracefiles_groups
!= NULL
) {
227 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
230 g_datalist_foreach(tracefiles_groups
,
231 (GDataForeachFunc
)compute_tracefile_group
,
238 self
->sync_position
= lttv_traceset_context_position_new(self
);
239 self
->pqueue
= g_tree_new(compare_tracefile
);
240 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
241 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
246 void fini(LttvTracesetContext
*self
)
248 guint i
, j
, nb_trace
, nb_tracefile
;
250 LttvTraceContext
*tc
;
252 LttvTracefileContext
**tfc
;
254 LttvTraceset
*ts
= self
->ts
;
256 g_tree_destroy(self
->pqueue
);
257 g_object_unref(self
->a
);
258 lttv_traceset_context_position_destroy(self
->sync_position
);
260 nb_trace
= lttv_traceset_number(ts
);
262 for(i
= 0 ; i
< nb_trace
; i
++) {
263 tc
= self
->traces
[i
];
265 g_object_unref(tc
->a
);
267 nb_tracefile
= tc
->tracefiles
->len
;
269 for(j
= 0 ; j
< nb_tracefile
; j
++) {
270 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
271 lttv_hooks_destroy((*tfc
)->event
);
272 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
273 g_object_unref((*tfc
)->a
);
274 g_object_unref(*tfc
);
276 g_array_free(tc
->tracefiles
, TRUE
);
279 g_free(self
->traces
);
283 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
284 LttvHooks
*before_traceset
,
285 LttvHooks
*before_trace
,
286 LttvHooks
*before_tracefile
,
288 LttvHooksByIdChannelArray
*event_by_id_channel
)
290 LttvTraceset
*ts
= self
->ts
;
294 LttvTraceContext
*tc
;
296 lttv_hooks_call(before_traceset
, self
);
298 lttv_hooks_add_list(self
->event_hooks
, event
);
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
=
367 &g_array_index(event_by_id_channel
->array
,
368 LttvHooksByIdChannel
, j
);
369 if (tf
->name
== hooks
->channel
)
370 lttv_tracefile_context_add_hooks(*tfc
,
381 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
382 LttvHooks
*after_trace
,
383 LttvHooks
*after_tracefile
,
385 LttvHooksByIdChannelArray
*event_by_id_channel
)
387 guint i
, j
, nb_tracefile
;
388 LttvTracefileContext
**tfc
;
391 nb_tracefile
= self
->tracefiles
->len
;
393 for(i
= 0 ; i
< nb_tracefile
; i
++) {
394 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
396 if (event_by_id_channel
) {
397 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
398 LttvHooksByIdChannel
*hooks
=
399 &g_array_index(event_by_id_channel
->array
,
400 LttvHooksByIdChannel
, j
);
401 if (tf
->name
== hooks
->channel
)
402 lttv_tracefile_context_remove_hooks(*tfc
,
408 lttv_tracefile_context_remove_hooks(*tfc
,
415 lttv_hooks_call(after_trace
, self
);
418 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
419 LttvHooks
*before_tracefile
,
421 LttvHooksById
*event_by_id
)
426 lttv_hooks_call(before_tracefile
, self
);
427 lttv_hooks_add_list(self
->event
, event
);
428 if(event_by_id
!= NULL
) {
429 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
430 index
= g_array_index(event_by_id
->array
, guint
, i
);
431 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
432 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
437 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
438 LttvHooks
*after_tracefile
,
440 LttvHooksById
*event_by_id
)
446 lttv_hooks_remove_list(self
->event
, event
);
447 if(event_by_id
!= NULL
) {
448 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
449 index
= g_array_index(event_by_id
->array
, guint
, i
);
450 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
452 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
456 lttv_hooks_call(after_tracefile
, self
);
459 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
461 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
465 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
467 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
471 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
473 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
477 static void traceset_context_instance_init(GTypeInstance
*instance
,
480 /* Be careful of anything which would not work well with shallow copies */
484 static void traceset_context_finalize(LttvTracesetContext
*self
)
486 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
487 ->finalize(G_OBJECT(self
));
491 static void traceset_context_class_init(LttvTracesetContextClass
*klass
)
493 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
495 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
498 klass
->new_traceset_context
= new_traceset_context
;
499 klass
->new_trace_context
= new_trace_context
;
500 klass
->new_tracefile_context
= new_tracefile_context
;
504 GType
lttv_traceset_context_get_type(void)
506 static GType type
= 0;
508 static const GTypeInfo info
= {
509 sizeof (LttvTracesetContextClass
),
510 NULL
, /* base_init */
511 NULL
, /* base_finalize */
512 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
513 NULL
, /* class_finalize */
514 NULL
, /* class_data */
515 sizeof (LttvTracesetContext
),
517 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
518 NULL
/* Value handling */
521 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
529 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
531 /* Be careful of anything which would not work well with shallow copies */
535 static void trace_context_finalize (LttvTraceContext
*self
)
537 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
538 finalize(G_OBJECT(self
));
542 static void trace_context_class_init (LttvTraceContextClass
*klass
)
544 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
546 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
550 GType
lttv_trace_context_get_type(void)
552 static GType type
= 0;
554 static const GTypeInfo info
= {
555 sizeof (LttvTraceContextClass
),
556 NULL
, /* base_init */
557 NULL
, /* base_finalize */
558 (GClassInitFunc
) trace_context_class_init
, /* class_init */
559 NULL
, /* class_finalize */
560 NULL
, /* class_data */
561 sizeof (LttvTraceContext
),
563 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
564 NULL
/* Value handling */
567 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
574 static void tracefile_context_instance_init (GTypeInstance
*instance
,
577 /* Be careful of anything which would not work well with shallow copies */
581 static void tracefile_context_finalize (LttvTracefileContext
*self
)
583 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
584 ->finalize(G_OBJECT(self
));
588 static void tracefile_context_class_init (LttvTracefileContextClass
*klass
)
590 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
592 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
596 GType
lttv_tracefile_context_get_type(void)
598 static GType type
= 0;
600 static const GTypeInfo info
= {
601 sizeof (LttvTracefileContextClass
),
602 NULL
, /* base_init */
603 NULL
, /* base_finalize */
604 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
605 NULL
, /* class_finalize */
606 NULL
, /* class_data */
607 sizeof (LttvTracefileContext
),
609 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
610 NULL
/* Value handling */
613 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
621 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
622 g_assert(key
== value
);
623 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
628 // Test to see if pqueue is traversed in the right order.
629 static LttTime test_time
;
631 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
633 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
635 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
636 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
637 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
638 tfc
->index
, tfc
->t_context
->index
);
640 if(user_data
!= NULL
) {
641 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
642 g_assert(compare_tracefile(user_data
, value
) == 0);
644 g_assert(compare_tracefile(user_data
, value
) != 0);
646 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
647 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
648 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
651 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
658 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
659 LttvHooks
*before_traceset
,
660 LttvHooks
*before_trace
,
661 LttvHooks
*before_tracefile
,
663 LttvHooksByIdChannelArray
*event_by_id_channel
)
666 /* simply add hooks in context. _before hooks are called by add_hooks. */
667 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
668 lttv_traceset_context_add_hooks(self
,
673 event_by_id_channel
);
677 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
679 /* Note : a _middle must be preceded from a _seek or another middle */
680 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
683 const LttvTracesetContextPosition
*end_position
)
688 struct bt_ctf_event
*bt_event
;
691 /* TODO ybrosseau 2012-03-16: Put in really in the traceset */
692 LttvTraceState state
;
696 if((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) {
700 if((bt_event
= bt_ctf_iter_read_event(self
->iter
)) != NULL
) {
704 event
.bt_event
= bt_event
;
705 event
.state
= &state
;
707 lttv_hooks_call(self
->event_hooks
, &event
);
709 if(bt_iter_next(bt_ctf_get_iter(self
->iter
)) < 0) {
710 printf("ERROR NEXT\n");
725 GTree
*pqueue
= self
->pqueue
;
727 LttvTracefileContext
*tfc
;
733 gboolean is_live
= FALSE
; /* set this flag if we detect a live trace */
737 //enum read_state last_read_state = LAST_NONE;
739 gint last_ret
= 0; /* return value of the last hook list called */
741 /* Get the next event from the pqueue, call its hooks,
742 reinsert in the pqueue the following event from the same tracefile
743 unless the tracefile is finished or the event is later than the
748 g_tree_foreach(pqueue
, get_first
, &tfc
);
749 /* End of traceset : tfc is NULL */
750 if(unlikely(tfc
== NULL
))
756 * - the maximum number of events specified?
757 * - the end position ?
759 * then the read is finished. We leave the queue in the same state and
762 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0) {
766 if(unlikely(last_ret
== TRUE
767 || ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
))
768 || (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
770 || ltt_time_compare(end
, tfc
->timestamp
) <= 0))
775 /* Get the tracefile with an event for the smallest time found. If two
776 or more tracefiles have events for the same time, hope that lookup
777 and remove are consistent. */
780 test_time
.tv_sec
= 0;
781 test_time
.tv_nsec
= 0;
782 g_debug("test tree before remove");
783 g_tree_foreach(pqueue
, test_tree
, tfc
);
785 g_tree_remove(pqueue
, tfc
);
788 test_time
.tv_sec
= 0;
789 test_time
.tv_nsec
= 0;
790 g_debug("test tree after remove");
791 g_tree_foreach(pqueue
, test_tree
, tfc
);
795 e
= ltt_tracefile_get_event(tfc
->tf
);
797 //if(last_read_state != LAST_EMPTY) {
798 /* Only call hooks if the last read has given an event or if we are at the
799 * first pass (not if last read returned end of tracefile) */
802 tfc
->target_pid
= -1; /* unset target PID */
804 * return values : 0 : continue read, 1 : go to next position and stop read,
805 * 2 : stay at the current position and stop read */
806 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
807 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
810 /* This is buggy : it won't work well with state computation */
811 if(unlikely(last_ret
== 2)) {
812 /* This is a case where we want to stay at this position and stop read. */
813 g_tree_insert(pqueue
, tfc
, tfc
);
818 read_ret
= ltt_tracefile_read(tfc
->tf
);
821 if(likely(!read_ret
)) {
822 //g_debug("An event is ready");
823 tfc
->timestamp
= ltt_event_time(e
);
826 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
827 g_tree_insert(pqueue
, tfc
, tfc
);
828 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0)
834 test_time
.tv_sec
= 0;
835 test_time
.tv_nsec
= 0;
836 g_debug("test tree after event ready");
837 g_tree_foreach(pqueue
, test_tree
, NULL
);
840 //last_read_state = LAST_OK;
842 tfc
->timestamp
= ltt_time_infinite
;
844 if(read_ret
== ERANGE
) {
845 // last_read_state = LAST_EMPTY;
846 g_debug("End of trace");
848 g_error("Error happened in lttv_process_traceset_middle");
852 if (unlikely((count
== 0) && is_live
)) {
858 #endif /* BABEL_CLEANUP */
862 void lttv_process_traceset_end(LttvTracesetContext
*self
,
863 LttvHooks
*after_traceset
,
864 LttvHooks
*after_trace
,
865 LttvHooks
*after_tracefile
,
867 LttvHooksByIdChannelArray
*event_by_id_channel
)
869 /* Remove hooks from context. _after hooks are called by remove_hooks. */
870 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
871 lttv_traceset_context_remove_hooks(self
,
876 event_by_id_channel
);
879 /* Subtile modification :
880 * if tracefile has no event at or after the time requested, it is not put in
881 * the queue, as the next read would fail.
883 * Don't forget to empty the traceset pqueue before calling this.
885 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
887 guint i
, nb_tracefile
;
891 LttvTracefileContext
**tfc
;
893 nb_tracefile
= self
->tracefiles
->len
;
895 GTree
*pqueue
= self
->ts_context
->pqueue
;
897 for(i
= 0 ; i
< nb_tracefile
; i
++) {
898 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
900 g_tree_remove(pqueue
, *tfc
);
902 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
903 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
905 if(ret
== 0) { /* not ERANGE especially */
906 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
907 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
908 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
910 (*tfc
)->timestamp
= ltt_time_infinite
;
914 test_time
.tv_sec
= 0;
915 test_time
.tv_nsec
= 0;
916 g_debug("test tree after seek_time");
917 g_tree_foreach(pqueue
, test_tree
, NULL
);
921 /****************************************************************************
922 * lttv_process_trace_update
924 * process the changes that occur in the trace. Use a regular file polling to
925 * monitor the tracefile.
927 * Return the number of tracefile updated
928 ***************************************************************************/
929 guint
lttv_process_trace_update(LttvTraceContext
*self
)
932 guint nb_tracefile
= 0;
934 LttTracefile
*tf
= 0;
935 LttvTracefileContext
**tfc
;
937 /* Skip non live traces */
938 if(self
->t
->is_live
) {
940 nb_tracefile
= ltt_trace_update(self
->t
);
942 /* Recreate the pqueue following an update*/
943 GTree
*pqueue
= self
->ts_context
->pqueue
;
945 for(i
= 0 ; i
< self
->tracefiles
->len
; i
++) {
946 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
948 if(g_tree_remove(pqueue
, *tfc
) == FALSE
) {
949 if(tf
->buf_index
!= NULL
) {
951 if(ltt_tracefile_read(tf
) == 0) {
953 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
954 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
959 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
965 //Update self time span
966 self
->time_span
.end_time
= LTT_TIME_MAX(self
->t
->live_safe_timestamp
,
967 self
->time_span
.end_time
);
968 //Update self tscontext time span
969 self
->ts_context
->time_span
.end_time
= LTT_TIME_MAX(self
->time_span
.end_time
,
970 self
->ts_context
->time_span
.end_time
);
976 /****************************************************************************
977 * lttv_process_traceset_update
979 * process the changes that occur in the traceset.
981 * Return the number of file presently monitor(open for writting). If 0, the
982 * current traceset probably received all the data.
983 ***************************************************************************/
984 guint
lttv_process_traceset_update(LttvTracesetContext
*self
)
988 guint open_counter
= 0;
990 nb_trace
= lttv_traceset_number(self
->ts
);
992 for(i
= 0 ; i
< nb_trace
; i
++) {
993 open_counter
+= lttv_process_trace_update(self
->traces
[i
]);
998 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
1000 #ifdef WAIT_FOR_BABELTRACE_FIX_SEEK_ZERO
1001 struct bt_iter_pos seekpos
;
1003 seekpos
.type
= BT_SEEK_TIME
;
1004 seekpos
.u
.seek_time
= ltt_time_to_uint64(start
);
1005 ret
= bt_iter_set_pos(bt_ctf_get_iter(self
->iter
), &seekpos
);
1007 printf("Seek by time error: %s,\n",strerror(-ret
));
1010 #warning Seek time disabled because of babeltrace bugs
1013 #ifdef BABEL_CLEANUP
1018 LttvTraceContext
*tc
;
1020 //g_tree_destroy(self->pqueue);
1021 //self->pqueue = g_tree_new(compare_tracefile);
1023 nb_trace
= lttv_traceset_number(self
->ts
);
1024 for(i
= 0 ; i
< nb_trace
; i
++) {
1025 tc
= self
->traces
[i
];
1026 lttv_process_trace_seek_time(tc
, start
);
1032 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
1033 const LttvTracesetContextPosition
*pos
)
1036 /* If a position is set, seek the traceset to this position */
1037 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
1039 /* Test to see if the traces has been added to the trace set :
1040 * It should NEVER happen. Clear all positions if a new trace comes in. */
1041 /* FIXME I know this test is not optimal : should keep a number of
1042 * tracefiles variable in the traceset.. eventually */
1043 guint num_traces
= lttv_traceset_number(self
->ts
);
1045 for(i
=0; i
<num_traces
;i
++) {
1046 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1048 guint num_tracefiles
= tracefiles
->len
;
1049 for(j
=0;j
<num_tracefiles
;j
++)
1052 g_assert(tf_count
== pos
->tfcp
->len
);
1055 //g_tree_destroy(self->pqueue);
1056 //self->pqueue = g_tree_new(compare_tracefile);
1058 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
1059 LttvTracefileContextPosition
*tfcp
=
1060 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1062 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
1064 if(tfcp
->used
== TRUE
) {
1065 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
1067 tfcp
->tfc
->timestamp
=
1068 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
1069 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
1070 ltt_time_infinite
) != 0);
1071 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
1074 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
1079 test_time
.tv_sec
= 0;
1080 test_time
.tv_nsec
= 0;
1081 g_debug("test tree after seek_position");
1082 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
1091 #if 0 // pmf: temporary disable
1093 find_field(LttEventType
*et
, const GQuark field
)
1097 if(field
== 0) return NULL
;
1099 f
= ltt_eventtype_field_by_name(et
, field
);
1101 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
1102 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
1103 g_quark_to_string(ltt_eventtype_name(et
)));
1110 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
1112 return marker_get_info_from_id(th
->mdata
, th
->id
);
1115 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
1116 GQuark fields
[], LttvHook h
, gpointer hook_data
,
1117 GArray
**trace_hooks
)
1119 struct marker_info
*info
;
1121 int init_array_size
;
1123 struct marker_data
*mdata
;
1125 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
1126 if (unlikely(!group
|| group
->len
== 0)) {
1127 g_info("No channel for marker named %s.%s found",
1128 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1132 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
1133 info
= marker_get_info_from_name(mdata
, event_name
);
1134 if(unlikely(info
== NULL
)) {
1135 g_info("No marker named %s.%s found",
1136 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1140 init_array_size
= (*trace_hooks
)->len
;
1142 /* for each marker with the requested name */
1144 LttvTraceHook tmpth
;
1147 struct marker_field
*marker_field
;
1149 marker_id
= marker_get_id_from_info(mdata
, info
);
1152 tmpth
.mdata
= mdata
;
1153 tmpth
.channel
= channel_name
;
1154 tmpth
.id
= marker_id
;
1155 tmpth
.hook_data
= hook_data
;
1156 tmpth
.fields
= g_ptr_array_new();
1158 /* for each field requested */
1159 for(f
= fields
; f
&& *f
!= 0; f
++) {
1161 for_each_marker_field(marker_field
, info
) {
1162 if(marker_field
->name
== *f
) {
1164 g_ptr_array_add(tmpth
.fields
, marker_field
);
1169 /* Did not find the one of the fields in this instance of the
1170 marker. Print a warning and skip this marker completely.
1171 Still iterate on other markers with same name. */
1172 g_ptr_array_free(tmpth
.fields
, TRUE
);
1173 g_info("Field %s cannot be found in marker %s.%s",
1174 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1175 g_quark_to_string(event_name
));
1179 /* all fields were found: add the tracehook to the array */
1180 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1183 } while(info
!= NULL
);
1185 /* Error if no new trace hook has been added */
1186 if (init_array_size
== (*trace_hooks
)->len
) {
1187 g_info("No marker of name %s.%s has all requested fields",
1188 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1194 void lttv_trace_hook_remove_all(GArray
**th
)
1197 for(i
=0; i
<(*th
)->len
; i
++) {
1198 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1201 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1204 LttvTracesetContextPosition
*
1205 lttv_traceset_context_position_new(const LttvTracesetContext
*self
)
1207 guint num_traces
= lttv_traceset_number(self
->ts
);
1211 for(i
=0; i
<num_traces
;i
++) {
1212 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1214 guint num_tracefiles
= tracefiles
->len
;
1215 for(j
=0;j
<num_tracefiles
;j
++)
1218 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
, 1);
1219 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1220 sizeof(LttvTracefileContextPosition
),
1222 g_array_set_size(pos
->tfcp
, tf_count
);
1223 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1224 LttvTracefileContextPosition
*tfcp
=
1225 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1226 tfcp
->event
= ltt_event_position_new();
1229 pos
->timestamp
= ltt_time_infinite
;
1233 /* Save all positions, the ones with infinite time will have NULL
1235 /* note : a position must be destroyed when a trace is added/removed from a
1237 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1238 LttvTracesetContextPosition
*pos
)
1241 guint num_traces
= lttv_traceset_number(self
->ts
);
1244 pos
->timestamp
= ltt_time_infinite
;
1246 for(i
=0; i
<num_traces
;i
++) {
1247 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1249 guint num_tracefiles
= tracefiles
->len
;
1251 for(j
=0;j
<num_tracefiles
;j
++) {
1252 g_assert(tf_count
< pos
->tfcp
->len
);
1253 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1254 LttvTracefileContext
*, j
);
1255 LttvTracefileContextPosition
*tfcp
=
1256 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1260 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1261 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1262 ltt_event_position(event
, tfcp
->event
);
1263 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1264 pos
->timestamp
= (*tfc
)->timestamp
;
1270 //g_array_append_val(pos->tfc, *tfc);
1271 //g_array_append_val(pos->ep, ep);
1278 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1282 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1283 LttvTracefileContextPosition
*tfcp
=
1284 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1285 g_free(tfcp
->event
);
1289 g_array_free(pos
->tfcp
, TRUE
);
1293 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1294 const LttvTracesetContextPosition
*src
)
1297 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1299 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1301 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1303 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1305 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1307 dest_tfcp
->used
= src_tfcp
->used
;
1308 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1310 if(src_tfcp
->used
) {
1311 ltt_event_position_copy(
1316 dest
->timestamp
= src
->timestamp
;
1319 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1320 const LttvTracesetContextPosition
*pos
)
1325 if(pos
->tfcp
->len
== 0) {
1326 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1329 if(lttv_traceset_number(self
->ts
) == 0)
1332 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1333 LttvTracefileContextPosition
*tfcp
=
1334 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1336 if(tfcp
->used
== FALSE
) {
1337 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1341 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1344 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1346 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1350 if(ret
!= 0) return ret
;
1358 lttv_traceset_context_pos_pos_compare(const LttvTracesetContextPosition
*pos1
,
1359 const LttvTracesetContextPosition
*pos2
)
1364 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1365 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1370 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1373 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1374 LttvTracefileContextPosition
*tfcp1
=
1375 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1377 if(tfcp1
->used
== TRUE
) {
1378 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1379 LttvTracefileContextPosition
*tfcp2
=
1380 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1382 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1383 if(tfcp2
->used
== TRUE
)
1384 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1388 if(ret
!= 0) return ret
;
1393 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1394 LttvTracefileContextPosition
*tfcp2
=
1395 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1397 if(tfcp1
->tfc
== tfcp2
->tfc
)
1398 if(tfcp2
->used
== TRUE
) ret
= 1;
1399 if(ret
!= 0) return ret
;
1408 lttv_traceset_context_position_get_time(const LttvTracesetContextPosition
*pos
)
1410 return pos
->timestamp
;
1414 LttvTracefileContext
*
1415 lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1417 GTree
*pqueue
= self
->pqueue
;
1418 LttvTracefileContext
*tfc
= NULL
;
1420 g_tree_foreach(pqueue
, get_first
, &tfc
);
1425 /* lttv_process_traceset_synchronize_tracefiles
1427 * Use the sync_position field of the trace set context to synchronize each
1428 * tracefile with the previously saved position.
1430 * If no previous position has been saved, it simply does nothing.
1432 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1436 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1437 g_assert_cmpint(retval
, ==, 0);
1443 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1445 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1448 struct seek_back_data
{
1449 guint first_event
; /* Index of the first event in the array : we will always
1450 overwrite at this position : this is a circular array.
1453 guint n
; /* number of events requested */
1454 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1455 LttvFilter
*filter1
;
1456 LttvFilter
*filter2
;
1457 LttvFilter
*filter3
;
1459 check_handler
*check
;
1460 gboolean
*stop_flag
;
1461 guint raw_event_count
;
1464 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1466 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1467 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1468 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1469 LttvTracesetContextPosition
*pos
;
1471 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1473 sd
->raw_event_count
++;
1475 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1476 !lttv_filter_tree_parse(sd
->filter1
->head
,
1477 ltt_tracefile_get_event(tfc
->tf
),
1483 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1484 !lttv_filter_tree_parse(sd
->filter2
->head
,
1485 ltt_tracefile_get_event(tfc
->tf
),
1491 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1492 !lttv_filter_tree_parse(sd
->filter3
->head
,
1493 ltt_tracefile_get_event(tfc
->tf
),
1500 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1503 lttv_traceset_context_position_save(tsc
, pos
);
1505 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1506 else sd
->first_event
++;
1508 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1513 /* Seek back n events back from the current position.
1516 * @self The trace set context
1517 * @n number of events to jump over
1518 * @first_offset The initial offset value used.
1519 * never put first_offset at ltt_time_zero.
1520 * @time_seeker Function pointer of the function to use to seek time :
1521 * either lttv_process_traceset_seek_time
1522 * or lttv_state_traceset_seek_time_closest
1523 * @filter The filter to call.
1525 * Return value : the number of events found (might be lower than the number
1526 * requested if beginning of traceset is reached).
1528 * The first search will go back first_offset and try to find the last n events
1529 * matching the filter. If there are not enough, it will try to go back from the
1530 * new trace point from first_offset*2, and so on, until beginning of trace or n
1533 * Note : this function does not take in account the LttvFilter : use the
1534 * similar function found in state.c instead.
1536 * Note2 : the caller must make sure that the LttvTracesetContext does not
1537 * contain any hook, as process_traceset_middle is used in this routine.
1539 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1540 guint n
, LttTime first_offset
,
1541 seek_time_fct time_seeker
,
1542 check_handler
*check
,
1543 gboolean
*stop_flag
,
1544 LttvFilter
*filter1
,
1545 LttvFilter
*filter2
,
1546 LttvFilter
*filter3
,
1549 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1550 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1553 LttvTracesetContextPosition
*next_iter_end_pos
=
1554 lttv_traceset_context_position_new(self
);
1555 LttvTracesetContextPosition
*end_pos
=
1556 lttv_traceset_context_position_new(self
);
1557 LttvTracesetContextPosition
*saved_pos
=
1558 lttv_traceset_context_position_new(self
);
1561 LttTime time_offset
;
1562 struct seek_back_data sd
;
1563 LttvHooks
*hooks
= lttv_hooks_new();
1567 sd
.events_found
= 0;
1568 sd
.array
= g_ptr_array_sized_new(n
);
1569 sd
.filter1
= filter1
;
1570 sd
.filter2
= filter2
;
1571 sd
.filter3
= filter3
;
1575 sd
.stop_flag
= stop_flag
;
1576 sd
.raw_event_count
= 0;
1577 g_ptr_array_set_size(sd
.array
, n
);
1579 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1582 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1583 lttv_traceset_context_position_save(self
, saved_pos
);
1584 /* Get the current time from which we will offset */
1585 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1586 /* the position saved might be end of traceset... */
1587 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1588 time
= self
->time_span
.end_time
;
1590 time_offset
= first_offset
;
1592 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1594 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1597 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1599 /* We must seek the traceset back to time - time_offset */
1600 /* this time becomes the new reference time */
1601 if(ltt_time_compare(time
, time_offset
) > 0)
1602 time
= ltt_time_sub(time
, time_offset
);
1604 time
= self
->time_span
.start_time
;
1607 time_seeker(self
, time
);
1608 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1609 /* Resync the time in case of a seek_closest */
1610 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1611 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1612 time
= self
->time_span
.end_time
;
1615 /* Process the traceset, calling a hook which adds events
1616 * to the array, overwriting the tail. It changes first_event and
1617 * events_found too. */
1618 /* We would like to have a clean context here : no other hook than our's */
1620 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1621 G_MAXUINT
, end_pos
);
1623 /* stop criteria : - n events found
1624 * - asked_time < beginning of trace */
1625 if(sd
.events_found
< n
) {
1626 if(sd
.first_event
> 0) {
1627 /* Save the first position */
1628 LttvTracesetContextPosition
*pos
=
1629 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1630 lttv_traceset_context_position_copy(saved_pos
, pos
);
1632 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1633 /* Change array size to n - events_found */
1634 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1635 LttvTracesetContextPosition
*pos
=
1636 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1637 lttv_traceset_context_position_destroy(pos
);
1639 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1643 * Did not fill our event list and started before the beginning of the
1644 * trace. There is no hope to fill it then.
1645 * It is OK to compare with trace start time here because we explicitely
1646 * seeked by time (not by position), so we cannot miss multiple event
1647 * happening exactly at trace start.
1649 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) == 0)
1652 } else break; /* Second end criterion : n events found */
1654 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1657 lttv_traceset_context_position_destroy(end_pos
);
1658 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1660 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1662 if(sd
.events_found
>= n
) {
1663 /* Seek the traceset to the first event in the circular array */
1664 LttvTracesetContextPosition
*pos
=
1665 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1667 retval
= lttv_process_traceset_seek_position(self
, pos
);
1668 g_assert_cmpint(retval
, ==, 0);
1670 /* Will seek to the last saved position : in the worst case, it will be the
1671 * original position (if events_found is 0) */
1672 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1673 g_assert_cmpint(retval
, ==, 0);
1676 for(i
=0;i
<sd
.array
->len
;i
++) {
1677 LttvTracesetContextPosition
*pos
=
1678 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1679 lttv_traceset_context_position_destroy(pos
);
1681 g_ptr_array_free(sd
.array
, TRUE
);
1683 lttv_hooks_destroy(hooks
);
1685 lttv_traceset_context_position_destroy(saved_pos
);
1687 return sd
.events_found
;
1691 struct seek_forward_data
{
1692 guint event_count
; /* event counter */
1693 guint n
; /* requested number of events to jump over */
1694 LttvFilter
*filter1
;
1695 LttvFilter
*filter2
;
1696 LttvFilter
*filter3
;
1698 check_handler
*check
;
1699 gboolean
*stop_flag
;
1700 guint raw_event_count
; /* event counter */
1703 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1705 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1706 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1708 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1710 sd
->raw_event_count
++;
1712 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1713 !lttv_filter_tree_parse(sd
->filter1
->head
,
1714 ltt_tracefile_get_event(tfc
->tf
),
1720 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1721 !lttv_filter_tree_parse(sd
->filter2
->head
,
1722 ltt_tracefile_get_event(tfc
->tf
),
1728 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1729 !lttv_filter_tree_parse(sd
->filter3
->head
,
1730 ltt_tracefile_get_event(tfc
->tf
),
1738 if(sd
->event_count
>= sd
->n
)
1743 /* Seek back n events forward from the current position (1 to n)
1744 * 0 is ok too, but it will actually do nothing.
1747 * @self the trace set context
1748 * @n number of events to jump over
1749 * @filter filter to call.
1751 * returns : the number of events jumped over (may be less than requested if end
1752 * of traceset reached) */
1753 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1755 check_handler
*check
,
1756 gboolean
*stop_flag
,
1757 LttvFilter
*filter1
,
1758 LttvFilter
*filter2
,
1759 LttvFilter
*filter3
,
1762 struct seek_forward_data sd
;
1765 sd
.filter1
= filter1
;
1766 sd
.filter2
= filter2
;
1767 sd
.filter3
= filter3
;
1770 sd
.stop_flag
= stop_flag
;
1771 sd
.raw_event_count
= 0;
1773 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1775 LttvHooks
*hooks
= lttv_hooks_new();
1777 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1779 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1781 /* it will end on the end of traceset, or the fact that the
1782 * hook returns TRUE.
1784 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1787 /* Here, our position is either the end of traceset, or the exact position
1788 * after n events : leave it like this. This might be placed on an event that
1789 * will be filtered out, we don't care : all we know is that the following
1790 * event filtered in will be the right one. */
1792 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1794 lttv_hooks_destroy(hooks
);
1796 return sd
.event_count
;