1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 #include <lttv/lttv.h>
25 #include <lttv/tracecontext.h>
26 #include <ltt/event.h>
27 #include <ltt/trace.h>
28 #include <lttv/filter.h>
32 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
36 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
37 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
39 if(likely(trace_a
!= trace_b
)) {
40 comparison
= ltt_time_compare(trace_a
->timestamp
, trace_b
->timestamp
);
41 if(unlikely(comparison
== 0)) {
42 if(trace_a
->index
< trace_b
->index
) comparison
= -1;
43 else if(trace_a
->index
> trace_b
->index
) comparison
= 1;
44 else if(trace_a
->t_context
->index
< trace_b
->t_context
->index
)
46 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
53 typedef struct _LttvTracefileContextPosition
{
54 LttEventPosition
*event
;
55 LttvTracefileContext
*tfc
;
56 gboolean used
; /* Tells if the tfc is at end of traceset position */
57 } LttvTracefileContextPosition
;
60 struct _LttvTracesetContextPosition
{
61 GArray
*tfcp
; /* Array of LttvTracefileContextPosition */
62 LttTime timestamp
; /* Current time at the saved position */
63 /* If ltt_time_infinite : no position is
64 * set, else, a position is set (may be end
65 * of trace, with ep->len == 0) */
68 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
70 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
74 void lttv_context_fini(LttvTracesetContext
*self
)
76 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
81 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
83 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
90 lttv_context_new_trace_context(LttvTracesetContext
*self
)
92 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
96 LttvTracefileContext
*
97 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
99 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
102 /****************************************************************************
103 * lttv_traceset_context_compute_time_span
105 * Keep the time span in sync with on the fly addition and removal of traces
106 * in a trace set. It must be called each time a trace is added/removed from
107 * the traceset. It could be more efficient to call it only once a bunch
108 * of traces are loaded, but the calculation is not long, so it's not
111 * Author : Xang Xiu Yang
112 ***************************************************************************/
113 void lttv_traceset_context_compute_time_span(LttvTracesetContext
*self
,
114 TimeInterval
*time_span
)
116 LttvTraceset
* traceset
= self
->ts
;
117 int numTraces
= lttv_traceset_number(traceset
);
120 LttvTraceContext
*tc
;
123 time_span
->start_time
.tv_sec
= 0;
124 time_span
->start_time
.tv_nsec
= 0;
125 time_span
->end_time
.tv_sec
= 0;
126 time_span
->end_time
.tv_nsec
= 0;
128 for(i
=0; i
<numTraces
;i
++){
129 tc
= self
->traces
[i
];
132 ltt_trace_time_span_get(trace
, &s
, &e
);
133 tc
->time_span
.start_time
= s
;
134 tc
->time_span
.end_time
= e
;
137 time_span
->start_time
= s
;
138 time_span
->end_time
= e
;
140 if(s
.tv_sec
< time_span
->start_time
.tv_sec
141 || (s
.tv_sec
== time_span
->start_time
.tv_sec
142 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
143 time_span
->start_time
= s
;
144 if(e
.tv_sec
> time_span
->end_time
.tv_sec
145 || (e
.tv_sec
== time_span
->end_time
.tv_sec
146 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
147 time_span
->end_time
= e
;
152 static void init_tracefile_context(LttTracefile
*tracefile
,
153 LttvTraceContext
*tc
)
155 LttvTracefileContext
*tfc
;
156 LttvTracesetContext
*tsc
= tc
->ts_context
;
158 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
160 tfc
->index
= tc
->tracefiles
->len
;
161 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
166 tfc
->event
= lttv_hooks_new();
167 tfc
->event_by_id
= lttv_hooks_by_id_new();
168 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
169 tfc
->target_pid
= -1;
174 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
178 LttvTraceContext
*tc
;
180 GData
**tracefiles_groups
;
182 struct compute_tracefile_group_args args
;
184 nb_trace
= lttv_traceset_number(ts
);
186 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
187 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
188 self
->ts_a
= lttv_traceset_attribute(ts
);
189 for(i
= 0 ; i
< nb_trace
; i
++) {
190 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
191 self
->traces
[i
] = tc
;
193 tc
->ts_context
= self
;
195 tc
->vt
= lttv_traceset_get(ts
, i
);
196 tc
->t
= lttv_trace(tc
->vt
);
197 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
198 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
199 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
200 sizeof(LttvTracefileContext
*), 10);
202 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
203 if(tracefiles_groups
!= NULL
) {
204 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
207 g_datalist_foreach(tracefiles_groups
,
208 (GDataForeachFunc
)compute_tracefile_group
,
213 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
214 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
215 nb_tracefile
= nb_control
+ nb_per_cpu
;
216 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
218 for(j
= 0 ; j
< nb_tracefile
; j
++) {
219 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
220 tc
->tracefiles
[j
] = tfc
;
225 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
227 tfc
->control
= FALSE
;
228 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
232 tfc
->e
= ltt_event_new();
233 tfc
->event
= lttv_hooks_new();
234 tfc
->event_by_id
= lttv_hooks_by_id_new();
235 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
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 nb_trace
= lttv_traceset_number(ts
);
302 for(i
= 0 ; i
< nb_trace
; i
++) {
303 tc
= self
->traces
[i
];
304 lttv_trace_context_add_hooks(tc
,
308 event_by_id_channel
);
313 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
314 LttvHooks
*after_traceset
,
315 LttvHooks
*after_trace
,
316 LttvHooks
*after_tracefile
,
318 LttvHooksByIdChannelArray
*event_by_id_channel
)
321 LttvTraceset
*ts
= self
->ts
;
325 LttvTraceContext
*tc
;
327 nb_trace
= lttv_traceset_number(ts
);
329 for(i
= 0 ; i
< nb_trace
; i
++) {
330 tc
= self
->traces
[i
];
331 lttv_trace_context_remove_hooks(tc
,
335 event_by_id_channel
);
338 lttv_hooks_call(after_traceset
, self
);
343 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
344 LttvHooks
*before_trace
,
345 LttvHooks
*before_tracefile
,
347 LttvHooksByIdChannelArray
*event_by_id_channel
)
349 guint i
, j
, nb_tracefile
;
350 LttvTracefileContext
**tfc
;
353 lttv_hooks_call(before_trace
, self
);
355 nb_tracefile
= self
->tracefiles
->len
;
357 for(i
= 0 ; i
< nb_tracefile
; i
++) {
358 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
360 lttv_tracefile_context_add_hooks(*tfc
,
364 if (event_by_id_channel
) {
365 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
366 LttvHooksByIdChannel
*hooks
=
367 &g_array_index(event_by_id_channel
->array
,
368 LttvHooksByIdChannel
, j
);
369 if (tf
->name
== hooks
->channel
)
370 lttv_tracefile_context_add_hooks(*tfc
,
381 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
382 LttvHooks
*after_trace
,
383 LttvHooks
*after_tracefile
,
385 LttvHooksByIdChannelArray
*event_by_id_channel
)
387 guint i
, j
, nb_tracefile
;
388 LttvTracefileContext
**tfc
;
391 nb_tracefile
= self
->tracefiles
->len
;
393 for(i
= 0 ; i
< nb_tracefile
; i
++) {
394 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
396 if (event_by_id_channel
) {
397 for(j
= 0; j
< event_by_id_channel
->array
->len
; j
++) {
398 LttvHooksByIdChannel
*hooks
=
399 &g_array_index(event_by_id_channel
->array
,
400 LttvHooksByIdChannel
, j
);
401 if (tf
->name
== hooks
->channel
)
402 lttv_tracefile_context_remove_hooks(*tfc
,
408 lttv_tracefile_context_remove_hooks(*tfc
,
415 lttv_hooks_call(after_trace
, self
);
418 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
419 LttvHooks
*before_tracefile
,
421 LttvHooksById
*event_by_id
)
426 lttv_hooks_call(before_tracefile
, self
);
427 lttv_hooks_add_list(self
->event
, event
);
428 if(event_by_id
!= NULL
) {
429 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
430 index
= g_array_index(event_by_id
->array
, guint
, i
);
431 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
432 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
437 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
438 LttvHooks
*after_tracefile
,
440 LttvHooksById
*event_by_id
)
446 lttv_hooks_remove_list(self
->event
, event
);
447 if(event_by_id
!= NULL
) {
448 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
449 index
= g_array_index(event_by_id
->array
, guint
, i
);
450 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
452 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
456 lttv_hooks_call(after_tracefile
, self
);
459 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
461 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
465 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
467 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
471 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
473 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
477 static void traceset_context_instance_init(GTypeInstance
*instance
,
480 /* Be careful of anything which would not work well with shallow copies */
484 static void traceset_context_finalize(LttvTracesetContext
*self
)
486 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
487 ->finalize(G_OBJECT(self
));
491 static void traceset_context_class_init(LttvTracesetContextClass
*klass
)
493 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
495 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
498 klass
->new_traceset_context
= new_traceset_context
;
499 klass
->new_trace_context
= new_trace_context
;
500 klass
->new_tracefile_context
= new_tracefile_context
;
504 GType
lttv_traceset_context_get_type(void)
506 static GType type
= 0;
508 static const GTypeInfo info
= {
509 sizeof (LttvTracesetContextClass
),
510 NULL
, /* base_init */
511 NULL
, /* base_finalize */
512 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
513 NULL
, /* class_finalize */
514 NULL
, /* class_data */
515 sizeof (LttvTracesetContext
),
517 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
518 NULL
/* Value handling */
521 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
529 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
531 /* Be careful of anything which would not work well with shallow copies */
535 static void trace_context_finalize (LttvTraceContext
*self
)
537 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
538 finalize(G_OBJECT(self
));
542 static void trace_context_class_init (LttvTraceContextClass
*klass
)
544 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
546 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
550 GType
lttv_trace_context_get_type(void)
552 static GType type
= 0;
554 static const GTypeInfo info
= {
555 sizeof (LttvTraceContextClass
),
556 NULL
, /* base_init */
557 NULL
, /* base_finalize */
558 (GClassInitFunc
) trace_context_class_init
, /* class_init */
559 NULL
, /* class_finalize */
560 NULL
, /* class_data */
561 sizeof (LttvTraceContext
),
563 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
564 NULL
/* Value handling */
567 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
574 static void tracefile_context_instance_init (GTypeInstance
*instance
,
577 /* Be careful of anything which would not work well with shallow copies */
581 static void tracefile_context_finalize (LttvTracefileContext
*self
)
583 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
584 ->finalize(G_OBJECT(self
));
588 static void tracefile_context_class_init (LttvTracefileContextClass
*klass
)
590 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
592 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
596 GType
lttv_tracefile_context_get_type(void)
598 static GType type
= 0;
600 static const GTypeInfo info
= {
601 sizeof (LttvTracefileContextClass
),
602 NULL
, /* base_init */
603 NULL
, /* base_finalize */
604 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
605 NULL
, /* class_finalize */
606 NULL
, /* class_data */
607 sizeof (LttvTracefileContext
),
609 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
610 NULL
/* Value handling */
613 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
621 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
622 g_assert(key
== value
);
623 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
628 // Test to see if pqueue is traversed in the right order.
629 static LttTime test_time
;
631 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
633 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
635 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
636 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
637 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
638 tfc
->index
, tfc
->t_context
->index
);
640 if(user_data
!= NULL
) {
641 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
642 g_assert(compare_tracefile(user_data
, value
) == 0);
644 g_assert(compare_tracefile(user_data
, value
) != 0);
646 g_assert(ltt_time_compare(test_time
, tfc
->timestamp
) <= 0);
647 test_time
.tv_sec
= tfc
->timestamp
.tv_sec
;
648 test_time
.tv_nsec
= tfc
->timestamp
.tv_nsec
;
651 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
658 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
659 LttvHooks
*before_traceset
,
660 LttvHooks
*before_trace
,
661 LttvHooks
*before_tracefile
,
663 LttvHooksByIdChannelArray
*event_by_id_channel
)
666 /* simply add hooks in context. _before hooks are called by add_hooks. */
667 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
668 lttv_traceset_context_add_hooks(self
,
673 event_by_id_channel
);
677 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
679 /* Note : a _middle must be preceded from a _seek or another middle */
680 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
683 const LttvTracesetContextPosition
*end_position
)
685 GTree
*pqueue
= self
->pqueue
;
687 LttvTracefileContext
*tfc
;
693 gboolean is_live
= FALSE
; /* set this flag if we detect a live trace */
697 //enum read_state last_read_state = LAST_NONE;
699 gint last_ret
= 0; /* return value of the last hook list called */
701 /* Get the next event from the pqueue, call its hooks,
702 reinsert in the pqueue the following event from the same tracefile
703 unless the tracefile is finished or the event is later than the
708 g_tree_foreach(pqueue
, get_first
, &tfc
);
709 /* End of traceset : tfc is NULL */
710 if(unlikely(tfc
== NULL
))
716 * - the maximum number of events specified?
717 * - the end position ?
719 * then the read is finished. We leave the queue in the same state and
722 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0) {
726 if(unlikely(last_ret
== TRUE
727 || ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
))
728 || (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
730 || ltt_time_compare(end
, tfc
->timestamp
) <= 0))
735 /* Get the tracefile with an event for the smallest time found. If two
736 or more tracefiles have events for the same time, hope that lookup
737 and remove are consistent. */
740 test_time
.tv_sec
= 0;
741 test_time
.tv_nsec
= 0;
742 g_debug("test tree before remove");
743 g_tree_foreach(pqueue
, test_tree
, tfc
);
745 g_tree_remove(pqueue
, tfc
);
748 test_time
.tv_sec
= 0;
749 test_time
.tv_nsec
= 0;
750 g_debug("test tree after remove");
751 g_tree_foreach(pqueue
, test_tree
, tfc
);
755 e
= ltt_tracefile_get_event(tfc
->tf
);
757 //if(last_read_state != LAST_EMPTY) {
758 /* Only call hooks if the last read has given an event or if we are at the
759 * first pass (not if last read returned end of tracefile) */
762 tfc
->target_pid
= -1; /* unset target PID */
764 * return values : 0 : continue read, 1 : go to next position and stop read,
765 * 2 : stay at the current position and stop read */
766 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
767 lttv_hooks_by_id_get(tfc
->event_by_id
, e
->event_id
), tfc
);
770 /* This is buggy : it won't work well with state computation */
771 if(unlikely(last_ret
== 2)) {
772 /* This is a case where we want to stay at this position and stop read. */
773 g_tree_insert(pqueue
, tfc
, tfc
);
778 read_ret
= ltt_tracefile_read(tfc
->tf
);
781 if(likely(!read_ret
)) {
782 //g_debug("An event is ready");
783 tfc
->timestamp
= ltt_event_time(e
);
786 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
787 g_tree_insert(pqueue
, tfc
, tfc
);
788 if(tfc
->tf
->trace
->is_live
&& ltt_time_compare(tfc
->timestamp
, tfc
->tf
->trace
->live_safe_timestamp
) >= 0)
794 test_time
.tv_sec
= 0;
795 test_time
.tv_nsec
= 0;
796 g_debug("test tree after event ready");
797 g_tree_foreach(pqueue
, test_tree
, NULL
);
800 //last_read_state = LAST_OK;
802 tfc
->timestamp
= ltt_time_infinite
;
804 if(read_ret
== ERANGE
) {
805 // last_read_state = LAST_EMPTY;
806 g_debug("End of trace");
808 g_error("Error happened in lttv_process_traceset_middle");
812 if (unlikely((count
== 0) && is_live
)) {
820 void lttv_process_traceset_end(LttvTracesetContext
*self
,
821 LttvHooks
*after_traceset
,
822 LttvHooks
*after_trace
,
823 LttvHooks
*after_tracefile
,
825 LttvHooksByIdChannelArray
*event_by_id_channel
)
827 /* Remove hooks from context. _after hooks are called by remove_hooks. */
828 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
829 lttv_traceset_context_remove_hooks(self
,
834 event_by_id_channel
);
837 /* Subtile modification :
838 * if tracefile has no event at or after the time requested, it is not put in
839 * the queue, as the next read would fail.
841 * Don't forget to empty the traceset pqueue before calling this.
843 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
845 guint i
, nb_tracefile
;
849 LttvTracefileContext
**tfc
;
851 nb_tracefile
= self
->tracefiles
->len
;
853 GTree
*pqueue
= self
->ts_context
->pqueue
;
855 for(i
= 0 ; i
< nb_tracefile
; i
++) {
856 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
858 g_tree_remove(pqueue
, *tfc
);
860 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
861 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
863 if(ret
== 0) { /* not ERANGE especially */
864 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
865 g_assert(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0);
866 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
868 (*tfc
)->timestamp
= ltt_time_infinite
;
872 test_time
.tv_sec
= 0;
873 test_time
.tv_nsec
= 0;
874 g_debug("test tree after seek_time");
875 g_tree_foreach(pqueue
, test_tree
, NULL
);
879 /****************************************************************************
880 * lttv_process_trace_update
882 * process the changes that occur in the trace. Use a regular file polling to
883 * monitor the tracefile.
885 * Return the number of tracefile updated
886 ***************************************************************************/
887 guint
lttv_process_trace_update(LttvTraceContext
*self
)
890 guint nb_tracefile
= 0;
892 LttTracefile
*tf
= 0;
893 LttvTracefileContext
**tfc
;
895 /* Skip non live traces */
896 if(self
->t
->is_live
) {
898 nb_tracefile
= ltt_trace_update(self
->t
);
900 /* Recreate the pqueue following an update*/
901 GTree
*pqueue
= self
->ts_context
->pqueue
;
903 for(i
= 0 ; i
< self
->tracefiles
->len
; i
++) {
904 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
906 if(g_tree_remove(pqueue
, *tfc
) == FALSE
) {
907 if(tf
->buf_index
!= NULL
) {
909 if(ltt_tracefile_read(tf
) == 0) {
911 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
912 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
917 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
923 //Update self time span
924 self
->time_span
.end_time
= LTT_TIME_MAX(self
->t
->live_safe_timestamp
,
925 self
->time_span
.end_time
);
926 //Update self tscontext time span
927 self
->ts_context
->time_span
.end_time
= LTT_TIME_MAX(self
->time_span
.end_time
,
928 self
->ts_context
->time_span
.end_time
);
934 /****************************************************************************
935 * lttv_process_traceset_update
937 * process the changes that occur in the traceset.
939 * Return the number of file presently monitor(open for writting). If 0, the
940 * current traceset probably received all the data.
941 ***************************************************************************/
942 guint
lttv_process_traceset_update(LttvTracesetContext
*self
)
946 guint open_counter
= 0;
948 nb_trace
= lttv_traceset_number(self
->ts
);
950 for(i
= 0 ; i
< nb_trace
; i
++) {
951 open_counter
+= lttv_process_trace_update(self
->traces
[i
]);
956 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
960 LttvTraceContext
*tc
;
962 //g_tree_destroy(self->pqueue);
963 //self->pqueue = g_tree_new(compare_tracefile);
965 nb_trace
= lttv_traceset_number(self
->ts
);
966 for(i
= 0 ; i
< nb_trace
; i
++) {
967 tc
= self
->traces
[i
];
968 lttv_process_trace_seek_time(tc
, start
);
973 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
974 const LttvTracesetContextPosition
*pos
)
977 /* If a position is set, seek the traceset to this position */
978 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
980 /* Test to see if the traces has been added to the trace set :
981 * It should NEVER happen. Clear all positions if a new trace comes in. */
982 /* FIXME I know this test is not optimal : should keep a number of
983 * tracefiles variable in the traceset.. eventually */
984 guint num_traces
= lttv_traceset_number(self
->ts
);
986 for(i
=0; i
<num_traces
;i
++) {
987 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
989 guint num_tracefiles
= tracefiles
->len
;
990 for(j
=0;j
<num_tracefiles
;j
++)
993 g_assert(tf_count
== pos
->tfcp
->len
);
996 //g_tree_destroy(self->pqueue);
997 //self->pqueue = g_tree_new(compare_tracefile);
999 for(i
=0;i
<pos
->tfcp
->len
; i
++) {
1000 LttvTracefileContextPosition
*tfcp
=
1001 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1003 g_tree_remove(self
->pqueue
, tfcp
->tfc
);
1005 if(tfcp
->used
== TRUE
) {
1006 if(ltt_tracefile_seek_position(tfcp
->tfc
->tf
, tfcp
->event
) != 0)
1008 tfcp
->tfc
->timestamp
=
1009 ltt_event_time(ltt_tracefile_get_event(tfcp
->tfc
->tf
));
1010 g_assert(ltt_time_compare(tfcp
->tfc
->timestamp
,
1011 ltt_time_infinite
) != 0);
1012 g_tree_insert(self
->pqueue
, tfcp
->tfc
, tfcp
->tfc
);
1015 tfcp
->tfc
->timestamp
= ltt_time_infinite
;
1020 test_time
.tv_sec
= 0;
1021 test_time
.tv_nsec
= 0;
1022 g_debug("test tree after seek_position");
1023 g_tree_foreach(self
->pqueue
, test_tree
, NULL
);
1032 #if 0 // pmf: temporary disable
1034 find_field(LttEventType
*et
, const GQuark field
)
1038 if(field
== 0) return NULL
;
1040 f
= ltt_eventtype_field_by_name(et
, field
);
1042 g_warning("Cannot find field %s in event %s.%s", g_quark_to_string(field
),
1043 g_quark_to_string(ltt_facility_name(ltt_eventtype_facility(et
))),
1044 g_quark_to_string(ltt_eventtype_name(et
)));
1051 struct marker_info
*lttv_trace_hook_get_marker(LttTrace
*t
, LttvTraceHook
*th
)
1053 return marker_get_info_from_id(th
->mdata
, th
->id
);
1056 int lttv_trace_find_hook(LttTrace
*t
, GQuark channel_name
, GQuark event_name
,
1057 GQuark fields
[], LttvHook h
, gpointer hook_data
,
1058 GArray
**trace_hooks
)
1060 struct marker_info
*info
;
1062 int init_array_size
;
1064 struct marker_data
*mdata
;
1066 group
= g_datalist_id_get_data(&t
->tracefiles
, channel_name
);
1067 if (unlikely(!group
|| group
->len
== 0)) {
1068 g_info("No channel for marker named %s.%s found",
1069 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1073 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
1074 info
= marker_get_info_from_name(mdata
, event_name
);
1075 if(unlikely(info
== NULL
)) {
1076 g_info("No marker named %s.%s found",
1077 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1081 init_array_size
= (*trace_hooks
)->len
;
1083 /* for each marker with the requested name */
1085 LttvTraceHook tmpth
;
1088 struct marker_field
*marker_field
;
1090 marker_id
= marker_get_id_from_info(mdata
, info
);
1093 tmpth
.mdata
= mdata
;
1094 tmpth
.channel
= channel_name
;
1095 tmpth
.id
= marker_id
;
1096 tmpth
.hook_data
= hook_data
;
1097 tmpth
.fields
= g_ptr_array_new();
1099 /* for each field requested */
1100 for(f
= fields
; f
&& *f
!= 0; f
++) {
1102 for_each_marker_field(marker_field
, info
) {
1103 if(marker_field
->name
== *f
) {
1105 g_ptr_array_add(tmpth
.fields
, marker_field
);
1110 /* Did not find the one of the fields in this instance of the
1111 marker. Print a warning and skip this marker completely.
1112 Still iterate on other markers with same name. */
1113 g_ptr_array_free(tmpth
.fields
, TRUE
);
1114 g_info("Field %s cannot be found in marker %s.%s",
1115 g_quark_to_string(*f
), g_quark_to_string(channel_name
),
1116 g_quark_to_string(event_name
));
1120 /* all fields were found: add the tracehook to the array */
1121 *trace_hooks
= g_array_append_val(*trace_hooks
, tmpth
);
1124 } while(info
!= NULL
);
1126 /* Error if no new trace hook has been added */
1127 if (init_array_size
== (*trace_hooks
)->len
) {
1128 g_info("No marker of name %s.%s has all requested fields",
1129 g_quark_to_string(channel_name
), g_quark_to_string(event_name
));
1135 void lttv_trace_hook_remove_all(GArray
**th
)
1138 for(i
=0; i
<(*th
)->len
; i
++) {
1139 g_ptr_array_free(g_array_index(*th
, LttvTraceHook
, i
).fields
, TRUE
);
1142 *th
= g_array_remove_range(*th
, 0, (*th
)->len
);
1145 LttvTracesetContextPosition
*
1146 lttv_traceset_context_position_new(const LttvTracesetContext
*self
)
1148 guint num_traces
= lttv_traceset_number(self
->ts
);
1152 for(i
=0; i
<num_traces
;i
++) {
1153 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1155 guint num_tracefiles
= tracefiles
->len
;
1156 for(j
=0;j
<num_tracefiles
;j
++)
1159 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
, 1);
1160 pos
->tfcp
= g_array_sized_new(FALSE
, TRUE
,
1161 sizeof(LttvTracefileContextPosition
),
1163 g_array_set_size(pos
->tfcp
, tf_count
);
1164 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1165 LttvTracefileContextPosition
*tfcp
=
1166 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1167 tfcp
->event
= ltt_event_position_new();
1170 pos
->timestamp
= ltt_time_infinite
;
1174 /* Save all positions, the ones with infinite time will have NULL
1176 /* note : a position must be destroyed when a trace is added/removed from a
1178 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1179 LttvTracesetContextPosition
*pos
)
1182 guint num_traces
= lttv_traceset_number(self
->ts
);
1185 pos
->timestamp
= ltt_time_infinite
;
1187 for(i
=0; i
<num_traces
;i
++) {
1188 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1190 guint num_tracefiles
= tracefiles
->len
;
1192 for(j
=0;j
<num_tracefiles
;j
++) {
1193 g_assert(tf_count
< pos
->tfcp
->len
);
1194 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1195 LttvTracefileContext
*, j
);
1196 LttvTracefileContextPosition
*tfcp
=
1197 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, tf_count
);
1201 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1202 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1203 ltt_event_position(event
, tfcp
->event
);
1204 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1205 pos
->timestamp
= (*tfc
)->timestamp
;
1211 //g_array_append_val(pos->tfc, *tfc);
1212 //g_array_append_val(pos->ep, ep);
1219 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1223 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1224 LttvTracefileContextPosition
*tfcp
=
1225 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1226 g_free(tfcp
->event
);
1230 g_array_free(pos
->tfcp
, TRUE
);
1234 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1235 const LttvTracesetContextPosition
*src
)
1238 LttvTracefileContextPosition
*src_tfcp
, *dest_tfcp
;
1240 g_assert(src
->tfcp
->len
== dest
->tfcp
->len
);
1242 for(i
=0;i
<src
->tfcp
->len
;i
++) {
1244 &g_array_index(src
->tfcp
, LttvTracefileContextPosition
, i
);
1246 &g_array_index(dest
->tfcp
, LttvTracefileContextPosition
, i
);
1248 dest_tfcp
->used
= src_tfcp
->used
;
1249 dest_tfcp
->tfc
= src_tfcp
->tfc
;
1251 if(src_tfcp
->used
) {
1252 ltt_event_position_copy(
1257 dest
->timestamp
= src
->timestamp
;
1260 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1261 const LttvTracesetContextPosition
*pos
)
1266 if(pos
->tfcp
->len
== 0) {
1267 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1270 if(lttv_traceset_number(self
->ts
) == 0)
1273 for(i
=0;i
<pos
->tfcp
->len
;i
++) {
1274 LttvTracefileContextPosition
*tfcp
=
1275 &g_array_index(pos
->tfcp
, LttvTracefileContextPosition
, i
);
1277 if(tfcp
->used
== FALSE
) {
1278 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) < 0) {
1282 if(ltt_time_compare(tfcp
->tfc
->timestamp
, ltt_time_infinite
) == 0) {
1285 LttEvent
*event
= ltt_tracefile_get_event(tfcp
->tfc
->tf
);
1287 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1291 if(ret
!= 0) return ret
;
1299 lttv_traceset_context_pos_pos_compare(const LttvTracesetContextPosition
*pos1
,
1300 const LttvTracesetContextPosition
*pos2
)
1305 if(ltt_time_compare(pos1
->timestamp
, ltt_time_infinite
) == 0) {
1306 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1311 if(ltt_time_compare(pos2
->timestamp
, ltt_time_infinite
) == 0)
1314 for(i
=0;i
<pos1
->tfcp
->len
;i
++) {
1315 LttvTracefileContextPosition
*tfcp1
=
1316 &g_array_index(pos1
->tfcp
, LttvTracefileContextPosition
, i
);
1318 if(tfcp1
->used
== TRUE
) {
1319 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1320 LttvTracefileContextPosition
*tfcp2
=
1321 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1323 if(tfcp1
->tfc
== tfcp2
->tfc
) {
1324 if(tfcp2
->used
== TRUE
)
1325 ret
= ltt_event_position_compare(tfcp1
->event
, tfcp2
->event
);
1329 if(ret
!= 0) return ret
;
1334 for(j
=0;j
<pos2
->tfcp
->len
;j
++) {
1335 LttvTracefileContextPosition
*tfcp2
=
1336 &g_array_index(pos2
->tfcp
, LttvTracefileContextPosition
, j
);
1338 if(tfcp1
->tfc
== tfcp2
->tfc
)
1339 if(tfcp2
->used
== TRUE
) ret
= 1;
1340 if(ret
!= 0) return ret
;
1349 lttv_traceset_context_position_get_time(const LttvTracesetContextPosition
*pos
)
1351 return pos
->timestamp
;
1355 LttvTracefileContext
*
1356 lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1358 GTree
*pqueue
= self
->pqueue
;
1359 LttvTracefileContext
*tfc
= NULL
;
1361 g_tree_foreach(pqueue
, get_first
, &tfc
);
1366 /* lttv_process_traceset_synchronize_tracefiles
1368 * Use the sync_position field of the trace set context to synchronize each
1369 * tracefile with the previously saved position.
1371 * If no previous position has been saved, it simply does nothing.
1373 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1377 retval
= lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
);
1378 g_assert_cmpint(retval
, ==, 0);
1384 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1386 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);
1389 struct seek_back_data
{
1390 guint first_event
; /* Index of the first event in the array : we will always
1391 overwrite at this position : this is a circular array.
1394 guint n
; /* number of events requested */
1395 GPtrArray
*array
; /* array of LttvTracesetContextPositions pointers */
1396 LttvFilter
*filter1
;
1397 LttvFilter
*filter2
;
1398 LttvFilter
*filter3
;
1400 check_handler
*check
;
1401 gboolean
*stop_flag
;
1402 guint raw_event_count
;
1405 static gint
seek_back_event_hook(void *hook_data
, void* call_data
)
1407 struct seek_back_data
*sd
= (struct seek_back_data
*)hook_data
;
1408 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1409 LttvTracesetContext
*tsc
= tfc
->t_context
->ts_context
;
1410 LttvTracesetContextPosition
*pos
;
1412 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1414 sd
->raw_event_count
++;
1416 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1417 !lttv_filter_tree_parse(sd
->filter1
->head
,
1418 ltt_tracefile_get_event(tfc
->tf
),
1424 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1425 !lttv_filter_tree_parse(sd
->filter2
->head
,
1426 ltt_tracefile_get_event(tfc
->tf
),
1432 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1433 !lttv_filter_tree_parse(sd
->filter3
->head
,
1434 ltt_tracefile_get_event(tfc
->tf
),
1441 pos
= (LttvTracesetContextPosition
*)g_ptr_array_index (sd
->array
,
1444 lttv_traceset_context_position_save(tsc
, pos
);
1446 if(sd
->first_event
>= sd
->array
->len
- 1) sd
->first_event
= 0;
1447 else sd
->first_event
++;
1449 sd
->events_found
= min(sd
->n
, sd
->events_found
+ 1);
1454 /* Seek back n events back from the current position.
1457 * @self The trace set context
1458 * @n number of events to jump over
1459 * @first_offset The initial offset value used.
1460 * never put first_offset at ltt_time_zero.
1461 * @time_seeker Function pointer of the function to use to seek time :
1462 * either lttv_process_traceset_seek_time
1463 * or lttv_state_traceset_seek_time_closest
1464 * @filter The filter to call.
1466 * Return value : the number of events found (might be lower than the number
1467 * requested if beginning of traceset is reached).
1469 * The first search will go back first_offset and try to find the last n events
1470 * matching the filter. If there are not enough, it will try to go back from the
1471 * new trace point from first_offset*2, and so on, until beginning of trace or n
1474 * Note : this function does not take in account the LttvFilter : use the
1475 * similar function found in state.c instead.
1477 * Note2 : the caller must make sure that the LttvTracesetContext does not
1478 * contain any hook, as process_traceset_middle is used in this routine.
1480 guint
lttv_process_traceset_seek_n_backward(LttvTracesetContext
*self
,
1481 guint n
, LttTime first_offset
,
1482 seek_time_fct time_seeker
,
1483 check_handler
*check
,
1484 gboolean
*stop_flag
,
1485 LttvFilter
*filter1
,
1486 LttvFilter
*filter2
,
1487 LttvFilter
*filter3
,
1490 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1491 g_assert(ltt_time_compare(first_offset
, ltt_time_zero
) != 0);
1494 LttvTracesetContextPosition
*next_iter_end_pos
=
1495 lttv_traceset_context_position_new(self
);
1496 LttvTracesetContextPosition
*end_pos
=
1497 lttv_traceset_context_position_new(self
);
1498 LttvTracesetContextPosition
*saved_pos
=
1499 lttv_traceset_context_position_new(self
);
1502 LttTime time_offset
;
1503 struct seek_back_data sd
;
1504 LttvHooks
*hooks
= lttv_hooks_new();
1508 sd
.events_found
= 0;
1509 sd
.array
= g_ptr_array_sized_new(n
);
1510 sd
.filter1
= filter1
;
1511 sd
.filter2
= filter2
;
1512 sd
.filter3
= filter3
;
1516 sd
.stop_flag
= stop_flag
;
1517 sd
.raw_event_count
= 0;
1518 g_ptr_array_set_size(sd
.array
, n
);
1520 g_ptr_array_index (sd
.array
, i
) = lttv_traceset_context_position_new(self
);
1523 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1524 lttv_traceset_context_position_save(self
, saved_pos
);
1525 /* Get the current time from which we will offset */
1526 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1527 /* the position saved might be end of traceset... */
1528 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1529 time
= self
->time_span
.end_time
;
1531 time_offset
= first_offset
;
1533 lttv_hooks_add(hooks
, seek_back_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1535 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1538 lttv_traceset_context_position_copy(end_pos
, next_iter_end_pos
);
1540 /* We must seek the traceset back to time - time_offset */
1541 /* this time becomes the new reference time */
1542 if(ltt_time_compare(time
, time_offset
) > 0)
1543 time
= ltt_time_sub(time
, time_offset
);
1545 time
= self
->time_span
.start_time
;
1548 time_seeker(self
, time
);
1549 lttv_traceset_context_position_save(self
, next_iter_end_pos
);
1550 /* Resync the time in case of a seek_closest */
1551 time
= lttv_traceset_context_position_get_time(next_iter_end_pos
);
1552 if(ltt_time_compare(time
, self
->time_span
.end_time
) > 0) {
1553 time
= self
->time_span
.end_time
;
1556 /* Process the traceset, calling a hook which adds events
1557 * to the array, overwriting the tail. It changes first_event and
1558 * events_found too. */
1559 /* We would like to have a clean context here : no other hook than our's */
1561 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1562 G_MAXUINT
, end_pos
);
1564 /* stop criteria : - n events found
1565 * - asked_time < beginning of trace */
1566 if(sd
.events_found
< n
) {
1567 if(sd
.first_event
> 0) {
1568 /* Save the first position */
1569 LttvTracesetContextPosition
*pos
=
1570 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, 0);
1571 lttv_traceset_context_position_copy(saved_pos
, pos
);
1573 g_assert(n
-sd
.events_found
<= sd
.array
->len
);
1574 /* Change array size to n - events_found */
1575 for(i
=n
-sd
.events_found
;i
<sd
.array
->len
;i
++) {
1576 LttvTracesetContextPosition
*pos
=
1577 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1578 lttv_traceset_context_position_destroy(pos
);
1580 g_ptr_array_set_size(sd
.array
, n
-sd
.events_found
);
1584 * Did not fill our event list and started before the beginning of the
1585 * trace. There is no hope to fill it then.
1586 * It is OK to compare with trace start time here because we explicitely
1587 * seeked by time (not by position), so we cannot miss multiple event
1588 * happening exactly at trace start.
1590 if(ltt_time_compare(asked_time
, self
->time_span
.start_time
) == 0)
1593 } else break; /* Second end criterion : n events found */
1595 time_offset
= ltt_time_mul(time_offset
, BACKWARD_SEEK_MUL
);
1598 lttv_traceset_context_position_destroy(end_pos
);
1599 lttv_traceset_context_position_destroy(next_iter_end_pos
);
1601 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1603 if(sd
.events_found
>= n
) {
1604 /* Seek the traceset to the first event in the circular array */
1605 LttvTracesetContextPosition
*pos
=
1606 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
,
1608 retval
= lttv_process_traceset_seek_position(self
, pos
);
1609 g_assert_cmpint(retval
, ==, 0);
1611 /* Will seek to the last saved position : in the worst case, it will be the
1612 * original position (if events_found is 0) */
1613 retval
= lttv_process_traceset_seek_position(self
, saved_pos
);
1614 g_assert_cmpint(retval
, ==, 0);
1617 for(i
=0;i
<sd
.array
->len
;i
++) {
1618 LttvTracesetContextPosition
*pos
=
1619 (LttvTracesetContextPosition
*)g_ptr_array_index (sd
.array
, i
);
1620 lttv_traceset_context_position_destroy(pos
);
1622 g_ptr_array_free(sd
.array
, TRUE
);
1624 lttv_hooks_destroy(hooks
);
1626 lttv_traceset_context_position_destroy(saved_pos
);
1628 return sd
.events_found
;
1632 struct seek_forward_data
{
1633 guint event_count
; /* event counter */
1634 guint n
; /* requested number of events to jump over */
1635 LttvFilter
*filter1
;
1636 LttvFilter
*filter2
;
1637 LttvFilter
*filter3
;
1639 check_handler
*check
;
1640 gboolean
*stop_flag
;
1641 guint raw_event_count
; /* event counter */
1644 static gint
seek_forward_event_hook(void *hook_data
, void* call_data
)
1646 struct seek_forward_data
*sd
= (struct seek_forward_data
*)hook_data
;
1647 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1649 if(sd
->check
&& sd
->check(sd
->raw_event_count
, sd
->stop_flag
, sd
->data
))
1651 sd
->raw_event_count
++;
1653 if(sd
->filter1
!= NULL
&& sd
->filter1
->head
!= NULL
&&
1654 !lttv_filter_tree_parse(sd
->filter1
->head
,
1655 ltt_tracefile_get_event(tfc
->tf
),
1661 if(sd
->filter2
!= NULL
&& sd
->filter2
->head
!= NULL
&&
1662 !lttv_filter_tree_parse(sd
->filter2
->head
,
1663 ltt_tracefile_get_event(tfc
->tf
),
1669 if(sd
->filter3
!= NULL
&& sd
->filter3
->head
!= NULL
&&
1670 !lttv_filter_tree_parse(sd
->filter3
->head
,
1671 ltt_tracefile_get_event(tfc
->tf
),
1679 if(sd
->event_count
>= sd
->n
)
1684 /* Seek back n events forward from the current position (1 to n)
1685 * 0 is ok too, but it will actually do nothing.
1688 * @self the trace set context
1689 * @n number of events to jump over
1690 * @filter filter to call.
1692 * returns : the number of events jumped over (may be less than requested if end
1693 * of traceset reached) */
1694 guint
lttv_process_traceset_seek_n_forward(LttvTracesetContext
*self
,
1696 check_handler
*check
,
1697 gboolean
*stop_flag
,
1698 LttvFilter
*filter1
,
1699 LttvFilter
*filter2
,
1700 LttvFilter
*filter3
,
1703 struct seek_forward_data sd
;
1706 sd
.filter1
= filter1
;
1707 sd
.filter2
= filter2
;
1708 sd
.filter3
= filter3
;
1711 sd
.stop_flag
= stop_flag
;
1712 sd
.raw_event_count
= 0;
1714 if(sd
.event_count
>= sd
.n
) return sd
.event_count
;
1716 LttvHooks
*hooks
= lttv_hooks_new();
1718 lttv_hooks_add(hooks
, seek_forward_event_hook
, &sd
, LTTV_PRIO_DEFAULT
);
1720 lttv_process_traceset_begin(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1722 /* it will end on the end of traceset, or the fact that the
1723 * hook returns TRUE.
1725 lttv_process_traceset_middle(self
, ltt_time_infinite
,
1728 /* Here, our position is either the end of traceset, or the exact position
1729 * after n events : leave it like this. This might be placed on an event that
1730 * will be filtered out, we don't care : all we know is that the following
1731 * event filtered in will be the right one. */
1733 lttv_process_traceset_end(self
, NULL
, NULL
, NULL
, hooks
, NULL
);
1735 lttv_hooks_destroy(hooks
);
1737 return sd
.event_count
;