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 LttvTraceset
* traceset
= self
->ts
;
124 int numTraces
= lttv_traceset_number(traceset
);
127 LttvTraceContext
*tc
;
130 time_span
->start_time
.tv_sec
= 0;
131 time_span
->start_time
.tv_nsec
= 0;
132 time_span
->end_time
.tv_sec
= 0;
133 time_span
->end_time
.tv_nsec
= 0;
135 for(i
=0; i
<numTraces
;i
++){
136 tc
= self
->traces
[i
];
139 ltt_trace_time_span_get(trace
, &s
, &e
);
140 tc
->time_span
.start_time
= s
;
141 tc
->time_span
.end_time
= e
;
144 time_span
->start_time
= s
;
145 time_span
->end_time
= e
;
147 if(s
.tv_sec
< time_span
->start_time
.tv_sec
148 || (s
.tv_sec
== time_span
->start_time
.tv_sec
149 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
150 time_span
->start_time
= s
;
151 if(e
.tv_sec
> time_span
->end_time
.tv_sec
152 || (e
.tv_sec
== time_span
->end_time
.tv_sec
153 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
154 time_span
->end_time
= e
;
159 static void init_tracefile_context(LttTracefile
*tracefile
,
160 LttvTraceContext
*tc
)
162 LttvTracefileContext
*tfc
;
163 LttvTracesetContext
*tsc
= tc
->ts_context
;
165 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
167 tfc
->index
= tc
->tracefiles
->len
;
168 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
173 tfc
->event
= lttv_hooks_new();
174 tfc
->event_by_id
= lttv_hooks_by_id_new();
175 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
176 tfc
->target_pid
= -1;
181 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
185 LttvTraceContext
*tc
;
187 GData
**tracefiles_groups
;
189 struct compute_tracefile_group_args args
;
191 struct bt_iter_pos begin_pos
;
193 nb_trace
= lttv_traceset_number(ts
);
195 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
196 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
197 self
->ts_a
= lttv_traceset_attribute(ts
);
199 begin_pos
.type
= BT_SEEK_BEGIN
;
201 self
->iter
= bt_ctf_iter_create(lttv_traceset_get_context(ts
),
204 self
->event_hooks
= lttv_hooks_new();
206 for(i
= 0 ; i
< nb_trace
; i
++) {
207 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
208 self
->traces
[i
] = tc
;
210 tc
->ts_context
= self
;
212 tc
->vt
= lttv_traceset_get(ts
, i
);
213 tc
->t
= lttv_trace(tc
->vt
);
214 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
215 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
216 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
217 sizeof(LttvTracefileContext
*), 10);
219 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
220 if(tracefiles_groups
!= NULL
) {
221 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
224 g_datalist_foreach(tracefiles_groups
,
225 (GDataForeachFunc
)compute_tracefile_group
,
232 self
->sync_position
= lttv_traceset_context_position_new(self
);
233 self
->pqueue
= g_tree_new(compare_tracefile
);
234 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
235 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
240 void fini(LttvTracesetContext
*self
)
242 guint i
, j
, nb_trace
, nb_tracefile
;
244 LttvTraceContext
*tc
;
246 LttvTracefileContext
**tfc
;
248 LttvTraceset
*ts
= self
->ts
;
250 g_tree_destroy(self
->pqueue
);
251 g_object_unref(self
->a
);
252 lttv_traceset_context_position_destroy(self
->sync_position
);
254 nb_trace
= lttv_traceset_number(ts
);
256 for(i
= 0 ; i
< nb_trace
; i
++) {
257 tc
= self
->traces
[i
];
259 g_object_unref(tc
->a
);
261 nb_tracefile
= tc
->tracefiles
->len
;
263 for(j
= 0 ; j
< nb_tracefile
; j
++) {
264 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
265 lttv_hooks_destroy((*tfc
)->event
);
266 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
267 g_object_unref((*tfc
)->a
);
268 g_object_unref(*tfc
);
270 g_array_free(tc
->tracefiles
, TRUE
);
273 g_free(self
->traces
);
277 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
278 LttvHooks
*before_traceset
,
279 LttvHooks
*before_trace
,
280 LttvHooks
*before_tracefile
,
282 LttvHooksByIdChannelArray
*event_by_id_channel
)
284 LttvTraceset
*ts
= self
->ts
;
288 LttvTraceContext
*tc
;
290 lttv_hooks_call(before_traceset
, self
);
292 lttv_hooks_add_list(self
->event_hooks
, event
);
294 nb_trace
= lttv_traceset_number(ts
);
296 for(i
= 0 ; i
< nb_trace
; i
++) {
297 tc
= self
->traces
[i
];
298 lttv_trace_context_add_hooks(tc
,
302 event_by_id_channel
);
307 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
308 LttvHooks
*after_traceset
,
309 LttvHooks
*after_trace
,
310 LttvHooks
*after_tracefile
,
312 LttvHooksByIdChannelArray
*event_by_id_channel
)
315 LttvTraceset
*ts
= self
->ts
;
319 LttvTraceContext
*tc
;
321 nb_trace
= lttv_traceset_number(ts
);
323 for(i
= 0 ; i
< nb_trace
; i
++) {
324 tc
= self
->traces
[i
];
325 lttv_trace_context_remove_hooks(tc
,
329 event_by_id_channel
);
332 lttv_hooks_call(after_traceset
, self
);
337 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
338 LttvHooks
*before_trace
,
339 LttvHooks
*before_tracefile
,
341 LttvHooksByIdChannelArray
*event_by_id_channel
)
343 guint i
, j
, nb_tracefile
;
344 LttvTracefileContext
**tfc
;
347 lttv_hooks_call(before_trace
, self
);
349 nb_tracefile
= self
->tracefiles
->len
;
351 for(i
= 0 ; i
< nb_tracefile
; i
++) {
352 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
354 lttv_tracefile_context_add_hooks(*tfc
,
358 if (event_by_id_channel
) {
359 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
360 LttvHooksByIdChannel
*hooks
=
361 &g_array_index(event_by_id_channel
->array
,
362 LttvHooksByIdChannel
, j
);
363 if (tf
->name
== hooks
->channel
)
364 lttv_tracefile_context_add_hooks(*tfc
,
375 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
376 LttvHooks
*after_trace
,
377 LttvHooks
*after_tracefile
,
379 LttvHooksByIdChannelArray
*event_by_id_channel
)
381 guint i
, j
, nb_tracefile
;
382 LttvTracefileContext
**tfc
;
385 nb_tracefile
= self
->tracefiles
->len
;
387 for(i
= 0 ; i
< nb_tracefile
; i
++) {
388 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
390 if (event_by_id_channel
) {
391 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
392 LttvHooksByIdChannel
*hooks
=
393 &g_array_index(event_by_id_channel
->array
,
394 LttvHooksByIdChannel
, j
);
395 if (tf
->name
== hooks
->channel
)
396 lttv_tracefile_context_remove_hooks(*tfc
,
402 lttv_tracefile_context_remove_hooks(*tfc
,
409 lttv_hooks_call(after_trace
, self
);
412 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
413 LttvHooks
*before_tracefile
,
415 LttvHooksById
*event_by_id
)
420 lttv_hooks_call(before_tracefile
, self
);
421 lttv_hooks_add_list(self
->event
, event
);
422 if(event_by_id
!= NULL
) {
423 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
424 index
= g_array_index(event_by_id
->array
, guint
, i
);
425 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
426 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
431 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
432 LttvHooks
*after_tracefile
,
434 LttvHooksById
*event_by_id
)
440 lttv_hooks_remove_list(self
->event
, event
);
441 if(event_by_id
!= NULL
) {
442 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
443 index
= g_array_index(event_by_id
->array
, guint
, i
);
444 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
446 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
450 lttv_hooks_call(after_tracefile
, self
);
453 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
455 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
459 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
461 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
465 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
467 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
471 static void traceset_context_instance_init(GTypeInstance
*instance
,
474 /* Be careful of anything which would not work well with shallow copies */
478 static void traceset_context_finalize(LttvTracesetContext
*self
)
480 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
481 ->finalize(G_OBJECT(self
));
485 static void traceset_context_class_init(LttvTracesetContextClass
*klass
)
487 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
489 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
492 klass
->new_traceset_context
= new_traceset_context
;
493 klass
->new_trace_context
= new_trace_context
;
494 klass
->new_tracefile_context
= new_tracefile_context
;
498 GType
lttv_traceset_context_get_type(void)
500 static GType type
= 0;
502 static const GTypeInfo info
= {
503 sizeof (LttvTracesetContextClass
),
504 NULL
, /* base_init */
505 NULL
, /* base_finalize */
506 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
507 NULL
, /* class_finalize */
508 NULL
, /* class_data */
509 sizeof (LttvTracesetContext
),
511 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
512 NULL
/* Value handling */
515 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
523 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
525 /* Be careful of anything which would not work well with shallow copies */
529 static void trace_context_finalize (LttvTraceContext
*self
)
531 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
532 finalize(G_OBJECT(self
));
536 static void trace_context_class_init (LttvTraceContextClass
*klass
)
538 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
540 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
544 GType
lttv_trace_context_get_type(void)
546 static GType type
= 0;
548 static const GTypeInfo info
= {
549 sizeof (LttvTraceContextClass
),
550 NULL
, /* base_init */
551 NULL
, /* base_finalize */
552 (GClassInitFunc
) trace_context_class_init
, /* class_init */
553 NULL
, /* class_finalize */
554 NULL
, /* class_data */
555 sizeof (LttvTraceContext
),
557 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
558 NULL
/* Value handling */
561 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
568 static void tracefile_context_instance_init (GTypeInstance
*instance
,
571 /* Be careful of anything which would not work well with shallow copies */
575 static void tracefile_context_finalize (LttvTracefileContext
*self
)
577 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
578 ->finalize(G_OBJECT(self
));
582 static void tracefile_context_class_init (LttvTracefileContextClass
*klass
)
584 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
586 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
590 GType
lttv_tracefile_context_get_type(void)
592 static GType type
= 0;
594 static const GTypeInfo info
= {
595 sizeof (LttvTracefileContextClass
),
596 NULL
, /* base_init */
597 NULL
, /* base_finalize */
598 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
599 NULL
, /* class_finalize */
600 NULL
, /* class_data */
601 sizeof (LttvTracefileContext
),
603 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
604 NULL
/* Value handling */
607 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
615 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
616 g_assert(key
== value
);
617 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
622 // Test to see if pqueue is traversed in the right order.
623 static LttTime test_time
;
625 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
627 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
629 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
630 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
631 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
632 tfc
->index
, tfc
->t_context
->index
);
634 if(user_data
!= NULL
) {
635 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
636 g_assert(compare_tracefile(user_data
, value
) == 0);
638 g_assert(compare_tracefile(user_data
, value
) != 0);
640 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
641 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
642 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
645 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
652 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
653 LttvHooks
*before_traceset
,
654 LttvHooks
*before_trace
,
655 LttvHooks
*before_tracefile
,
657 LttvHooksByIdChannelArray
*event_by_id_channel
)
660 /* simply add hooks in context. _before hooks are called by add_hooks. */
661 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
662 lttv_traceset_context_add_hooks(self
,
667 event_by_id_channel
);
671 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
673 /* Note : a _middle must be preceded from a _seek or another middle */
674 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
677 const LttvTracesetContextPosition
*end_position
)
682 struct bt_ctf_event
*bt_event
;
685 /* TODO ybrosseau 2012-03-16: Put in really in the traceset */
686 LttvTraceState state
;
690 if((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) {
694 if((bt_event
= bt_ctf_iter_read_event(self
->iter
)) != NULL
) {
698 event
.bt_event
= bt_event
;
699 event
.state
= &state
;
701 lttv_hooks_call(self
->event_hooks
, &event
);
703 if(bt_iter_next(bt_ctf_get_iter(self
->iter
)) < 0) {
704 printf("ERROR NEXT\n");
719 GTree
*pqueue
= self
->pqueue
;
721 LttvTracefileContext
*tfc
;
727 gboolean is_live
= FALSE
; /* set this flag if we detect a live trace */
731 //enum read_state last_read_state = LAST_NONE;
733 gint last_ret
= 0; /* return value of the last hook list called */
735 /* Get the next event from the pqueue, call its hooks,
736 reinsert in the pqueue the following event from the same tracefile
737 unless the tracefile is finished or the event is later than the
742 g_tree_foreach(pqueue
, get_first
, &tfc
);
743 /* End of traceset : tfc is NULL */
744 if(unlikely(tfc
== NULL
))
750 * - the maximum number of events specified?
751 * - the end position ?
753 * then the read is finished. We leave the queue in the same state and
756 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0) {
760 if(unlikely(last_ret
== TRUE
761 || ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
))
762 || (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
764 || ltt_time_compare(end
, tfc
->timestamp
) <= 0))
769 /* Get the tracefile with an event for the smallest time found. If two
770 or more tracefiles have events for the same time, hope that lookup
771 and remove are consistent. */
774 test_time
.tv_sec
= 0;
775 test_time
.tv_nsec
= 0;
776 g_debug("test tree before remove");
777 g_tree_foreach(pqueue
, test_tree
, tfc
);
779 g_tree_remove(pqueue
, tfc
);
782 test_time
.tv_sec
= 0;
783 test_time
.tv_nsec
= 0;
784 g_debug("test tree after remove");
785 g_tree_foreach(pqueue
, test_tree
, tfc
);
789 e
= ltt_tracefile_get_event(tfc
->tf
);
791 //if(last_read_state != LAST_EMPTY) {
792 /* Only call hooks if the last read has given an event or if we are at the
793 * first pass (not if last read returned end of tracefile) */
796 tfc
->target_pid
= -1; /* unset target PID */
798 * return values : 0 : continue read, 1 : go to next position and stop read,
799 * 2 : stay at the current position and stop read */
800 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
801 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
804 /* This is buggy : it won't work well with state computation */
805 if(unlikely(last_ret
== 2)) {
806 /* This is a case where we want to stay at this position and stop read. */
807 g_tree_insert(pqueue
, tfc
, tfc
);
812 read_ret
= ltt_tracefile_read(tfc
->tf
);
815 if(likely(!read_ret
)) {
816 //g_debug("An event is ready");
817 tfc
->timestamp
= ltt_event_time(e
);
820 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
821 g_tree_insert(pqueue
, tfc
, tfc
);
822 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0)
828 test_time
.tv_sec
= 0;
829 test_time
.tv_nsec
= 0;
830 g_debug("test tree after event ready");
831 g_tree_foreach(pqueue
, test_tree
, NULL
);
834 //last_read_state = LAST_OK;
836 tfc
->timestamp
= ltt_time_infinite
;
838 if(read_ret
== ERANGE
) {
839 // last_read_state = LAST_EMPTY;
840 g_debug("End of trace");
842 g_error("Error happened in lttv_process_traceset_middle");
846 if (unlikely((count
== 0) && is_live
)) {
852 #endif /* BABEL_CLEANUP */
856 void lttv_process_traceset_end(LttvTracesetContext
*self
,
857 LttvHooks
*after_traceset
,
858 LttvHooks
*after_trace
,
859 LttvHooks
*after_tracefile
,
861 LttvHooksByIdChannelArray
*event_by_id_channel
)
863 /* Remove hooks from context. _after hooks are called by remove_hooks. */
864 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
865 lttv_traceset_context_remove_hooks(self
,
870 event_by_id_channel
);
873 /* Subtile modification :
874 * if tracefile has no event at or after the time requested, it is not put in
875 * the queue, as the next read would fail.
877 * Don't forget to empty the traceset pqueue before calling this.
879 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
884 guint i
, nb_tracefile
;
888 LttvTracefileContext
**tfc
;
890 nb_tracefile
= self
->tracefiles
->len
;
892 GTree
*pqueue
= self
->ts_context
->pqueue
;
894 for(i
= 0 ; i
< nb_tracefile
; i
++) {
895 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
897 g_tree_remove(pqueue
, *tfc
);
899 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
900 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
902 if(ret
== 0) { /* not ERANGE especially */
903 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
904 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
905 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
907 (*tfc
)->timestamp
= ltt_time_infinite
;
911 test_time
.tv_sec
= 0;
912 test_time
.tv_nsec
= 0;
913 g_debug("test tree after seek_time");
914 g_tree_foreach(pqueue
, test_tree
, NULL
);
919 /****************************************************************************
920 * lttv_process_trace_update
922 * process the changes that occur in the trace. Use a regular file polling to
923 * monitor the tracefile.
925 * Return the number of tracefile updated
926 ***************************************************************************/
927 guint
lttv_process_trace_update(LttvTraceContext
*self
)
930 guint nb_tracefile
= 0;
932 LttTracefile
*tf
= 0;
933 LttvTracefileContext
**tfc
;
935 /* Skip non live traces */
936 if(self
->t
->is_live
) {
938 nb_tracefile
= ltt_trace_update(self
->t
);
940 /* Recreate the pqueue following an update*/
941 GTree
*pqueue
= self
->ts_context
->pqueue
;
943 for(i
= 0 ; i
< self
->tracefiles
->len
; i
++) {
944 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
946 if(g_tree_remove(pqueue
, *tfc
) == FALSE
) {
947 if(tf
->buf_index
!= NULL
) {
949 if(ltt_tracefile_read(tf
) == 0) {
951 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
952 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
957 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
963 //Update self time span
964 self
->time_span
.end_time
= LTT_TIME_MAX(self
->t
->live_safe_timestamp
,
965 self
->time_span
.end_time
);
966 //Update self tscontext time span
967 self
->ts_context
->time_span
.end_time
= LTT_TIME_MAX(self
->time_span
.end_time
,
968 self
->ts_context
->time_span
.end_time
);
974 /****************************************************************************
975 * lttv_process_traceset_update
977 * process the changes that occur in the traceset.
979 * Return the number of file presently monitor(open for writting). If 0, the
980 * current traceset probably received all the data.
981 ***************************************************************************/
982 guint
lttv_process_traceset_update(LttvTracesetContext
*self
)
986 guint open_counter
= 0;
988 nb_trace
= lttv_traceset_number(self
->ts
);
990 for(i
= 0 ; i
< nb_trace
; i
++) {
991 open_counter
+= lttv_process_trace_update(self
->traces
[i
]);
996 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
998 #ifdef WAIT_FOR_BABELTRACE_FIX_SEEK_ZERO
999 struct bt_iter_pos seekpos
;
1001 seekpos
.type
= BT_SEEK_TIME
;
1002 seekpos
.u
.seek_time
= ltt_time_to_uint64(start
);
1003 ret
= bt_iter_set_pos(bt_ctf_get_iter(self
->iter
), &seekpos
);
1005 printf("Seek by time error: %s,\n",strerror(-ret
));
1008 #warning Seek time disabled because of babeltrace bugs
1011 #ifdef BABEL_CLEANUP
1016 LttvTraceContext
*tc
;
1018 //g_tree_destroy(self->pqueue);
1019 //self->pqueue = g_tree_new(compare_tracefile);
1021 nb_trace
= lttv_traceset_number(self
->ts
);
1022 for(i
= 0 ; i
< nb_trace
; i
++) {
1023 tc
= self
->traces
[i
];
1024 lttv_process_trace_seek_time(tc
, start
);
1030 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
1031 const LttvTracesetContextPosition
*pos
)
1034 /* If a position is set, seek the traceset to this position */
1035 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
1037 /* Test to see if the traces has been added to the trace set :
1038 * It should NEVER happen. Clear all positions if a new trace comes in. */
1039 /* FIXME I know this test is not optimal : should keep a number of
1040 * tracefiles variable in the traceset.. eventually */
1041 guint num_traces
= lttv_traceset_number(self
->ts
);
1043 for(i
=0; i
<num_traces
;i
++) {
1044 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1046 guint num_tracefiles
= tracefiles
->len
;
1047 for(j
=0;j
<num_tracefiles
;j
++)
1050 g_assert(tf_count
== pos
->tfcp
->len
);
1053 //g_tree_destroy(self->pqueue);
1054 //self->pqueue = g_tree_new(compare_tracefile);
1056 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
1057 LttvTracefileContextPosition
*tfcp
=
1058 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1060 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
1062 if(tfcp
->used
== TRUE
) {
1063 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
1065 tfcp
->tfc
->timestamp
=
1066 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
1067 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
1068 ltt_time_infinite
) != 0);
1069 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
1072 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
1077 test_time
.tv_sec
= 0;
1078 test_time
.tv_nsec
= 0;
1079 g_debug("test tree after seek_position");
1080 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
1089 #if 0 // pmf: temporary disable
1091 find_field(LttEventType
*et
, const GQuark field
)
1095 if(field
== 0) return NULL
;
1097 f
= ltt_eventtype_field_by_name(et
, field
);
1099 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
1100 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
1101 g_quark_to_string(ltt_eventtype_name(et
)));
1108 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
1110 return marker_get_info_from_id(th
->mdata
, th
->id
);
1113 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
1114 GQuark fields
[], LttvHook h
, gpointer hook_data
,
1115 GArray
**trace_hooks
)
1117 struct marker_info
*info
;
1119 int init_array_size
;
1121 struct marker_data
*mdata
;
1123 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
1124 if (unlikely(!group
|| group
->len
== 0)) {
1125 g_info("No channel for marker named %s.%s found",
1126 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1130 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
1131 info
= marker_get_info_from_name(mdata
, event_name
);
1132 if(unlikely(info
== NULL
)) {
1133 g_info("No marker named %s.%s found",
1134 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1138 init_array_size
= (*trace_hooks
)->len
;
1140 /* for each marker with the requested name */
1142 LttvTraceHook tmpth
;
1145 struct marker_field
*marker_field
;
1147 marker_id
= marker_get_id_from_info(mdata
, info
);
1150 tmpth
.mdata
= mdata
;
1151 tmpth
.channel
= channel_name
;
1152 tmpth
.id
= marker_id
;
1153 tmpth
.hook_data
= hook_data
;
1154 tmpth
.fields
= g_ptr_array_new();
1156 /* for each field requested */
1157 for(f
= fields
; f
&& *f
!= 0; f
++) {
1159 for_each_marker_field(marker_field
, info
) {
1160 if(marker_field
->name
== *f
) {
1162 g_ptr_array_add(tmpth
.fields
, marker_field
);
1167 /* Did not find the one of the fields in this instance of the
1168 marker. Print a warning and skip this marker completely.
1169 Still iterate on other markers with same name. */
1170 g_ptr_array_free(tmpth
.fields
, TRUE
);
1171 g_info("Field %s cannot be found in marker %s.%s",
1172 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1173 g_quark_to_string(event_name
));
1177 /* all fields were found: add the tracehook to the array */
1178 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1181 } while(info
!= NULL
);
1183 /* Error if no new trace hook has been added */
1184 if (init_array_size
== (*trace_hooks
)->len
) {
1185 g_info("No marker of name %s.%s has all requested fields",
1186 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1192 void lttv_trace_hook_remove_all(GArray
**th
)
1195 for(i
=0; i
<(*th
)->len
; i
++) {
1196 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1199 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1202 LttvTracesetContextPosition
*
1203 lttv_traceset_context_position_new(const LttvTracesetContext
*self
)
1205 guint num_traces
= lttv_traceset_number(self
->ts
);
1209 for(i
=0; i
<num_traces
;i
++) {
1210 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1212 guint num_tracefiles
= tracefiles
->len
;
1213 for(j
=0;j
<num_tracefiles
;j
++)
1216 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
, 1);
1217 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1218 sizeof(LttvTracefileContextPosition
),
1220 g_array_set_size(pos
->tfcp
, tf_count
);
1221 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1222 LttvTracefileContextPosition
*tfcp
=
1223 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1224 tfcp
->event
= ltt_event_position_new();
1227 pos
->timestamp
= ltt_time_infinite
;
1231 /* Save all positions, the ones with infinite time will have NULL
1233 /* note : a position must be destroyed when a trace is added/removed from a
1235 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1236 LttvTracesetContextPosition
*pos
)
1239 guint num_traces
= lttv_traceset_number(self
->ts
);
1242 pos
->timestamp
= ltt_time_infinite
;
1244 for(i
=0; i
<num_traces
;i
++) {
1245 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1247 guint num_tracefiles
= tracefiles
->len
;
1249 for(j
=0;j
<num_tracefiles
;j
++) {
1250 g_assert(tf_count
< pos
->tfcp
->len
);
1251 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1252 LttvTracefileContext
*, j
);
1253 LttvTracefileContextPosition
*tfcp
=
1254 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1258 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1259 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1260 ltt_event_position(event
, tfcp
->event
);
1261 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1262 pos
->timestamp
= (*tfc
)->timestamp
;
1268 //g_array_append_val(pos->tfc, *tfc);
1269 //g_array_append_val(pos->ep, ep);
1276 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1280 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1281 LttvTracefileContextPosition
*tfcp
=
1282 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1283 g_free(tfcp
->event
);
1287 g_array_free(pos
->tfcp
, TRUE
);
1291 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1292 const LttvTracesetContextPosition
*src
)
1295 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1297 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1299 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1301 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1303 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1305 dest_tfcp
->used
= src_tfcp
->used
;
1306 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1308 if(src_tfcp
->used
) {
1309 ltt_event_position_copy(
1314 dest
->timestamp
= src
->timestamp
;
1317 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1318 const LttvTracesetContextPosition
*pos
)
1323 if(pos
->tfcp
->len
== 0) {
1324 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1327 if(lttv_traceset_number(self
->ts
) == 0)
1330 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1331 LttvTracefileContextPosition
*tfcp
=
1332 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1334 if(tfcp
->used
== FALSE
) {
1335 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1339 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1342 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1344 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1348 if(ret
!= 0) return ret
;
1356 lttv_traceset_context_pos_pos_compare(const LttvTracesetContextPosition
*pos1
,
1357 const LttvTracesetContextPosition
*pos2
)
1362 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1363 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1368 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1371 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1372 LttvTracefileContextPosition
*tfcp1
=
1373 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1375 if(tfcp1
->used
== TRUE
) {
1376 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1377 LttvTracefileContextPosition
*tfcp2
=
1378 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1380 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1381 if(tfcp2
->used
== TRUE
)
1382 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1386 if(ret
!= 0) return ret
;
1391 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1392 LttvTracefileContextPosition
*tfcp2
=
1393 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1395 if(tfcp1
->tfc
== tfcp2
->tfc
)
1396 if(tfcp2
->used
== TRUE
) ret
= 1;
1397 if(ret
!= 0) return ret
;
1406 lttv_traceset_context_position_get_time(const LttvTracesetContextPosition
*pos
)
1408 return pos
->timestamp
;
1412 LttvTracefileContext
*
1413 lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1415 GTree
*pqueue
= self
->pqueue
;
1416 LttvTracefileContext
*tfc
= NULL
;
1418 g_tree_foreach(pqueue
, get_first
, &tfc
);
1423 /* lttv_process_traceset_synchronize_tracefiles
1425 * Use the sync_position field of the trace set context to synchronize each
1426 * tracefile with the previously saved position.
1428 * If no previous position has been saved, it simply does nothing.
1430 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1434 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1435 g_assert_cmpint(retval
, ==, 0);
1441 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1443 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1446 struct seek_back_data
{
1447 guint first_event
; /* Index of the first event in the array : we will always
1448 overwrite at this position : this is a circular array.
1451 guint n
; /* number of events requested */
1452 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1453 LttvFilter
*filter1
;
1454 LttvFilter
*filter2
;
1455 LttvFilter
*filter3
;
1457 check_handler
*check
;
1458 gboolean
*stop_flag
;
1459 guint raw_event_count
;
1462 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1464 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1465 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1466 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1467 LttvTracesetContextPosition
*pos
;
1469 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1471 sd
->raw_event_count
++;
1473 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1474 !lttv_filter_tree_parse(sd
->filter1
->head
,
1475 ltt_tracefile_get_event(tfc
->tf
),
1481 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1482 !lttv_filter_tree_parse(sd
->filter2
->head
,
1483 ltt_tracefile_get_event(tfc
->tf
),
1489 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1490 !lttv_filter_tree_parse(sd
->filter3
->head
,
1491 ltt_tracefile_get_event(tfc
->tf
),
1498 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1501 lttv_traceset_context_position_save(tsc
, pos
);
1503 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1504 else sd
->first_event
++;
1506 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1511 /* Seek back n events back from the current position.
1514 * @self The trace set context
1515 * @n number of events to jump over
1516 * @first_offset The initial offset value used.
1517 * never put first_offset at ltt_time_zero.
1518 * @time_seeker Function pointer of the function to use to seek time :
1519 * either lttv_process_traceset_seek_time
1520 * or lttv_state_traceset_seek_time_closest
1521 * @filter The filter to call.
1523 * Return value : the number of events found (might be lower than the number
1524 * requested if beginning of traceset is reached).
1526 * The first search will go back first_offset and try to find the last n events
1527 * matching the filter. If there are not enough, it will try to go back from the
1528 * new trace point from first_offset*2, and so on, until beginning of trace or n
1531 * Note : this function does not take in account the LttvFilter : use the
1532 * similar function found in state.c instead.
1534 * Note2 : the caller must make sure that the LttvTracesetContext does not
1535 * contain any hook, as process_traceset_middle is used in this routine.
1537 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1538 guint n
, LttTime first_offset
,
1539 seek_time_fct time_seeker
,
1540 check_handler
*check
,
1541 gboolean
*stop_flag
,
1542 LttvFilter
*filter1
,
1543 LttvFilter
*filter2
,
1544 LttvFilter
*filter3
,
1547 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1548 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1551 LttvTracesetContextPosition
*next_iter_end_pos
=
1552 lttv_traceset_context_position_new(self
);
1553 LttvTracesetContextPosition
*end_pos
=
1554 lttv_traceset_context_position_new(self
);
1555 LttvTracesetContextPosition
*saved_pos
=
1556 lttv_traceset_context_position_new(self
);
1559 LttTime time_offset
;
1560 struct seek_back_data sd
;
1561 LttvHooks
*hooks
= lttv_hooks_new();
1565 sd
.events_found
= 0;
1566 sd
.array
= g_ptr_array_sized_new(n
);
1567 sd
.filter1
= filter1
;
1568 sd
.filter2
= filter2
;
1569 sd
.filter3
= filter3
;
1573 sd
.stop_flag
= stop_flag
;
1574 sd
.raw_event_count
= 0;
1575 g_ptr_array_set_size(sd
.array
, n
);
1577 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1580 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1581 lttv_traceset_context_position_save(self
, saved_pos
);
1582 /* Get the current time from which we will offset */
1583 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1584 /* the position saved might be end of traceset... */
1585 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1586 time
= self
->time_span
.end_time
;
1588 time_offset
= first_offset
;
1590 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1592 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1595 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1597 /* We must seek the traceset back to time - time_offset */
1598 /* this time becomes the new reference time */
1599 if(ltt_time_compare(time
, time_offset
) > 0)
1600 time
= ltt_time_sub(time
, time_offset
);
1602 time
= self
->time_span
.start_time
;
1605 time_seeker(self
, time
);
1606 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1607 /* Resync the time in case of a seek_closest */
1608 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1609 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1610 time
= self
->time_span
.end_time
;
1613 /* Process the traceset, calling a hook which adds events
1614 * to the array, overwriting the tail. It changes first_event and
1615 * events_found too. */
1616 /* We would like to have a clean context here : no other hook than our's */
1618 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1619 G_MAXUINT
, end_pos
);
1621 /* stop criteria : - n events found
1622 * - asked_time < beginning of trace */
1623 if(sd
.events_found
< n
) {
1624 if(sd
.first_event
> 0) {
1625 /* Save the first position */
1626 LttvTracesetContextPosition
*pos
=
1627 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1628 lttv_traceset_context_position_copy(saved_pos
, pos
);
1630 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1631 /* Change array size to n - events_found */
1632 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1633 LttvTracesetContextPosition
*pos
=
1634 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1635 lttv_traceset_context_position_destroy(pos
);
1637 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1641 * Did not fill our event list and started before the beginning of the
1642 * trace. There is no hope to fill it then.
1643 * It is OK to compare with trace start time here because we explicitely
1644 * seeked by time (not by position), so we cannot miss multiple event
1645 * happening exactly at trace start.
1647 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) == 0)
1650 } else break; /* Second end criterion : n events found */
1652 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1655 lttv_traceset_context_position_destroy(end_pos
);
1656 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1658 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1660 if(sd
.events_found
>= n
) {
1661 /* Seek the traceset to the first event in the circular array */
1662 LttvTracesetContextPosition
*pos
=
1663 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1665 retval
= lttv_process_traceset_seek_position(self
, pos
);
1666 g_assert_cmpint(retval
, ==, 0);
1668 /* Will seek to the last saved position : in the worst case, it will be the
1669 * original position (if events_found is 0) */
1670 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1671 g_assert_cmpint(retval
, ==, 0);
1674 for(i
=0;i
<sd
.array
->len
;i
++) {
1675 LttvTracesetContextPosition
*pos
=
1676 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1677 lttv_traceset_context_position_destroy(pos
);
1679 g_ptr_array_free(sd
.array
, TRUE
);
1681 lttv_hooks_destroy(hooks
);
1683 lttv_traceset_context_position_destroy(saved_pos
);
1685 return sd
.events_found
;
1689 struct seek_forward_data
{
1690 guint event_count
; /* event counter */
1691 guint n
; /* requested number of events to jump over */
1692 LttvFilter
*filter1
;
1693 LttvFilter
*filter2
;
1694 LttvFilter
*filter3
;
1696 check_handler
*check
;
1697 gboolean
*stop_flag
;
1698 guint raw_event_count
; /* event counter */
1701 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1703 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1704 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1706 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1708 sd
->raw_event_count
++;
1710 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1711 !lttv_filter_tree_parse(sd
->filter1
->head
,
1712 ltt_tracefile_get_event(tfc
->tf
),
1718 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1719 !lttv_filter_tree_parse(sd
->filter2
->head
,
1720 ltt_tracefile_get_event(tfc
->tf
),
1726 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1727 !lttv_filter_tree_parse(sd
->filter3
->head
,
1728 ltt_tracefile_get_event(tfc
->tf
),
1736 if(sd
->event_count
>= sd
->n
)
1741 /* Seek back n events forward from the current position (1 to n)
1742 * 0 is ok too, but it will actually do nothing.
1745 * @self the trace set context
1746 * @n number of events to jump over
1747 * @filter filter to call.
1749 * returns : the number of events jumped over (may be less than requested if end
1750 * of traceset reached) */
1751 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1753 check_handler
*check
,
1754 gboolean
*stop_flag
,
1755 LttvFilter
*filter1
,
1756 LttvFilter
*filter2
,
1757 LttvFilter
*filter3
,
1760 struct seek_forward_data sd
;
1763 sd
.filter1
= filter1
;
1764 sd
.filter2
= filter2
;
1765 sd
.filter3
= filter3
;
1768 sd
.stop_flag
= stop_flag
;
1769 sd
.raw_event_count
= 0;
1771 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1773 LttvHooks
*hooks
= lttv_hooks_new();
1775 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1777 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1779 /* it will end on the end of traceset, or the fact that the
1780 * hook returns TRUE.
1782 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1785 /* Here, our position is either the end of traceset, or the exact position
1786 * after n events : leave it like this. This might be placed on an event that
1787 * will be filtered out, we don't care : all we know is that the following
1788 * event filtered in will be the right one. */
1790 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1792 lttv_hooks_destroy(hooks
);
1794 return sd
.event_count
;