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/traceset-process.h>
26 #include <ltt/event.h>
27 #include <ltt/trace.h>
29 #include <lttv/filter.h>
33 #include <lttv/event.h>
35 #include <babeltrace/context.h>
36 #include <babeltrace/iterator.h>
38 #include <babeltrace/ctf/events.h>
39 #include <babeltrace/ctf/iterator.h>
43 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
47 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
48 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
50 if(likely(trace_a
!= trace_b
)) {
51 comparison
= ltt_time_compare(trace_a
->timestamp
, trace_b
->timestamp
);
52 if(unlikely(comparison
== 0)) {
53 if(trace_a
->index
< trace_b
->index
) comparison
= -1;
54 else if(trace_a
->index
> trace_b
->index
) comparison
= 1;
55 else if(trace_a
->t_context
->index
< trace_b
->t_context
->index
)
57 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
64 typedef struct _LttvTracefileContextPosition
{
65 LttEventPosition
*event
;
66 LttvTracefileContext
*tfc
;
67 gboolean used
; /* Tells if the tfc is at end of traceset position */
68 } LttvTracefileContextPosition
;
71 struct _LttvTracesetContextPosition
{
72 GArray
*tfcp
; /* Array of LttvTracefileContextPosition */
73 LttTime timestamp
; /* Current time at the saved position */
74 /* If ltt_time_infinite : no position is
75 * set, else, a position is set (may be end
76 * of trace, with ep->len == 0) */
79 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
81 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
85 void lttv_context_fini(LttvTracesetContext
*self
)
87 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
92 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
94 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
101 lttv_context_new_trace_context(LttvTracesetContext
*self
)
103 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
107 LttvTracefileContext
*
108 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
110 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
113 /****************************************************************************
114 * lttv_traceset_context_compute_time_span
116 * Keep the time span in sync with on the fly addition and removal of traces
117 * in a trace set. It must be called each time a trace is added/removed from
118 * the traceset. It could be more efficient to call it only once a bunch
119 * of traces are loaded, but the calculation is not long, so it's not
122 * Author : Xang Xiu Yang
123 ***************************************************************************/
124 void lttv_traceset_context_compute_time_span(LttvTracesetContext
*self
,
125 TimeInterval
*time_span
)
127 //todo mdenis: adapt to babeltrace
129 LttvTraceset
* traceset
= self
->ts
;
130 int numTraces
= lttv_traceset_number(traceset
);
133 LttvTraceContext
*tc
;
136 time_span
->start_time
.tv_sec
= 0;
137 time_span
->start_time
.tv_nsec
= 0;
138 time_span
->end_time
.tv_sec
= 0;
139 time_span
->end_time
.tv_nsec
= 0;
141 for(i
=0; i
<numTraces
;i
++){
142 tc
= self
->traces
[i
];
146 ltt_trace_time_span_get(trace
, &s
, &e
);
147 tc
->time_span
.start_time
= s
;
148 tc
->time_span
.end_time
= e
;
151 time_span
->start_time
= s
;
152 time_span
->end_time
= e
;
154 if(s
.tv_sec
< time_span
->start_time
.tv_sec
155 || (s
.tv_sec
== time_span
->start_time
.tv_sec
156 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
157 time_span
->start_time
= s
;
158 if(e
.tv_sec
> time_span
->end_time
.tv_sec
159 || (e
.tv_sec
== time_span
->end_time
.tv_sec
160 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
161 time_span
->end_time
= e
;
167 static void init_tracefile_context(LttTracefile
*tracefile
,
168 LttvTraceContext
*tc
)
170 LttvTracefileContext
*tfc
;
171 LttvTracesetContext
*tsc
= tc
->ts_context
;
173 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
175 tfc
->index
= tc
->tracefiles
->len
;
176 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
181 tfc
->event
= lttv_hooks_new();
182 tfc
->event_by_id
= lttv_hooks_by_id_new();
183 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
184 tfc
->target_pid
= -1;
189 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
193 LttvTraceContext
*tc
;
195 GData
**tracefiles_groups
;
197 struct compute_tracefile_group_args args
;
199 struct bt_iter_pos begin_pos
;
201 nb_trace
= lttv_traceset_number(ts
);
203 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
204 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
205 self
->ts_a
= lttv_traceset_attribute(ts
);
207 begin_pos
.type
= BT_SEEK_BEGIN
;
209 self
->iter
= bt_ctf_iter_create(lttv_traceset_get_context(ts
),
212 self
->event_hooks
= lttv_hooks_new();
213 self
->tmpState
= g_new(LttvTraceState
*, 1);
215 for(i
= 0 ; i
< nb_trace
; i
++) {
216 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
217 self
->traces
[i
] = tc
;
219 tc
->ts_context
= self
;
221 tc
->vt
= lttv_traceset_get(ts
, i
);
223 tc
->t
= lttv_trace(tc
->vt
);
225 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
226 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
227 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
228 sizeof(LttvTracefileContext
*), 10);
231 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
232 if(tracefiles_groups
!= NULL
) {
233 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
236 g_datalist_foreach(tracefiles_groups
,
237 (GDataForeachFunc
)compute_tracefile_group
,
244 self
->sync_position
= lttv_traceset_context_position_new(self
);
246 self
->pqueue
= g_tree_new(compare_tracefile
);
248 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
249 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
254 void fini(LttvTracesetContext
*self
)
256 guint i
, j
, nb_trace
, nb_tracefile
;
258 LttvTraceContext
*tc
;
260 LttvTracefileContext
**tfc
;
262 LttvTraceset
*ts
= self
->ts
;
264 g_tree_destroy(self
->pqueue
);
265 g_object_unref(self
->a
);
266 lttv_traceset_context_position_destroy(self
->sync_position
);
268 nb_trace
= lttv_traceset_number(ts
);
270 for(i
= 0 ; i
< nb_trace
; i
++) {
271 tc
= self
->traces
[i
];
273 g_object_unref(tc
->a
);
275 nb_tracefile
= tc
->tracefiles
->len
;
277 for(j
= 0 ; j
< nb_tracefile
; j
++) {
278 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
279 lttv_hooks_destroy((*tfc
)->event
);
280 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
281 g_object_unref((*tfc
)->a
);
282 g_object_unref(*tfc
);
284 g_array_free(tc
->tracefiles
, TRUE
);
287 g_free(self
->traces
);
291 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
292 LttvHooks
*before_traceset
,
293 LttvHooks
*before_trace
,
294 LttvHooks
*before_tracefile
,
296 LttvHooksByIdChannelArray
*event_by_id_channel
)
298 LttvTraceset
*ts
= self
->ts
;
302 LttvTraceContext
*tc
;
304 lttv_hooks_call(before_traceset
, self
);
306 lttv_hooks_add_list(self
->event_hooks
, event
);
308 nb_trace
= lttv_traceset_number(ts
);
310 for(i
= 0 ; i
< nb_trace
; i
++) {
311 tc
= self
->traces
[i
];
312 lttv_trace_context_add_hooks(tc
,
316 event_by_id_channel
);
321 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
322 LttvHooks
*after_traceset
,
323 LttvHooks
*after_trace
,
324 LttvHooks
*after_tracefile
,
326 LttvHooksByIdChannelArray
*event_by_id_channel
)
329 LttvTraceset
*ts
= self
->ts
;
333 LttvTraceContext
*tc
;
335 nb_trace
= lttv_traceset_number(ts
);
337 for(i
= 0 ; i
< nb_trace
; i
++) {
338 tc
= self
->traces
[i
];
339 lttv_trace_context_remove_hooks(tc
,
343 event_by_id_channel
);
346 lttv_hooks_call(after_traceset
, self
);
351 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
352 LttvHooks
*before_trace
,
353 LttvHooks
*before_tracefile
,
355 LttvHooksByIdChannelArray
*event_by_id_channel
)
357 guint i
, j
, nb_tracefile
;
358 LttvTracefileContext
**tfc
;
361 lttv_hooks_call(before_trace
, self
);
363 nb_tracefile
= self
->tracefiles
->len
;
365 for(i
= 0 ; i
< nb_tracefile
; i
++) {
366 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
368 lttv_tracefile_context_add_hooks(*tfc
,
372 if (event_by_id_channel
) {
373 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
374 LttvHooksByIdChannel
*hooks
=
375 &g_array_index(event_by_id_channel
->array
,
376 LttvHooksByIdChannel
, j
);
377 if (tf
->name
== hooks
->channel
)
378 lttv_tracefile_context_add_hooks(*tfc
,
389 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
390 LttvHooks
*after_trace
,
391 LttvHooks
*after_tracefile
,
393 LttvHooksByIdChannelArray
*event_by_id_channel
)
395 guint i
, j
, nb_tracefile
;
396 LttvTracefileContext
**tfc
;
399 nb_tracefile
= self
->tracefiles
->len
;
401 for(i
= 0 ; i
< nb_tracefile
; i
++) {
402 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
404 if (event_by_id_channel
) {
405 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
406 LttvHooksByIdChannel
*hooks
=
407 &g_array_index(event_by_id_channel
->array
,
408 LttvHooksByIdChannel
, j
);
409 if (tf
->name
== hooks
->channel
)
410 lttv_tracefile_context_remove_hooks(*tfc
,
416 lttv_tracefile_context_remove_hooks(*tfc
,
423 lttv_hooks_call(after_trace
, self
);
426 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
427 LttvHooks
*before_tracefile
,
429 LttvHooksById
*event_by_id
)
434 lttv_hooks_call(before_tracefile
, self
);
435 lttv_hooks_add_list(self
->event
, event
);
436 if(event_by_id
!= NULL
) {
437 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
438 index
= g_array_index(event_by_id
->array
, guint
, i
);
439 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
440 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
445 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
446 LttvHooks
*after_tracefile
,
448 LttvHooksById
*event_by_id
)
454 lttv_hooks_remove_list(self
->event
, event
);
455 if(event_by_id
!= NULL
) {
456 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
457 index
= g_array_index(event_by_id
->array
, guint
, i
);
458 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
460 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
464 lttv_hooks_call(after_tracefile
, self
);
467 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
469 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
473 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
475 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
479 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
481 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
485 static void traceset_context_instance_init(GTypeInstance
*instance
,
488 /* Be careful of anything which would not work well with shallow copies */
492 static void traceset_context_finalize(LttvTracesetContext
*self
)
494 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
495 ->finalize(G_OBJECT(self
));
499 static void traceset_context_class_init(LttvTracesetContextClass
*klass
)
501 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
503 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
506 klass
->new_traceset_context
= new_traceset_context
;
507 klass
->new_trace_context
= new_trace_context
;
508 klass
->new_tracefile_context
= new_tracefile_context
;
512 GType
lttv_traceset_context_get_type(void)
514 static GType type
= 0;
516 static const GTypeInfo info
= {
517 sizeof (LttvTracesetContextClass
),
518 NULL
, /* base_init */
519 NULL
, /* base_finalize */
520 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
521 NULL
, /* class_finalize */
522 NULL
, /* class_data */
523 sizeof (LttvTracesetContext
),
525 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
526 NULL
/* Value handling */
529 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
537 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
539 /* Be careful of anything which would not work well with shallow copies */
543 static void trace_context_finalize (LttvTraceContext
*self
)
545 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
546 finalize(G_OBJECT(self
));
550 static void trace_context_class_init (LttvTraceContextClass
*klass
)
552 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
554 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
558 GType
lttv_trace_context_get_type(void)
560 static GType type
= 0;
562 static const GTypeInfo info
= {
563 sizeof (LttvTraceContextClass
),
564 NULL
, /* base_init */
565 NULL
, /* base_finalize */
566 (GClassInitFunc
) trace_context_class_init
, /* class_init */
567 NULL
, /* class_finalize */
568 NULL
, /* class_data */
569 sizeof (LttvTraceContext
),
571 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
572 NULL
/* Value handling */
575 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
582 static void tracefile_context_instance_init (GTypeInstance
*instance
,
585 /* Be careful of anything which would not work well with shallow copies */
589 static void tracefile_context_finalize (LttvTracefileContext
*self
)
591 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
592 ->finalize(G_OBJECT(self
));
596 static void tracefile_context_class_init (LttvTracefileContextClass
*klass
)
598 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
600 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
604 GType
lttv_tracefile_context_get_type(void)
606 static GType type
= 0;
608 static const GTypeInfo info
= {
609 sizeof (LttvTracefileContextClass
),
610 NULL
, /* base_init */
611 NULL
, /* base_finalize */
612 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
613 NULL
, /* class_finalize */
614 NULL
, /* class_data */
615 sizeof (LttvTracefileContext
),
617 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
618 NULL
/* Value handling */
621 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
629 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
630 g_assert(key
== value
);
631 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
636 // Test to see if pqueue is traversed in the right order.
637 static LttTime test_time
;
639 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
641 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
643 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
644 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
645 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
646 tfc
->index
, tfc
->t_context
->index
);
648 if(user_data
!= NULL
) {
649 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
650 g_assert(compare_tracefile(user_data
, value
) == 0);
652 g_assert(compare_tracefile(user_data
, value
) != 0);
654 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
655 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
656 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
659 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
666 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
667 LttvHooks
*before_traceset
,
668 LttvHooks
*before_trace
,
669 LttvHooks
*before_tracefile
,
671 LttvHooksByIdChannelArray
*event_by_id_channel
)
674 /* simply add hooks in context. _before hooks are called by add_hooks. */
675 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
676 lttv_traceset_context_add_hooks(self
,
681 event_by_id_channel
);
685 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
687 /* Note : a _middle must be preceded from a _seek or another middle */
688 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
691 const LttvTracesetContextPosition
*end_position
)
697 struct bt_ctf_event
*bt_event
;
703 if(last_ret
== TRUE
|| ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
))) {
707 if((bt_event
= bt_ctf_iter_read_event(self
->iter
)) != NULL
) {
711 event
.bt_event
= bt_event
;
712 /* TODO ybrosseau 2012-04-01: use bt_ctf_get_trace_handle
713 to retrieve the right state container */
714 event
.state
= self
->tmpState
;
716 last_ret
= lttv_hooks_call(self
->event_hooks
, &event
);
718 if(bt_iter_next(bt_ctf_get_iter(self
->iter
)) < 0) {
719 printf("ERROR NEXT\n");
734 GTree
*pqueue
= self
->pqueue
;
736 LttvTracefileContext
*tfc
;
742 gboolean is_live
= FALSE
; /* set this flag if we detect a live trace */
746 //enum read_state last_read_state = LAST_NONE;
748 gint last_ret
= 0; /* return value of the last hook list called */
750 /* Get the next event from the pqueue, call its hooks,
751 reinsert in the pqueue the following event from the same tracefile
752 unless the tracefile is finished or the event is later than the
757 g_tree_foreach(pqueue
, get_first
, &tfc
);
758 /* End of traceset : tfc is NULL */
759 if(unlikely(tfc
== NULL
))
765 * - the maximum number of events specified?
766 * - the end position ?
768 * then the read is finished. We leave the queue in the same state and
771 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0) {
775 if(unlikely(last_ret
== TRUE
776 || ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
))
777 || (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
779 || ltt_time_compare(end
, tfc
->timestamp
) <= 0))
784 /* Get the tracefile with an event for the smallest time found. If two
785 or more tracefiles have events for the same time, hope that lookup
786 and remove are consistent. */
789 test_time
.tv_sec
= 0;
790 test_time
.tv_nsec
= 0;
791 g_debug("test tree before remove");
792 g_tree_foreach(pqueue
, test_tree
, tfc
);
794 g_tree_remove(pqueue
, tfc
);
797 test_time
.tv_sec
= 0;
798 test_time
.tv_nsec
= 0;
799 g_debug("test tree after remove");
800 g_tree_foreach(pqueue
, test_tree
, tfc
);
804 e
= ltt_tracefile_get_event(tfc
->tf
);
806 //if(last_read_state != LAST_EMPTY) {
807 /* Only call hooks if the last read has given an event or if we are at the
808 * first pass (not if last read returned end of tracefile) */
811 tfc
->target_pid
= -1; /* unset target PID */
813 * return values : 0 : continue read, 1 : go to next position and stop read,
814 * 2 : stay at the current position and stop read */
815 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
816 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
819 /* This is buggy : it won't work well with state computation */
820 if(unlikely(last_ret
== 2)) {
821 /* This is a case where we want to stay at this position and stop read. */
822 g_tree_insert(pqueue
, tfc
, tfc
);
827 read_ret
= ltt_tracefile_read(tfc
->tf
);
830 if(likely(!read_ret
)) {
831 //g_debug("An event is ready");
832 tfc
->timestamp
= ltt_event_time(e
);
835 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
836 g_tree_insert(pqueue
, tfc
, tfc
);
837 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0)
843 test_time
.tv_sec
= 0;
844 test_time
.tv_nsec
= 0;
845 g_debug("test tree after event ready");
846 g_tree_foreach(pqueue
, test_tree
, NULL
);
849 //last_read_state = LAST_OK;
851 tfc
->timestamp
= ltt_time_infinite
;
853 if(read_ret
== ERANGE
) {
854 // last_read_state = LAST_EMPTY;
855 g_debug("End of trace");
857 g_error("Error happened in lttv_process_traceset_middle");
861 if (unlikely((count
== 0) && is_live
)) {
867 #endif /* BABEL_CLEANUP */
871 void lttv_process_traceset_end(LttvTracesetContext
*self
,
872 LttvHooks
*after_traceset
,
873 LttvHooks
*after_trace
,
874 LttvHooks
*after_tracefile
,
876 LttvHooksByIdChannelArray
*event_by_id_channel
)
878 /* Remove hooks from context. _after hooks are called by remove_hooks. */
879 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
880 lttv_traceset_context_remove_hooks(self
,
885 event_by_id_channel
);
888 /* Subtile modification :
889 * if tracefile has no event at or after the time requested, it is not put in
890 * the queue, as the next read would fail.
892 * Don't forget to empty the traceset pqueue before calling this.
894 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
896 guint i
, nb_tracefile
;
900 LttvTracefileContext
**tfc
;
902 nb_tracefile
= self
->tracefiles
->len
;
904 GTree
*pqueue
= self
->ts_context
->pqueue
;
906 for(i
= 0 ; i
< nb_tracefile
; i
++) {
907 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
909 g_tree_remove(pqueue
, *tfc
);
911 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
912 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
914 if(ret
== 0) { /* not ERANGE especially */
915 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
916 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
917 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
919 (*tfc
)->timestamp
= ltt_time_infinite
;
923 test_time
.tv_sec
= 0;
924 test_time
.tv_nsec
= 0;
925 g_debug("test tree after seek_time");
926 g_tree_foreach(pqueue
, test_tree
, NULL
);
930 /****************************************************************************
931 * lttv_process_trace_update
933 * process the changes that occur in the trace. Use a regular file polling to
934 * monitor the tracefile.
936 * Return the number of tracefile updated
937 ***************************************************************************/
938 guint
lttv_process_trace_update(LttvTraceContext
*self
)
941 guint nb_tracefile
= 0;
943 LttTracefile
*tf
= 0;
944 LttvTracefileContext
**tfc
;
946 /* Skip non live traces */
947 if(self
->t
->is_live
) {
949 nb_tracefile
= ltt_trace_update(self
->t
);
951 /* Recreate the pqueue following an update*/
952 GTree
*pqueue
= self
->ts_context
->pqueue
;
954 for(i
= 0 ; i
< self
->tracefiles
->len
; i
++) {
955 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
957 if(g_tree_remove(pqueue
, *tfc
) == FALSE
) {
958 if(tf
->buf_index
!= NULL
) {
960 if(ltt_tracefile_read(tf
) == 0) {
962 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
963 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
968 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
974 //Update self time span
975 self
->time_span
.end_time
= LTT_TIME_MAX(self
->t
->live_safe_timestamp
,
976 self
->time_span
.end_time
);
977 //Update self tscontext time span
978 self
->ts_context
->time_span
.end_time
= LTT_TIME_MAX(self
->time_span
.end_time
,
979 self
->ts_context
->time_span
.end_time
);
985 /****************************************************************************
986 * lttv_process_traceset_update
988 * process the changes that occur in the traceset.
990 * Return the number of file presently monitor(open for writting). If 0, the
991 * current traceset probably received all the data.
992 ***************************************************************************/
993 guint
lttv_process_traceset_update(LttvTracesetContext
*self
)
997 guint open_counter
= 0;
999 nb_trace
= lttv_traceset_number(self
->ts
);
1001 for(i
= 0 ; i
< nb_trace
; i
++) {
1002 open_counter
+= lttv_process_trace_update(self
->traces
[i
]);
1004 return open_counter
;
1007 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
1009 #ifdef WAIT_FOR_BABELTRACE_FIX_SEEK_ZERO
1010 struct bt_iter_pos seekpos
;
1012 seekpos
.type
= BT_SEEK_TIME
;
1013 seekpos
.u
.seek_time
= ltt_time_to_uint64(start
);
1014 ret
= bt_iter_set_pos(bt_ctf_get_iter(self
->iter
), &seekpos
);
1016 printf("Seek by time error: %s,\n",strerror(-ret
));
1019 #warning Seek time disabled because of babeltrace bugs
1022 #ifdef BABEL_CLEANUP
1027 LttvTraceContext
*tc
;
1029 //g_tree_destroy(self->pqueue);
1030 //self->pqueue = g_tree_new(compare_tracefile);
1032 nb_trace
= lttv_traceset_number(self
->ts
);
1033 for(i
= 0 ; i
< nb_trace
; i
++) {
1034 tc
= self
->traces
[i
];
1035 lttv_process_trace_seek_time(tc
, start
);
1041 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
1042 const LttvTracesetContextPosition
*pos
)
1045 /* If a position is set, seek the traceset to this position */
1046 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
1048 /* Test to see if the traces has been added to the trace set :
1049 * It should NEVER happen. Clear all positions if a new trace comes in. */
1050 /* FIXME I know this test is not optimal : should keep a number of
1051 * tracefiles variable in the traceset.. eventually */
1052 guint num_traces
= lttv_traceset_number(self
->ts
);
1054 for(i
=0; i
<num_traces
;i
++) {
1055 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1057 guint num_tracefiles
= tracefiles
->len
;
1058 for(j
=0;j
<num_tracefiles
;j
++)
1061 g_assert(tf_count
== pos
->tfcp
->len
);
1064 //g_tree_destroy(self->pqueue);
1065 //self->pqueue = g_tree_new(compare_tracefile);
1067 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
1068 LttvTracefileContextPosition
*tfcp
=
1069 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1071 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
1073 if(tfcp
->used
== TRUE
) {
1074 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
1076 tfcp
->tfc
->timestamp
=
1077 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
1078 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
1079 ltt_time_infinite
) != 0);
1080 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
1083 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
1088 test_time
.tv_sec
= 0;
1089 test_time
.tv_nsec
= 0;
1090 g_debug("test tree after seek_position");
1091 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
1100 #if 0 // pmf: temporary disable
1102 find_field(LttEventType
*et
, const GQuark field
)
1106 if(field
== 0) return NULL
;
1108 f
= ltt_eventtype_field_by_name(et
, field
);
1110 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
1111 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
1112 g_quark_to_string(ltt_eventtype_name(et
)));
1119 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
1121 return marker_get_info_from_id(th
->mdata
, th
->id
);
1124 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
1125 GQuark fields
[], LttvHook h
, gpointer hook_data
,
1126 GArray
**trace_hooks
)
1128 struct marker_info
*info
;
1130 int init_array_size
;
1132 struct marker_data
*mdata
;
1134 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
1135 if (unlikely(!group
|| group
->len
== 0)) {
1136 g_info("No channel for marker named %s.%s found",
1137 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1141 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
1142 info
= marker_get_info_from_name(mdata
, event_name
);
1143 if(unlikely(info
== NULL
)) {
1144 g_info("No marker named %s.%s found",
1145 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1149 init_array_size
= (*trace_hooks
)->len
;
1151 /* for each marker with the requested name */
1153 LttvTraceHook tmpth
;
1156 struct marker_field
*marker_field
;
1158 marker_id
= marker_get_id_from_info(mdata
, info
);
1161 tmpth
.mdata
= mdata
;
1162 tmpth
.channel
= channel_name
;
1163 tmpth
.id
= marker_id
;
1164 tmpth
.hook_data
= hook_data
;
1165 tmpth
.fields
= g_ptr_array_new();
1167 /* for each field requested */
1168 for(f
= fields
; f
&& *f
!= 0; f
++) {
1170 for_each_marker_field(marker_field
, info
) {
1171 if(marker_field
->name
== *f
) {
1173 g_ptr_array_add(tmpth
.fields
, marker_field
);
1178 /* Did not find the one of the fields in this instance of the
1179 marker. Print a warning and skip this marker completely.
1180 Still iterate on other markers with same name. */
1181 g_ptr_array_free(tmpth
.fields
, TRUE
);
1182 g_info("Field %s cannot be found in marker %s.%s",
1183 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1184 g_quark_to_string(event_name
));
1188 /* all fields were found: add the tracehook to the array */
1189 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1192 } while(info
!= NULL
);
1194 /* Error if no new trace hook has been added */
1195 if (init_array_size
== (*trace_hooks
)->len
) {
1196 g_info("No marker of name %s.%s has all requested fields",
1197 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1203 void lttv_trace_hook_remove_all(GArray
**th
)
1206 for(i
=0; i
<(*th
)->len
; i
++) {
1207 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1210 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1213 LttvTracesetContextPosition
*
1214 lttv_traceset_context_position_new(const LttvTracesetContext
*self
)
1216 guint num_traces
= lttv_traceset_number(self
->ts
);
1220 for(i
=0; i
<num_traces
;i
++) {
1221 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1223 guint num_tracefiles
= tracefiles
->len
;
1224 for(j
=0;j
<num_tracefiles
;j
++)
1227 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
, 1);
1228 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1229 sizeof(LttvTracefileContextPosition
),
1231 g_array_set_size(pos
->tfcp
, tf_count
);
1232 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1233 LttvTracefileContextPosition
*tfcp
=
1234 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1235 tfcp
->event
= ltt_event_position_new();
1238 pos
->timestamp
= ltt_time_infinite
;
1242 /* Save all positions, the ones with infinite time will have NULL
1244 /* note : a position must be destroyed when a trace is added/removed from a
1246 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1247 LttvTracesetContextPosition
*pos
)
1250 guint num_traces
= lttv_traceset_number(self
->ts
);
1253 pos
->timestamp
= ltt_time_infinite
;
1255 for(i
=0; i
<num_traces
;i
++) {
1256 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1258 guint num_tracefiles
= tracefiles
->len
;
1260 for(j
=0;j
<num_tracefiles
;j
++) {
1261 g_assert(tf_count
< pos
->tfcp
->len
);
1262 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1263 LttvTracefileContext
*, j
);
1264 LttvTracefileContextPosition
*tfcp
=
1265 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1269 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1270 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1271 ltt_event_position(event
, tfcp
->event
);
1272 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1273 pos
->timestamp
= (*tfc
)->timestamp
;
1279 //g_array_append_val(pos->tfc, *tfc);
1280 //g_array_append_val(pos->ep, ep);
1287 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1291 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1292 LttvTracefileContextPosition
*tfcp
=
1293 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1294 g_free(tfcp
->event
);
1298 g_array_free(pos
->tfcp
, TRUE
);
1302 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1303 const LttvTracesetContextPosition
*src
)
1306 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1308 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1310 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1312 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1314 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1316 dest_tfcp
->used
= src_tfcp
->used
;
1317 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1319 if(src_tfcp
->used
) {
1320 ltt_event_position_copy(
1325 dest
->timestamp
= src
->timestamp
;
1328 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1329 const LttvTracesetContextPosition
*pos
)
1334 if(pos
->tfcp
->len
== 0) {
1335 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1338 if(lttv_traceset_number(self
->ts
) == 0)
1341 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1342 LttvTracefileContextPosition
*tfcp
=
1343 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1345 if(tfcp
->used
== FALSE
) {
1346 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1350 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1353 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1355 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1359 if(ret
!= 0) return ret
;
1367 lttv_traceset_context_pos_pos_compare(const LttvTracesetContextPosition
*pos1
,
1368 const LttvTracesetContextPosition
*pos2
)
1373 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1374 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1379 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1382 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1383 LttvTracefileContextPosition
*tfcp1
=
1384 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1386 if(tfcp1
->used
== TRUE
) {
1387 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1388 LttvTracefileContextPosition
*tfcp2
=
1389 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1391 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1392 if(tfcp2
->used
== TRUE
)
1393 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1397 if(ret
!= 0) return ret
;
1402 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1403 LttvTracefileContextPosition
*tfcp2
=
1404 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1406 if(tfcp1
->tfc
== tfcp2
->tfc
)
1407 if(tfcp2
->used
== TRUE
) ret
= 1;
1408 if(ret
!= 0) return ret
;
1417 lttv_traceset_context_position_get_time(const LttvTracesetContextPosition
*pos
)
1419 return pos
->timestamp
;
1423 LttvTracefileContext
*
1424 lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1426 GTree
*pqueue
= self
->pqueue
;
1427 LttvTracefileContext
*tfc
= NULL
;
1429 g_tree_foreach(pqueue
, get_first
, &tfc
);
1434 /* lttv_process_traceset_synchronize_tracefiles
1436 * Use the sync_position field of the trace set context to synchronize each
1437 * tracefile with the previously saved position.
1439 * If no previous position has been saved, it simply does nothing.
1441 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1445 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1446 g_assert_cmpint(retval
, ==, 0);
1452 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1454 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1457 struct seek_back_data
{
1458 guint first_event
; /* Index of the first event in the array : we will always
1459 overwrite at this position : this is a circular array.
1462 guint n
; /* number of events requested */
1463 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1464 LttvFilter
*filter1
;
1465 LttvFilter
*filter2
;
1466 LttvFilter
*filter3
;
1468 check_handler
*check
;
1469 gboolean
*stop_flag
;
1470 guint raw_event_count
;
1473 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1475 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1476 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1477 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1478 LttvTracesetContextPosition
*pos
;
1480 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1482 sd
->raw_event_count
++;
1484 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1485 !lttv_filter_tree_parse(sd
->filter1
->head
,
1486 ltt_tracefile_get_event(tfc
->tf
),
1492 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1493 !lttv_filter_tree_parse(sd
->filter2
->head
,
1494 ltt_tracefile_get_event(tfc
->tf
),
1500 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1501 !lttv_filter_tree_parse(sd
->filter3
->head
,
1502 ltt_tracefile_get_event(tfc
->tf
),
1509 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1512 lttv_traceset_context_position_save(tsc
, pos
);
1514 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1515 else sd
->first_event
++;
1517 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1522 /* Seek back n events back from the current position.
1525 * @self The trace set context
1526 * @n number of events to jump over
1527 * @first_offset The initial offset value used.
1528 * never put first_offset at ltt_time_zero.
1529 * @time_seeker Function pointer of the function to use to seek time :
1530 * either lttv_process_traceset_seek_time
1531 * or lttv_state_traceset_seek_time_closest
1532 * @filter The filter to call.
1534 * Return value : the number of events found (might be lower than the number
1535 * requested if beginning of traceset is reached).
1537 * The first search will go back first_offset and try to find the last n events
1538 * matching the filter. If there are not enough, it will try to go back from the
1539 * new trace point from first_offset*2, and so on, until beginning of trace or n
1542 * Note : this function does not take in account the LttvFilter : use the
1543 * similar function found in state.c instead.
1545 * Note2 : the caller must make sure that the LttvTracesetContext does not
1546 * contain any hook, as process_traceset_middle is used in this routine.
1548 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1549 guint n
, LttTime first_offset
,
1550 seek_time_fct time_seeker
,
1551 check_handler
*check
,
1552 gboolean
*stop_flag
,
1553 LttvFilter
*filter1
,
1554 LttvFilter
*filter2
,
1555 LttvFilter
*filter3
,
1558 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1559 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1562 LttvTracesetContextPosition
*next_iter_end_pos
=
1563 lttv_traceset_context_position_new(self
);
1564 LttvTracesetContextPosition
*end_pos
=
1565 lttv_traceset_context_position_new(self
);
1566 LttvTracesetContextPosition
*saved_pos
=
1567 lttv_traceset_context_position_new(self
);
1570 LttTime time_offset
;
1571 struct seek_back_data sd
;
1572 LttvHooks
*hooks
= lttv_hooks_new();
1576 sd
.events_found
= 0;
1577 sd
.array
= g_ptr_array_sized_new(n
);
1578 sd
.filter1
= filter1
;
1579 sd
.filter2
= filter2
;
1580 sd
.filter3
= filter3
;
1584 sd
.stop_flag
= stop_flag
;
1585 sd
.raw_event_count
= 0;
1586 g_ptr_array_set_size(sd
.array
, n
);
1588 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1591 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1592 lttv_traceset_context_position_save(self
, saved_pos
);
1593 /* Get the current time from which we will offset */
1594 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1595 /* the position saved might be end of traceset... */
1596 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1597 time
= self
->time_span
.end_time
;
1599 time_offset
= first_offset
;
1601 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1603 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1606 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1608 /* We must seek the traceset back to time - time_offset */
1609 /* this time becomes the new reference time */
1610 if(ltt_time_compare(time
, time_offset
) > 0)
1611 time
= ltt_time_sub(time
, time_offset
);
1613 time
= self
->time_span
.start_time
;
1616 time_seeker(self
, time
);
1617 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1618 /* Resync the time in case of a seek_closest */
1619 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1620 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1621 time
= self
->time_span
.end_time
;
1624 /* Process the traceset, calling a hook which adds events
1625 * to the array, overwriting the tail. It changes first_event and
1626 * events_found too. */
1627 /* We would like to have a clean context here : no other hook than our's */
1629 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1630 G_MAXUINT
, end_pos
);
1632 /* stop criteria : - n events found
1633 * - asked_time < beginning of trace */
1634 if(sd
.events_found
< n
) {
1635 if(sd
.first_event
> 0) {
1636 /* Save the first position */
1637 LttvTracesetContextPosition
*pos
=
1638 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1639 lttv_traceset_context_position_copy(saved_pos
, pos
);
1641 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1642 /* Change array size to n - events_found */
1643 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1644 LttvTracesetContextPosition
*pos
=
1645 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1646 lttv_traceset_context_position_destroy(pos
);
1648 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1652 * Did not fill our event list and started before the beginning of the
1653 * trace. There is no hope to fill it then.
1654 * It is OK to compare with trace start time here because we explicitely
1655 * seeked by time (not by position), so we cannot miss multiple event
1656 * happening exactly at trace start.
1658 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) == 0)
1661 } else break; /* Second end criterion : n events found */
1663 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1666 lttv_traceset_context_position_destroy(end_pos
);
1667 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1669 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1671 if(sd
.events_found
>= n
) {
1672 /* Seek the traceset to the first event in the circular array */
1673 LttvTracesetContextPosition
*pos
=
1674 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1676 retval
= lttv_process_traceset_seek_position(self
, pos
);
1677 g_assert_cmpint(retval
, ==, 0);
1679 /* Will seek to the last saved position : in the worst case, it will be the
1680 * original position (if events_found is 0) */
1681 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1682 g_assert_cmpint(retval
, ==, 0);
1685 for(i
=0;i
<sd
.array
->len
;i
++) {
1686 LttvTracesetContextPosition
*pos
=
1687 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1688 lttv_traceset_context_position_destroy(pos
);
1690 g_ptr_array_free(sd
.array
, TRUE
);
1692 lttv_hooks_destroy(hooks
);
1694 lttv_traceset_context_position_destroy(saved_pos
);
1696 return sd
.events_found
;
1700 struct seek_forward_data
{
1701 guint event_count
; /* event counter */
1702 guint n
; /* requested number of events to jump over */
1703 LttvFilter
*filter1
;
1704 LttvFilter
*filter2
;
1705 LttvFilter
*filter3
;
1707 check_handler
*check
;
1708 gboolean
*stop_flag
;
1709 guint raw_event_count
; /* event counter */
1712 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1714 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1715 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1717 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1719 sd
->raw_event_count
++;
1721 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1722 !lttv_filter_tree_parse(sd
->filter1
->head
,
1723 ltt_tracefile_get_event(tfc
->tf
),
1729 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1730 !lttv_filter_tree_parse(sd
->filter2
->head
,
1731 ltt_tracefile_get_event(tfc
->tf
),
1737 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1738 !lttv_filter_tree_parse(sd
->filter3
->head
,
1739 ltt_tracefile_get_event(tfc
->tf
),
1747 if(sd
->event_count
>= sd
->n
)
1752 /* Seek back n events forward from the current position (1 to n)
1753 * 0 is ok too, but it will actually do nothing.
1756 * @self the trace set context
1757 * @n number of events to jump over
1758 * @filter filter to call.
1760 * returns : the number of events jumped over (may be less than requested if end
1761 * of traceset reached) */
1762 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1764 check_handler
*check
,
1765 gboolean
*stop_flag
,
1766 LttvFilter
*filter1
,
1767 LttvFilter
*filter2
,
1768 LttvFilter
*filter3
,
1771 struct seek_forward_data sd
;
1774 sd
.filter1
= filter1
;
1775 sd
.filter2
= filter2
;
1776 sd
.filter3
= filter3
;
1779 sd
.stop_flag
= stop_flag
;
1780 sd
.raw_event_count
= 0;
1782 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1784 LttvHooks
*hooks
= lttv_hooks_new();
1786 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1788 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1790 /* it will end on the end of traceset, or the fact that the
1791 * hook returns TRUE.
1793 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1796 /* Here, our position is either the end of traceset, or the exact position
1797 * after n events : leave it like this. This might be placed on an event that
1798 * will be filtered out, we don't care : all we know is that the following
1799 * event filtered in will be the right one. */
1801 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1803 lttv_hooks_destroy(hooks
);
1805 return sd
.event_count
;