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 self
->tmpState
= g_new(LttvTraceState
*, 1);
211 for(i
= 0 ; i
< nb_trace
; i
++) {
212 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
213 self
->traces
[i
] = tc
;
215 tc
->ts_context
= self
;
217 tc
->vt
= lttv_traceset_get(ts
, i
);
219 tc
->t
= lttv_trace(tc
->vt
);
221 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
222 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
223 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
224 sizeof(LttvTracefileContext
*), 10);
227 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
228 if(tracefiles_groups
!= NULL
) {
229 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
232 g_datalist_foreach(tracefiles_groups
,
233 (GDataForeachFunc
)compute_tracefile_group
,
240 self
->sync_position
= lttv_traceset_context_position_new(self
);
241 self
->pqueue
= g_tree_new(compare_tracefile
);
242 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
243 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
248 void fini(LttvTracesetContext
*self
)
250 guint i
, j
, nb_trace
, nb_tracefile
;
252 LttvTraceContext
*tc
;
254 LttvTracefileContext
**tfc
;
256 LttvTraceset
*ts
= self
->ts
;
258 g_tree_destroy(self
->pqueue
);
259 g_object_unref(self
->a
);
260 lttv_traceset_context_position_destroy(self
->sync_position
);
262 nb_trace
= lttv_traceset_number(ts
);
264 for(i
= 0 ; i
< nb_trace
; i
++) {
265 tc
= self
->traces
[i
];
267 g_object_unref(tc
->a
);
269 nb_tracefile
= tc
->tracefiles
->len
;
271 for(j
= 0 ; j
< nb_tracefile
; j
++) {
272 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
273 lttv_hooks_destroy((*tfc
)->event
);
274 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
275 g_object_unref((*tfc
)->a
);
276 g_object_unref(*tfc
);
278 g_array_free(tc
->tracefiles
, TRUE
);
281 g_free(self
->traces
);
285 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
286 LttvHooks
*before_traceset
,
287 LttvHooks
*before_trace
,
288 LttvHooks
*before_tracefile
,
290 LttvHooksByIdChannelArray
*event_by_id_channel
)
292 LttvTraceset
*ts
= self
->ts
;
296 LttvTraceContext
*tc
;
298 lttv_hooks_call(before_traceset
, self
);
300 lttv_hooks_add_list(self
->event_hooks
, event
);
302 nb_trace
= lttv_traceset_number(ts
);
304 for(i
= 0 ; i
< nb_trace
; i
++) {
305 tc
= self
->traces
[i
];
306 lttv_trace_context_add_hooks(tc
,
310 event_by_id_channel
);
315 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
316 LttvHooks
*after_traceset
,
317 LttvHooks
*after_trace
,
318 LttvHooks
*after_tracefile
,
320 LttvHooksByIdChannelArray
*event_by_id_channel
)
323 LttvTraceset
*ts
= self
->ts
;
327 LttvTraceContext
*tc
;
329 nb_trace
= lttv_traceset_number(ts
);
331 for(i
= 0 ; i
< nb_trace
; i
++) {
332 tc
= self
->traces
[i
];
333 lttv_trace_context_remove_hooks(tc
,
337 event_by_id_channel
);
340 lttv_hooks_call(after_traceset
, self
);
345 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
346 LttvHooks
*before_trace
,
347 LttvHooks
*before_tracefile
,
349 LttvHooksByIdChannelArray
*event_by_id_channel
)
351 guint i
, j
, nb_tracefile
;
352 LttvTracefileContext
**tfc
;
355 lttv_hooks_call(before_trace
, self
);
357 nb_tracefile
= self
->tracefiles
->len
;
359 for(i
= 0 ; i
< nb_tracefile
; i
++) {
360 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
362 lttv_tracefile_context_add_hooks(*tfc
,
366 if (event_by_id_channel
) {
367 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
368 LttvHooksByIdChannel
*hooks
=
369 &g_array_index(event_by_id_channel
->array
,
370 LttvHooksByIdChannel
, j
);
371 if (tf
->name
== hooks
->channel
)
372 lttv_tracefile_context_add_hooks(*tfc
,
383 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
384 LttvHooks
*after_trace
,
385 LttvHooks
*after_tracefile
,
387 LttvHooksByIdChannelArray
*event_by_id_channel
)
389 guint i
, j
, nb_tracefile
;
390 LttvTracefileContext
**tfc
;
393 nb_tracefile
= self
->tracefiles
->len
;
395 for(i
= 0 ; i
< nb_tracefile
; i
++) {
396 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
398 if (event_by_id_channel
) {
399 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
400 LttvHooksByIdChannel
*hooks
=
401 &g_array_index(event_by_id_channel
->array
,
402 LttvHooksByIdChannel
, j
);
403 if (tf
->name
== hooks
->channel
)
404 lttv_tracefile_context_remove_hooks(*tfc
,
410 lttv_tracefile_context_remove_hooks(*tfc
,
417 lttv_hooks_call(after_trace
, self
);
420 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
421 LttvHooks
*before_tracefile
,
423 LttvHooksById
*event_by_id
)
428 lttv_hooks_call(before_tracefile
, self
);
429 lttv_hooks_add_list(self
->event
, event
);
430 if(event_by_id
!= NULL
) {
431 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
432 index
= g_array_index(event_by_id
->array
, guint
, i
);
433 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
434 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
439 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
440 LttvHooks
*after_tracefile
,
442 LttvHooksById
*event_by_id
)
448 lttv_hooks_remove_list(self
->event
, event
);
449 if(event_by_id
!= NULL
) {
450 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
451 index
= g_array_index(event_by_id
->array
, guint
, i
);
452 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
454 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
458 lttv_hooks_call(after_tracefile
, self
);
461 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
463 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
467 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
469 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
473 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
475 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
479 static void traceset_context_instance_init(GTypeInstance
*instance
,
482 /* Be careful of anything which would not work well with shallow copies */
486 static void traceset_context_finalize(LttvTracesetContext
*self
)
488 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
489 ->finalize(G_OBJECT(self
));
493 static void traceset_context_class_init(LttvTracesetContextClass
*klass
)
495 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
497 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
500 klass
->new_traceset_context
= new_traceset_context
;
501 klass
->new_trace_context
= new_trace_context
;
502 klass
->new_tracefile_context
= new_tracefile_context
;
506 GType
lttv_traceset_context_get_type(void)
508 static GType type
= 0;
510 static const GTypeInfo info
= {
511 sizeof (LttvTracesetContextClass
),
512 NULL
, /* base_init */
513 NULL
, /* base_finalize */
514 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
515 NULL
, /* class_finalize */
516 NULL
, /* class_data */
517 sizeof (LttvTracesetContext
),
519 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
520 NULL
/* Value handling */
523 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
531 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
533 /* Be careful of anything which would not work well with shallow copies */
537 static void trace_context_finalize (LttvTraceContext
*self
)
539 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
540 finalize(G_OBJECT(self
));
544 static void trace_context_class_init (LttvTraceContextClass
*klass
)
546 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
548 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
552 GType
lttv_trace_context_get_type(void)
554 static GType type
= 0;
556 static const GTypeInfo info
= {
557 sizeof (LttvTraceContextClass
),
558 NULL
, /* base_init */
559 NULL
, /* base_finalize */
560 (GClassInitFunc
) trace_context_class_init
, /* class_init */
561 NULL
, /* class_finalize */
562 NULL
, /* class_data */
563 sizeof (LttvTraceContext
),
565 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
566 NULL
/* Value handling */
569 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
576 static void tracefile_context_instance_init (GTypeInstance
*instance
,
579 /* Be careful of anything which would not work well with shallow copies */
583 static void tracefile_context_finalize (LttvTracefileContext
*self
)
585 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
586 ->finalize(G_OBJECT(self
));
590 static void tracefile_context_class_init (LttvTracefileContextClass
*klass
)
592 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
594 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
598 GType
lttv_tracefile_context_get_type(void)
600 static GType type
= 0;
602 static const GTypeInfo info
= {
603 sizeof (LttvTracefileContextClass
),
604 NULL
, /* base_init */
605 NULL
, /* base_finalize */
606 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
607 NULL
, /* class_finalize */
608 NULL
, /* class_data */
609 sizeof (LttvTracefileContext
),
611 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
612 NULL
/* Value handling */
615 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
623 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
624 g_assert(key
== value
);
625 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
630 // Test to see if pqueue is traversed in the right order.
631 static LttTime test_time
;
633 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
635 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
637 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
638 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
639 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
640 tfc
->index
, tfc
->t_context
->index
);
642 if(user_data
!= NULL
) {
643 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
644 g_assert(compare_tracefile(user_data
, value
) == 0);
646 g_assert(compare_tracefile(user_data
, value
) != 0);
648 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
649 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
650 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
653 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
660 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
661 LttvHooks
*before_traceset
,
662 LttvHooks
*before_trace
,
663 LttvHooks
*before_tracefile
,
665 LttvHooksByIdChannelArray
*event_by_id_channel
)
668 /* simply add hooks in context. _before hooks are called by add_hooks. */
669 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
670 lttv_traceset_context_add_hooks(self
,
675 event_by_id_channel
);
679 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
681 /* Note : a _middle must be preceded from a _seek or another middle */
682 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
685 const LttvTracesetContextPosition
*end_position
)
690 struct bt_ctf_event
*bt_event
;
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 /* TODO ybrosseau 2012-04-01: use bt_ctf_get_trace_handle
706 to retrieve the right state container */
707 event
.state
= self
->tmpState
;
709 lttv_hooks_call(self
->event_hooks
, &event
);
711 if(bt_iter_next(bt_ctf_get_iter(self
->iter
)) < 0) {
712 printf("ERROR NEXT\n");
727 GTree
*pqueue
= self
->pqueue
;
729 LttvTracefileContext
*tfc
;
735 gboolean is_live
= FALSE
; /* set this flag if we detect a live trace */
739 //enum read_state last_read_state = LAST_NONE;
741 gint last_ret
= 0; /* return value of the last hook list called */
743 /* Get the next event from the pqueue, call its hooks,
744 reinsert in the pqueue the following event from the same tracefile
745 unless the tracefile is finished or the event is later than the
750 g_tree_foreach(pqueue
, get_first
, &tfc
);
751 /* End of traceset : tfc is NULL */
752 if(unlikely(tfc
== NULL
))
758 * - the maximum number of events specified?
759 * - the end position ?
761 * then the read is finished. We leave the queue in the same state and
764 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0) {
768 if(unlikely(last_ret
== TRUE
769 || ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
))
770 || (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
772 || ltt_time_compare(end
, tfc
->timestamp
) <= 0))
777 /* Get the tracefile with an event for the smallest time found. If two
778 or more tracefiles have events for the same time, hope that lookup
779 and remove are consistent. */
782 test_time
.tv_sec
= 0;
783 test_time
.tv_nsec
= 0;
784 g_debug("test tree before remove");
785 g_tree_foreach(pqueue
, test_tree
, tfc
);
787 g_tree_remove(pqueue
, tfc
);
790 test_time
.tv_sec
= 0;
791 test_time
.tv_nsec
= 0;
792 g_debug("test tree after remove");
793 g_tree_foreach(pqueue
, test_tree
, tfc
);
797 e
= ltt_tracefile_get_event(tfc
->tf
);
799 //if(last_read_state != LAST_EMPTY) {
800 /* Only call hooks if the last read has given an event or if we are at the
801 * first pass (not if last read returned end of tracefile) */
804 tfc
->target_pid
= -1; /* unset target PID */
806 * return values : 0 : continue read, 1 : go to next position and stop read,
807 * 2 : stay at the current position and stop read */
808 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
809 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
812 /* This is buggy : it won't work well with state computation */
813 if(unlikely(last_ret
== 2)) {
814 /* This is a case where we want to stay at this position and stop read. */
815 g_tree_insert(pqueue
, tfc
, tfc
);
820 read_ret
= ltt_tracefile_read(tfc
->tf
);
823 if(likely(!read_ret
)) {
824 //g_debug("An event is ready");
825 tfc
->timestamp
= ltt_event_time(e
);
828 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
829 g_tree_insert(pqueue
, tfc
, tfc
);
830 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0)
836 test_time
.tv_sec
= 0;
837 test_time
.tv_nsec
= 0;
838 g_debug("test tree after event ready");
839 g_tree_foreach(pqueue
, test_tree
, NULL
);
842 //last_read_state = LAST_OK;
844 tfc
->timestamp
= ltt_time_infinite
;
846 if(read_ret
== ERANGE
) {
847 // last_read_state = LAST_EMPTY;
848 g_debug("End of trace");
850 g_error("Error happened in lttv_process_traceset_middle");
854 if (unlikely((count
== 0) && is_live
)) {
860 #endif /* BABEL_CLEANUP */
864 void lttv_process_traceset_end(LttvTracesetContext
*self
,
865 LttvHooks
*after_traceset
,
866 LttvHooks
*after_trace
,
867 LttvHooks
*after_tracefile
,
869 LttvHooksByIdChannelArray
*event_by_id_channel
)
871 /* Remove hooks from context. _after hooks are called by remove_hooks. */
872 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
873 lttv_traceset_context_remove_hooks(self
,
878 event_by_id_channel
);
881 /* Subtile modification :
882 * if tracefile has no event at or after the time requested, it is not put in
883 * the queue, as the next read would fail.
885 * Don't forget to empty the traceset pqueue before calling this.
887 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
889 guint i
, nb_tracefile
;
893 LttvTracefileContext
**tfc
;
895 nb_tracefile
= self
->tracefiles
->len
;
897 GTree
*pqueue
= self
->ts_context
->pqueue
;
899 for(i
= 0 ; i
< nb_tracefile
; i
++) {
900 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
902 g_tree_remove(pqueue
, *tfc
);
904 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
905 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
907 if(ret
== 0) { /* not ERANGE especially */
908 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
909 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
910 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
912 (*tfc
)->timestamp
= ltt_time_infinite
;
916 test_time
.tv_sec
= 0;
917 test_time
.tv_nsec
= 0;
918 g_debug("test tree after seek_time");
919 g_tree_foreach(pqueue
, test_tree
, NULL
);
923 /****************************************************************************
924 * lttv_process_trace_update
926 * process the changes that occur in the trace. Use a regular file polling to
927 * monitor the tracefile.
929 * Return the number of tracefile updated
930 ***************************************************************************/
931 guint
lttv_process_trace_update(LttvTraceContext
*self
)
934 guint nb_tracefile
= 0;
936 LttTracefile
*tf
= 0;
937 LttvTracefileContext
**tfc
;
939 /* Skip non live traces */
940 if(self
->t
->is_live
) {
942 nb_tracefile
= ltt_trace_update(self
->t
);
944 /* Recreate the pqueue following an update*/
945 GTree
*pqueue
= self
->ts_context
->pqueue
;
947 for(i
= 0 ; i
< self
->tracefiles
->len
; i
++) {
948 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
950 if(g_tree_remove(pqueue
, *tfc
) == FALSE
) {
951 if(tf
->buf_index
!= NULL
) {
953 if(ltt_tracefile_read(tf
) == 0) {
955 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
956 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
961 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
967 //Update self time span
968 self
->time_span
.end_time
= LTT_TIME_MAX(self
->t
->live_safe_timestamp
,
969 self
->time_span
.end_time
);
970 //Update self tscontext time span
971 self
->ts_context
->time_span
.end_time
= LTT_TIME_MAX(self
->time_span
.end_time
,
972 self
->ts_context
->time_span
.end_time
);
978 /****************************************************************************
979 * lttv_process_traceset_update
981 * process the changes that occur in the traceset.
983 * Return the number of file presently monitor(open for writting). If 0, the
984 * current traceset probably received all the data.
985 ***************************************************************************/
986 guint
lttv_process_traceset_update(LttvTracesetContext
*self
)
990 guint open_counter
= 0;
992 nb_trace
= lttv_traceset_number(self
->ts
);
994 for(i
= 0 ; i
< nb_trace
; i
++) {
995 open_counter
+= lttv_process_trace_update(self
->traces
[i
]);
1000 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
1002 #ifdef WAIT_FOR_BABELTRACE_FIX_SEEK_ZERO
1003 struct bt_iter_pos seekpos
;
1005 seekpos
.type
= BT_SEEK_TIME
;
1006 seekpos
.u
.seek_time
= ltt_time_to_uint64(start
);
1007 ret
= bt_iter_set_pos(bt_ctf_get_iter(self
->iter
), &seekpos
);
1009 printf("Seek by time error: %s,\n",strerror(-ret
));
1012 #warning Seek time disabled because of babeltrace bugs
1015 #ifdef BABEL_CLEANUP
1020 LttvTraceContext
*tc
;
1022 //g_tree_destroy(self->pqueue);
1023 //self->pqueue = g_tree_new(compare_tracefile);
1025 nb_trace
= lttv_traceset_number(self
->ts
);
1026 for(i
= 0 ; i
< nb_trace
; i
++) {
1027 tc
= self
->traces
[i
];
1028 lttv_process_trace_seek_time(tc
, start
);
1034 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
1035 const LttvTracesetContextPosition
*pos
)
1038 /* If a position is set, seek the traceset to this position */
1039 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
1041 /* Test to see if the traces has been added to the trace set :
1042 * It should NEVER happen. Clear all positions if a new trace comes in. */
1043 /* FIXME I know this test is not optimal : should keep a number of
1044 * tracefiles variable in the traceset.. eventually */
1045 guint num_traces
= lttv_traceset_number(self
->ts
);
1047 for(i
=0; i
<num_traces
;i
++) {
1048 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1050 guint num_tracefiles
= tracefiles
->len
;
1051 for(j
=0;j
<num_tracefiles
;j
++)
1054 g_assert(tf_count
== pos
->tfcp
->len
);
1057 //g_tree_destroy(self->pqueue);
1058 //self->pqueue = g_tree_new(compare_tracefile);
1060 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
1061 LttvTracefileContextPosition
*tfcp
=
1062 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1064 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
1066 if(tfcp
->used
== TRUE
) {
1067 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
1069 tfcp
->tfc
->timestamp
=
1070 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
1071 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
1072 ltt_time_infinite
) != 0);
1073 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
1076 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
1081 test_time
.tv_sec
= 0;
1082 test_time
.tv_nsec
= 0;
1083 g_debug("test tree after seek_position");
1084 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
1093 #if 0 // pmf: temporary disable
1095 find_field(LttEventType
*et
, const GQuark field
)
1099 if(field
== 0) return NULL
;
1101 f
= ltt_eventtype_field_by_name(et
, field
);
1103 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
1104 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
1105 g_quark_to_string(ltt_eventtype_name(et
)));
1112 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
1114 return marker_get_info_from_id(th
->mdata
, th
->id
);
1117 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
1118 GQuark fields
[], LttvHook h
, gpointer hook_data
,
1119 GArray
**trace_hooks
)
1121 struct marker_info
*info
;
1123 int init_array_size
;
1125 struct marker_data
*mdata
;
1127 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
1128 if (unlikely(!group
|| group
->len
== 0)) {
1129 g_info("No channel for marker named %s.%s found",
1130 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1134 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
1135 info
= marker_get_info_from_name(mdata
, event_name
);
1136 if(unlikely(info
== NULL
)) {
1137 g_info("No marker named %s.%s found",
1138 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1142 init_array_size
= (*trace_hooks
)->len
;
1144 /* for each marker with the requested name */
1146 LttvTraceHook tmpth
;
1149 struct marker_field
*marker_field
;
1151 marker_id
= marker_get_id_from_info(mdata
, info
);
1154 tmpth
.mdata
= mdata
;
1155 tmpth
.channel
= channel_name
;
1156 tmpth
.id
= marker_id
;
1157 tmpth
.hook_data
= hook_data
;
1158 tmpth
.fields
= g_ptr_array_new();
1160 /* for each field requested */
1161 for(f
= fields
; f
&& *f
!= 0; f
++) {
1163 for_each_marker_field(marker_field
, info
) {
1164 if(marker_field
->name
== *f
) {
1166 g_ptr_array_add(tmpth
.fields
, marker_field
);
1171 /* Did not find the one of the fields in this instance of the
1172 marker. Print a warning and skip this marker completely.
1173 Still iterate on other markers with same name. */
1174 g_ptr_array_free(tmpth
.fields
, TRUE
);
1175 g_info("Field %s cannot be found in marker %s.%s",
1176 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1177 g_quark_to_string(event_name
));
1181 /* all fields were found: add the tracehook to the array */
1182 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1185 } while(info
!= NULL
);
1187 /* Error if no new trace hook has been added */
1188 if (init_array_size
== (*trace_hooks
)->len
) {
1189 g_info("No marker of name %s.%s has all requested fields",
1190 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1196 void lttv_trace_hook_remove_all(GArray
**th
)
1199 for(i
=0; i
<(*th
)->len
; i
++) {
1200 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1203 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1206 LttvTracesetContextPosition
*
1207 lttv_traceset_context_position_new(const LttvTracesetContext
*self
)
1209 guint num_traces
= lttv_traceset_number(self
->ts
);
1213 for(i
=0; i
<num_traces
;i
++) {
1214 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1216 guint num_tracefiles
= tracefiles
->len
;
1217 for(j
=0;j
<num_tracefiles
;j
++)
1220 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
, 1);
1221 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1222 sizeof(LttvTracefileContextPosition
),
1224 g_array_set_size(pos
->tfcp
, tf_count
);
1225 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1226 LttvTracefileContextPosition
*tfcp
=
1227 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1228 tfcp
->event
= ltt_event_position_new();
1231 pos
->timestamp
= ltt_time_infinite
;
1235 /* Save all positions, the ones with infinite time will have NULL
1237 /* note : a position must be destroyed when a trace is added/removed from a
1239 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1240 LttvTracesetContextPosition
*pos
)
1243 guint num_traces
= lttv_traceset_number(self
->ts
);
1246 pos
->timestamp
= ltt_time_infinite
;
1248 for(i
=0; i
<num_traces
;i
++) {
1249 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1251 guint num_tracefiles
= tracefiles
->len
;
1253 for(j
=0;j
<num_tracefiles
;j
++) {
1254 g_assert(tf_count
< pos
->tfcp
->len
);
1255 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1256 LttvTracefileContext
*, j
);
1257 LttvTracefileContextPosition
*tfcp
=
1258 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1262 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1263 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1264 ltt_event_position(event
, tfcp
->event
);
1265 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1266 pos
->timestamp
= (*tfc
)->timestamp
;
1272 //g_array_append_val(pos->tfc, *tfc);
1273 //g_array_append_val(pos->ep, ep);
1280 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1284 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1285 LttvTracefileContextPosition
*tfcp
=
1286 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1287 g_free(tfcp
->event
);
1291 g_array_free(pos
->tfcp
, TRUE
);
1295 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1296 const LttvTracesetContextPosition
*src
)
1299 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1301 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1303 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1305 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1307 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1309 dest_tfcp
->used
= src_tfcp
->used
;
1310 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1312 if(src_tfcp
->used
) {
1313 ltt_event_position_copy(
1318 dest
->timestamp
= src
->timestamp
;
1321 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1322 const LttvTracesetContextPosition
*pos
)
1327 if(pos
->tfcp
->len
== 0) {
1328 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1331 if(lttv_traceset_number(self
->ts
) == 0)
1334 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1335 LttvTracefileContextPosition
*tfcp
=
1336 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1338 if(tfcp
->used
== FALSE
) {
1339 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1343 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1346 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1348 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1352 if(ret
!= 0) return ret
;
1360 lttv_traceset_context_pos_pos_compare(const LttvTracesetContextPosition
*pos1
,
1361 const LttvTracesetContextPosition
*pos2
)
1366 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1367 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1372 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1375 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1376 LttvTracefileContextPosition
*tfcp1
=
1377 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1379 if(tfcp1
->used
== TRUE
) {
1380 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1381 LttvTracefileContextPosition
*tfcp2
=
1382 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1384 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1385 if(tfcp2
->used
== TRUE
)
1386 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1390 if(ret
!= 0) return ret
;
1395 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1396 LttvTracefileContextPosition
*tfcp2
=
1397 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1399 if(tfcp1
->tfc
== tfcp2
->tfc
)
1400 if(tfcp2
->used
== TRUE
) ret
= 1;
1401 if(ret
!= 0) return ret
;
1410 lttv_traceset_context_position_get_time(const LttvTracesetContextPosition
*pos
)
1412 return pos
->timestamp
;
1416 LttvTracefileContext
*
1417 lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1419 GTree
*pqueue
= self
->pqueue
;
1420 LttvTracefileContext
*tfc
= NULL
;
1422 g_tree_foreach(pqueue
, get_first
, &tfc
);
1427 /* lttv_process_traceset_synchronize_tracefiles
1429 * Use the sync_position field of the trace set context to synchronize each
1430 * tracefile with the previously saved position.
1432 * If no previous position has been saved, it simply does nothing.
1434 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1438 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1439 g_assert_cmpint(retval
, ==, 0);
1445 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1447 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1450 struct seek_back_data
{
1451 guint first_event
; /* Index of the first event in the array : we will always
1452 overwrite at this position : this is a circular array.
1455 guint n
; /* number of events requested */
1456 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1457 LttvFilter
*filter1
;
1458 LttvFilter
*filter2
;
1459 LttvFilter
*filter3
;
1461 check_handler
*check
;
1462 gboolean
*stop_flag
;
1463 guint raw_event_count
;
1466 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1468 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1469 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1470 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1471 LttvTracesetContextPosition
*pos
;
1473 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1475 sd
->raw_event_count
++;
1477 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1478 !lttv_filter_tree_parse(sd
->filter1
->head
,
1479 ltt_tracefile_get_event(tfc
->tf
),
1485 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1486 !lttv_filter_tree_parse(sd
->filter2
->head
,
1487 ltt_tracefile_get_event(tfc
->tf
),
1493 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1494 !lttv_filter_tree_parse(sd
->filter3
->head
,
1495 ltt_tracefile_get_event(tfc
->tf
),
1502 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1505 lttv_traceset_context_position_save(tsc
, pos
);
1507 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1508 else sd
->first_event
++;
1510 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1515 /* Seek back n events back from the current position.
1518 * @self The trace set context
1519 * @n number of events to jump over
1520 * @first_offset The initial offset value used.
1521 * never put first_offset at ltt_time_zero.
1522 * @time_seeker Function pointer of the function to use to seek time :
1523 * either lttv_process_traceset_seek_time
1524 * or lttv_state_traceset_seek_time_closest
1525 * @filter The filter to call.
1527 * Return value : the number of events found (might be lower than the number
1528 * requested if beginning of traceset is reached).
1530 * The first search will go back first_offset and try to find the last n events
1531 * matching the filter. If there are not enough, it will try to go back from the
1532 * new trace point from first_offset*2, and so on, until beginning of trace or n
1535 * Note : this function does not take in account the LttvFilter : use the
1536 * similar function found in state.c instead.
1538 * Note2 : the caller must make sure that the LttvTracesetContext does not
1539 * contain any hook, as process_traceset_middle is used in this routine.
1541 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1542 guint n
, LttTime first_offset
,
1543 seek_time_fct time_seeker
,
1544 check_handler
*check
,
1545 gboolean
*stop_flag
,
1546 LttvFilter
*filter1
,
1547 LttvFilter
*filter2
,
1548 LttvFilter
*filter3
,
1551 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1552 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1555 LttvTracesetContextPosition
*next_iter_end_pos
=
1556 lttv_traceset_context_position_new(self
);
1557 LttvTracesetContextPosition
*end_pos
=
1558 lttv_traceset_context_position_new(self
);
1559 LttvTracesetContextPosition
*saved_pos
=
1560 lttv_traceset_context_position_new(self
);
1563 LttTime time_offset
;
1564 struct seek_back_data sd
;
1565 LttvHooks
*hooks
= lttv_hooks_new();
1569 sd
.events_found
= 0;
1570 sd
.array
= g_ptr_array_sized_new(n
);
1571 sd
.filter1
= filter1
;
1572 sd
.filter2
= filter2
;
1573 sd
.filter3
= filter3
;
1577 sd
.stop_flag
= stop_flag
;
1578 sd
.raw_event_count
= 0;
1579 g_ptr_array_set_size(sd
.array
, n
);
1581 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1584 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1585 lttv_traceset_context_position_save(self
, saved_pos
);
1586 /* Get the current time from which we will offset */
1587 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1588 /* the position saved might be end of traceset... */
1589 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1590 time
= self
->time_span
.end_time
;
1592 time_offset
= first_offset
;
1594 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1596 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1599 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1601 /* We must seek the traceset back to time - time_offset */
1602 /* this time becomes the new reference time */
1603 if(ltt_time_compare(time
, time_offset
) > 0)
1604 time
= ltt_time_sub(time
, time_offset
);
1606 time
= self
->time_span
.start_time
;
1609 time_seeker(self
, time
);
1610 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1611 /* Resync the time in case of a seek_closest */
1612 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1613 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1614 time
= self
->time_span
.end_time
;
1617 /* Process the traceset, calling a hook which adds events
1618 * to the array, overwriting the tail. It changes first_event and
1619 * events_found too. */
1620 /* We would like to have a clean context here : no other hook than our's */
1622 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1623 G_MAXUINT
, end_pos
);
1625 /* stop criteria : - n events found
1626 * - asked_time < beginning of trace */
1627 if(sd
.events_found
< n
) {
1628 if(sd
.first_event
> 0) {
1629 /* Save the first position */
1630 LttvTracesetContextPosition
*pos
=
1631 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1632 lttv_traceset_context_position_copy(saved_pos
, pos
);
1634 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1635 /* Change array size to n - events_found */
1636 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1637 LttvTracesetContextPosition
*pos
=
1638 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1639 lttv_traceset_context_position_destroy(pos
);
1641 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1645 * Did not fill our event list and started before the beginning of the
1646 * trace. There is no hope to fill it then.
1647 * It is OK to compare with trace start time here because we explicitely
1648 * seeked by time (not by position), so we cannot miss multiple event
1649 * happening exactly at trace start.
1651 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) == 0)
1654 } else break; /* Second end criterion : n events found */
1656 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1659 lttv_traceset_context_position_destroy(end_pos
);
1660 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1662 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1664 if(sd
.events_found
>= n
) {
1665 /* Seek the traceset to the first event in the circular array */
1666 LttvTracesetContextPosition
*pos
=
1667 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1669 retval
= lttv_process_traceset_seek_position(self
, pos
);
1670 g_assert_cmpint(retval
, ==, 0);
1672 /* Will seek to the last saved position : in the worst case, it will be the
1673 * original position (if events_found is 0) */
1674 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1675 g_assert_cmpint(retval
, ==, 0);
1678 for(i
=0;i
<sd
.array
->len
;i
++) {
1679 LttvTracesetContextPosition
*pos
=
1680 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1681 lttv_traceset_context_position_destroy(pos
);
1683 g_ptr_array_free(sd
.array
, TRUE
);
1685 lttv_hooks_destroy(hooks
);
1687 lttv_traceset_context_position_destroy(saved_pos
);
1689 return sd
.events_found
;
1693 struct seek_forward_data
{
1694 guint event_count
; /* event counter */
1695 guint n
; /* requested number of events to jump over */
1696 LttvFilter
*filter1
;
1697 LttvFilter
*filter2
;
1698 LttvFilter
*filter3
;
1700 check_handler
*check
;
1701 gboolean
*stop_flag
;
1702 guint raw_event_count
; /* event counter */
1705 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1707 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1708 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1710 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1712 sd
->raw_event_count
++;
1714 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1715 !lttv_filter_tree_parse(sd
->filter1
->head
,
1716 ltt_tracefile_get_event(tfc
->tf
),
1722 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1723 !lttv_filter_tree_parse(sd
->filter2
->head
,
1724 ltt_tracefile_get_event(tfc
->tf
),
1730 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1731 !lttv_filter_tree_parse(sd
->filter3
->head
,
1732 ltt_tracefile_get_event(tfc
->tf
),
1740 if(sd
->event_count
>= sd
->n
)
1745 /* Seek back n events forward from the current position (1 to n)
1746 * 0 is ok too, but it will actually do nothing.
1749 * @self the trace set context
1750 * @n number of events to jump over
1751 * @filter filter to call.
1753 * returns : the number of events jumped over (may be less than requested if end
1754 * of traceset reached) */
1755 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1757 check_handler
*check
,
1758 gboolean
*stop_flag
,
1759 LttvFilter
*filter1
,
1760 LttvFilter
*filter2
,
1761 LttvFilter
*filter3
,
1764 struct seek_forward_data sd
;
1767 sd
.filter1
= filter1
;
1768 sd
.filter2
= filter2
;
1769 sd
.filter3
= filter3
;
1772 sd
.stop_flag
= stop_flag
;
1773 sd
.raw_event_count
= 0;
1775 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1777 LttvHooks
*hooks
= lttv_hooks_new();
1779 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1781 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1783 /* it will end on the end of traceset, or the fact that the
1784 * hook returns TRUE.
1786 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1789 /* Here, our position is either the end of traceset, or the exact position
1790 * after n events : leave it like this. This might be placed on an event that
1791 * will be filtered out, we don't care : all we know is that the following
1792 * event filtered in will be the right one. */
1794 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1796 lttv_hooks_destroy(hooks
);
1798 return sd
.event_count
;