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/tracecontext.h>
25 #include <ltt/event.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
34 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
38 const LttvTracefileContext
*trace_a
= (const LttvTracefileContext
*)a
;
39 const LttvTracefileContext
*trace_b
= (const LttvTracefileContext
*)b
;
41 if(likely(trace_a
!= trace_b
)) {
42 comparison
= ltt_time_compare(trace_a
->timestamp
, trace_b
->timestamp
);
43 if(unlikely(comparison
== 0)) {
44 if(trace_a
->index
< trace_b
->index
) comparison
= -1;
45 else if(trace_a
->index
> trace_b
->index
) comparison
= 1;
46 else if(trace_a
->t_context
->index
< trace_b
->t_context
->index
)
48 else if(trace_a
->t_context
->index
> trace_b
->t_context
->index
)
55 struct _LttvTracesetContextPosition
{
56 GArray
*ep
; /* Array of LttEventPosition */
57 GArray
*tfc
; /* Array of corresponding
59 LttTime timestamp
; /* Current time at the saved position */
60 /* If ltt_time_infinite : no position is
61 * set, else, a position is set (may be end
62 * of trace, with ep->len == 0) */
65 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
67 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
71 void lttv_context_fini(LttvTracesetContext
*self
)
73 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
78 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
80 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
87 lttv_context_new_trace_context(LttvTracesetContext
*self
)
89 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
93 LttvTracefileContext
*
94 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
96 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
99 /****************************************************************************
100 * lttv_traceset_context_compute_time_span
102 * Keep the time span is sync with on the fly addition and removal of traces
103 * in a trace set. It must be called each time a trace is added/removed from
104 * the traceset. It could be more efficient to call it only once a bunch
105 * of traces are loaded, but the calculation is not long, so it's not
108 * Author : Xang Xiu Yang
109 ***************************************************************************/
110 static void lttv_traceset_context_compute_time_span(
111 LttvTracesetContext
*self
,
112 TimeInterval
*time_span
)
114 LttvTraceset
* traceset
= self
->ts
;
115 int numTraces
= lttv_traceset_number(traceset
);
118 LttvTraceContext
*tc
;
121 time_span
->start_time
.tv_sec
= 0;
122 time_span
->start_time
.tv_nsec
= 0;
123 time_span
->end_time
.tv_sec
= 0;
124 time_span
->end_time
.tv_nsec
= 0;
126 for(i
=0; i
<numTraces
;i
++){
127 tc
= self
->traces
[i
];
130 ltt_trace_time_span_get(trace
, &s
, &e
);
133 time_span
->start_time
= s
;
134 time_span
->end_time
= e
;
136 if(s
.tv_sec
< time_span
->start_time
.tv_sec
137 || (s
.tv_sec
== time_span
->start_time
.tv_sec
138 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
139 time_span
->start_time
= s
;
140 if(e
.tv_sec
> time_span
->end_time
.tv_sec
141 || (e
.tv_sec
== time_span
->end_time
.tv_sec
142 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
143 time_span
->end_time
= e
;
148 static void init_tracefile_context(LttTracefile
*tracefile
,
149 LttvTraceContext
*tc
)
151 LttvTracefileContext
*tfc
;
152 LttvTracesetContext
*tsc
= tc
->ts_context
;
154 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
156 tfc
->index
= tc
->tracefiles
->len
;
157 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
162 tfc
->event
= lttv_hooks_new();
163 tfc
->event_by_id
= lttv_hooks_by_id_new();
164 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
169 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
173 LttvTraceContext
*tc
;
175 GData
**tracefiles_groups
;
177 struct compute_tracefile_group_args args
;
179 nb_trace
= lttv_traceset_number(ts
);
181 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
182 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
183 self
->ts_a
= lttv_traceset_attribute(ts
);
184 self
->sync_position
= lttv_traceset_context_position_new();
185 for(i
= 0 ; i
< nb_trace
; i
++) {
186 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
187 self
->traces
[i
] = tc
;
189 tc
->ts_context
= self
;
191 tc
->vt
= lttv_traceset_get(ts
, i
);
192 tc
->t
= lttv_trace(tc
->vt
);
193 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
194 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
195 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
196 sizeof(LttvTracefileContext
*), 10);
198 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
199 if(tracefiles_groups
!= NULL
) {
200 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
203 g_datalist_foreach(tracefiles_groups
,
204 (GDataForeachFunc
)compute_tracefile_group
,
209 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
210 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
211 nb_tracefile
= nb_control
+ nb_per_cpu
;
212 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
214 for(j
= 0 ; j
< nb_tracefile
; j
++) {
215 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
216 tc
->tracefiles
[j
] = tfc
;
221 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
224 tfc
->control
= FALSE
;
225 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
229 tfc
->e
= ltt_event_new();
230 tfc
->event
= lttv_hooks_new();
231 tfc
->event_by_id
= lttv_hooks_by_id_new();
232 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
237 self
->pqueue
= g_tree_new(compare_tracefile
);
238 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
239 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
244 void fini(LttvTracesetContext
*self
)
246 guint i
, j
, nb_trace
, nb_tracefile
;
248 LttvTraceContext
*tc
;
250 LttvTracefileContext
**tfc
;
252 LttvTraceset
*ts
= self
->ts
;
254 g_tree_destroy(self
->pqueue
);
255 g_object_unref(self
->a
);
256 lttv_traceset_context_position_destroy(self
->sync_position
);
258 nb_trace
= lttv_traceset_number(ts
);
260 for(i
= 0 ; i
< nb_trace
; i
++) {
261 tc
= self
->traces
[i
];
263 g_object_unref(tc
->a
);
265 nb_tracefile
= tc
->tracefiles
->len
;
267 for(j
= 0 ; j
< nb_tracefile
; j
++) {
268 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
269 lttv_hooks_destroy((*tfc
)->event
);
270 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
271 g_object_unref((*tfc
)->a
);
272 g_object_unref(*tfc
);
274 g_array_free(tc
->tracefiles
, TRUE
);
277 g_free(self
->traces
);
281 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
282 LttvHooks
*before_traceset
,
283 LttvHooks
*before_trace
,
284 LttvHooks
*before_tracefile
,
286 LttvHooksById
*event_by_id
)
288 LttvTraceset
*ts
= self
->ts
;
292 LttvTraceContext
*tc
;
294 lttv_hooks_call(before_traceset
, self
);
296 nb_trace
= lttv_traceset_number(ts
);
298 for(i
= 0 ; i
< nb_trace
; i
++) {
299 tc
= self
->traces
[i
];
300 lttv_trace_context_add_hooks(tc
,
309 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
310 LttvHooks
*after_traceset
,
311 LttvHooks
*after_trace
,
312 LttvHooks
*after_tracefile
,
314 LttvHooksById
*event_by_id
)
317 LttvTraceset
*ts
= self
->ts
;
321 LttvTraceContext
*tc
;
323 nb_trace
= lttv_traceset_number(ts
);
325 for(i
= 0 ; i
< nb_trace
; i
++) {
326 tc
= self
->traces
[i
];
327 lttv_trace_context_remove_hooks(tc
,
334 lttv_hooks_call(after_traceset
, self
);
339 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
340 LttvHooks
*before_trace
,
341 LttvHooks
*before_tracefile
,
343 LttvHooksById
*event_by_id
)
345 guint i
, nb_tracefile
;
347 LttvTracefileContext
**tfc
;
349 lttv_hooks_call(before_trace
, self
);
351 nb_tracefile
= self
->tracefiles
->len
;
353 for(i
= 0 ; i
< nb_tracefile
; i
++) {
354 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
355 lttv_tracefile_context_add_hooks(*tfc
,
364 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
365 LttvHooks
*after_trace
,
366 LttvHooks
*after_tracefile
,
368 LttvHooksById
*event_by_id
)
370 guint i
, nb_tracefile
;
372 LttvTracefileContext
**tfc
;
374 nb_tracefile
= self
->tracefiles
->len
;
376 for(i
= 0 ; i
< nb_tracefile
; i
++) {
377 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
378 lttv_tracefile_context_remove_hooks(*tfc
,
384 lttv_hooks_call(after_trace
, self
);
387 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
388 LttvHooks
*before_tracefile
,
390 LttvHooksById
*event_by_id
)
396 lttv_hooks_call(before_tracefile
, self
);
397 lttv_hooks_add_list(self
->event
, event
);
398 if(event_by_id
!= NULL
) {
399 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
400 index
= g_array_index(event_by_id
->array
, guint
, i
);
401 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
402 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
407 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
408 LttvHooks
*after_tracefile
,
410 LttvHooksById
*event_by_id
)
416 lttv_hooks_remove_list(self
->event
, event
);
417 if(event_by_id
!= NULL
) {
418 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
419 index
= g_array_index(event_by_id
->array
, guint
, i
);
420 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
422 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
426 lttv_hooks_call(after_tracefile
, self
);
431 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext
*tfc
,
433 LttvHooks
*event_by_id
)
436 h
= lttv_hooks_by_id_find(tfc
->event_by_id
, i
);
437 lttv_hooks_add_list(h
, event_by_id
);
440 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext
*tfc
,
443 lttv_hooks_by_id_remove(tfc
->event_by_id
, i
);
446 static LttvTracesetContext
*
447 new_traceset_context(LttvTracesetContext
*self
)
449 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
453 static LttvTraceContext
*
454 new_trace_context(LttvTracesetContext
*self
)
456 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
460 static LttvTracefileContext
*
461 new_tracefile_context(LttvTracesetContext
*self
)
463 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
468 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
470 /* Be careful of anything which would not work well with shallow copies */
475 traceset_context_finalize (LttvTracesetContext
*self
)
477 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
478 ->finalize(G_OBJECT(self
));
483 traceset_context_class_init (LttvTracesetContextClass
*klass
)
485 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
487 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
490 klass
->new_traceset_context
= new_traceset_context
;
491 klass
->new_trace_context
= new_trace_context
;
492 klass
->new_tracefile_context
= new_tracefile_context
;
497 lttv_traceset_context_get_type(void)
499 static GType type
= 0;
501 static const GTypeInfo info
= {
502 sizeof (LttvTracesetContextClass
),
503 NULL
, /* base_init */
504 NULL
, /* base_finalize */
505 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
506 NULL
, /* class_finalize */
507 NULL
, /* class_data */
508 sizeof (LttvTracesetContext
),
510 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
511 NULL
/* Value handling */
514 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
522 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
524 /* Be careful of anything which would not work well with shallow copies */
529 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
));
537 trace_context_class_init (LttvTraceContextClass
*klass
)
539 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
541 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
546 lttv_trace_context_get_type(void)
548 static GType type
= 0;
550 static const GTypeInfo info
= {
551 sizeof (LttvTraceContextClass
),
552 NULL
, /* base_init */
553 NULL
, /* base_finalize */
554 (GClassInitFunc
) trace_context_class_init
, /* class_init */
555 NULL
, /* class_finalize */
556 NULL
, /* class_data */
557 sizeof (LttvTraceContext
),
559 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
560 NULL
/* Value handling */
563 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
571 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
573 /* Be careful of anything which would not work well with shallow copies */
578 tracefile_context_finalize (LttvTracefileContext
*self
)
580 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
581 ->finalize(G_OBJECT(self
));
586 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
588 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
590 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
595 lttv_tracefile_context_get_type(void)
597 static GType type
= 0;
599 static const GTypeInfo info
= {
600 sizeof (LttvTracefileContextClass
),
601 NULL
, /* base_init */
602 NULL
, /* base_finalize */
603 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
604 NULL
, /* class_finalize */
605 NULL
, /* class_data */
606 sizeof (LttvTracefileContext
),
608 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
609 NULL
/* Value handling */
612 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
620 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
621 g_assert(key
== value
);
622 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
626 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
628 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
630 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
631 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
632 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
633 tfc
->index
, tfc
->t_context
->index
);
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(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
646 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
647 LttvHooks
*before_traceset
,
648 LttvHooks
*before_trace
,
649 LttvHooks
*before_tracefile
,
651 LttvHooksById
*event_by_id
)
654 /* simply add hooks in context. _before hooks are called by add_hooks. */
655 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
656 lttv_traceset_context_add_hooks(self
,
665 enum read_state
{ LAST_NONE
, LAST_OK
, LAST_EMPTY
};
667 /* Note : a _middle must be preceded from a _seek or another middle */
668 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
671 const LttvTracesetContextPosition
*end_position
)
673 GTree
*pqueue
= self
->pqueue
;
675 guint fac_id
, ev_id
, id
;
677 LttvTracefileContext
*tfc
;
685 enum read_state last_read_state
= LAST_NONE
;
687 gboolean last_ret
= FALSE
; /* return value of the last hook list called */
689 /* Get the next event from the pqueue, call its hooks,
690 reinsert in the pqueue the following event from the same tracefile
691 unless the tracefile is finished or the event is later than the
696 g_tree_foreach(pqueue
, get_first
, &tfc
);
697 /* End of traceset : tfc is NULL */
698 if(unlikely(tfc
== NULL
))
704 * - the maximum number of events specified?
705 * - the end position ?
707 * then the read is finished. We leave the queue in the same state and
711 if(unlikely(last_ret
== TRUE
||
712 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
713 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
714 end_position
) == 0)||
715 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
720 /* Get the tracefile with an event for the smallest time found. If two
721 or more tracefiles have events for the same time, hope that lookup
722 and remove are consistent. */
725 g_debug("test tree before remove");
726 g_tree_foreach(pqueue
, test_tree
, tfc
);
728 g_tree_remove(pqueue
, tfc
);
731 g_debug("test tree after remove");
732 g_tree_foreach(pqueue
, test_tree
, tfc
);
735 e
= ltt_tracefile_get_event(tfc
->tf
);
737 if(last_read_state
!= LAST_EMPTY
) {
738 /* Only call hooks if the last read has given an event or if we are at the
739 * first pass (not if last read returned end of tracefile) */
742 fac_id
= ltt_event_facility_id(e
);
743 ev_id
= ltt_event_eventtype_id(e
);
744 id
= GET_HOOK_ID(fac_id
, ev_id
);
745 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
746 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
749 read_ret
= ltt_tracefile_read(tfc
->tf
);
751 if(likely(!read_ret
)) {
752 g_debug("An event is ready");
753 tfc
->timestamp
= ltt_event_time(e
);
755 g_tree_insert(pqueue
, tfc
, tfc
);
756 last_read_state
= LAST_OK
;
758 tfc
->timestamp
= ltt_time_infinite
;
760 if(read_ret
== ERANGE
) {
761 last_read_state
= LAST_EMPTY
;
762 g_debug("End of trace");
764 g_error("Error happened in lttv_process_traceset_middle");
770 void lttv_process_traceset_end(LttvTracesetContext
*self
,
771 LttvHooks
*after_traceset
,
772 LttvHooks
*after_trace
,
773 LttvHooks
*after_tracefile
,
775 LttvHooksById
*event_by_id
)
777 /* Remove hooks from context. _after hooks are called by remove_hooks. */
778 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
779 lttv_traceset_context_remove_hooks(self
,
787 /* Subtile modification :
788 * if tracefile has no event at or after the time requested, it is not put in
789 * the queue, as the next read would fail. */
790 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
792 guint i
, nb_tracefile
;
796 LttvTracefileContext
**tfc
;
798 GTree
*pqueue
= self
->ts_context
->pqueue
;
800 nb_tracefile
= self
->tracefiles
->len
;
802 for(i
= 0 ; i
< nb_tracefile
; i
++) {
803 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
805 g_tree_remove(pqueue
, *tfc
);
807 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
808 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
810 if(ret
== 0) { /* not ERANGE especially */
811 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
812 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
814 (*tfc
)->timestamp
= ltt_time_infinite
;
820 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
824 LttvTraceContext
*tc
;
826 nb_trace
= lttv_traceset_number(self
->ts
);
827 for(i
= 0 ; i
< nb_trace
; i
++) {
828 tc
= self
->traces
[i
];
829 lttv_process_trace_seek_time(tc
, start
);
834 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
835 const LttvTracesetContextPosition
*pos
)
839 /* If a position is set, seek the traceset to this position */
840 if(ltt_time_compare(pos
->timestamp
, ltt_time_infinite
) != 0) {
841 g_tree_destroy(self
->pqueue
);
842 self
->pqueue
= g_tree_new(compare_tracefile
);
844 for(i
=0;i
<pos
->ep
->len
; i
++) {
845 LttEventPosition
**ep
= &g_array_index(pos
->ep
, LttEventPosition
*, i
);
846 LttvTracefileContext
**tfc
=
847 &g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
849 if(ltt_tracefile_seek_position((*tfc
)->tf
, *ep
) != 0)
851 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
852 g_tree_insert(self
->pqueue
, (*tfc
), (*tfc
));
854 (*tfc
)->timestamp
= ltt_time_infinite
;
864 find_field(LttEventType
*et
, const GQuark field
)
875 if(field
== 0) return NULL
;
877 f
= ltt_eventtype_field(et
);
878 t
= ltt_eventtype_type(et
);
879 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
880 nb
= ltt_type_member_number(t
);
881 for(i
= 0 ; i
< nb
; i
++) {
882 ltt_type_member_type(t
, i
, &name
);
883 if(name
== field
) break;
886 return ltt_field_member(f
, i
);
889 LttvTraceHookByFacility
*lttv_trace_hook_get_fac(LttvTraceHook
*th
,
892 return &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, facility_id
);
895 /* Get the first facility corresponding to the name. As the types must be
896 * compatible, it is relevant to use the field name and sizes of the first
897 * facility to create data structures and assume the data will be compatible
898 * thorough the trace */
899 LttvTraceHookByFacility
*lttv_trace_hook_get_first(LttvTraceHook
*th
)
901 g_assert(th
->fac_list
->len
> 0);
902 return g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0);
906 /* Returns 0 on success, -1 if fails. */
908 lttv_trace_find_hook(LttTrace
*t
, GQuark facility
, GQuark event
,
909 GQuark field1
, GQuark field2
, GQuark field3
, LttvHook h
, gpointer hook_data
,
914 LttEventType
*et
, *first_et
;
918 guint i
, fac_id
, ev_id
;
920 LttvTraceHookByFacility
*thf
, *first_thf
;
922 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
924 if(unlikely(facilities
== NULL
)) goto facility_error
;
926 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
927 sizeof(LttvTraceHookByFacility
),
929 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
931 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
932 sizeof(LttvTraceHookByFacility
*),
934 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
936 fac_id
= g_array_index(facilities
, guint
, 0);
937 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
939 et
= ltt_facility_eventtype_get_by_name(f
, event
);
940 if(unlikely(et
== NULL
)) goto event_error
;
942 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
943 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0) = thf
;
945 ev_id
= ltt_eventtype_id(et
);
948 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
949 thf
->f1
= find_field(et
, field1
);
950 thf
->f2
= find_field(et
, field2
);
951 thf
->f3
= find_field(et
, field3
);
952 thf
->hook_data
= hook_data
;
957 /* Check for type compatibility too */
958 for(i
=1;i
<facilities
->len
;i
++) {
959 fac_id
= g_array_index(facilities
, guint
, i
);
960 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
962 et
= ltt_facility_eventtype_get_by_name(f
, ltt_eventtype_name(et
));
963 if(unlikely(et
== NULL
)) goto event_error
;
965 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
966 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
) = thf
;
967 ev_id
= ltt_eventtype_id(et
);
969 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
970 thf
->f1
= find_field(et
, field1
);
971 if(check_fields_compatibility(first_et
, et
,
972 first_thf
->f1
, thf
->f1
))
975 thf
->f2
= find_field(et
, field2
);
976 if(check_fields_compatibility(first_et
, et
,
977 first_thf
->f2
, thf
->f2
))
980 thf
->f3
= find_field(et
, field3
);
981 if(check_fields_compatibility(first_et
, et
,
982 first_thf
->f3
, thf
->f3
))
984 thf
->hook_data
= hook_data
;
992 g_error("Event type %s does not exist",
993 g_quark_to_string(ltt_eventtype_name(et
)));
996 g_error("No %s facility", g_quark_to_string(facility
));
999 g_array_free(th
->fac_index
, TRUE
);
1000 g_array_free(th
->fac_list
, TRUE
);
1001 th
->fac_index
= NULL
;
1002 th
->fac_list
= NULL
;
1006 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
1008 g_array_free(th
->fac_index
, TRUE
);
1009 g_array_free(th
->fac_list
, TRUE
);
1013 LttvTracesetContextPosition
*lttv_traceset_context_position_new()
1015 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
,1);
1016 pos
->ep
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttEventPosition
*),
1018 pos
->tfc
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttvTracefileContext
*),
1020 pos
->timestamp
= ltt_time_infinite
;
1024 /* Save all positions, the ones not in the pqueue will have NULL
1026 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1027 LttvTracesetContextPosition
*pos
)
1030 guint num_traces
= lttv_traceset_number(self
->ts
);
1032 for(i
=0; i
<num_traces
;i
++) {
1033 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1035 guint num_tracefiles
= tracefiles
->len
;
1037 for(j
=0;j
<num_tracefiles
;j
++) {
1038 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1039 LttvTracefileContext
*, j
);
1041 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1042 LttEventPosition
*ep
;
1044 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1045 ep
= ltt_event_position_new();
1046 ltt_event_position(event
, ep
);
1047 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1048 pos
->timestamp
= (*tfc
)->timestamp
;
1052 g_array_append_val(pos
->tfc
, *tfc
);
1053 g_array_append_val(pos
->ep
, ep
);
1059 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1062 LttEventPosition
**ep
;
1064 for(i
=0;i
<pos
->ep
->len
;i
++) {
1065 ep
= &g_array_index(pos
->ep
, LttEventPosition
*, i
);
1069 g_array_free(pos
->ep
, TRUE
);
1070 g_array_free(pos
->tfc
, TRUE
);
1074 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1075 const LttvTracesetContextPosition
*src
)
1078 LttEventPosition
**src_ep
, **dest_ep
;
1080 g_array_set_size(dest
->ep
, src
->ep
->len
);
1081 g_array_set_size(dest
->tfc
, src
->tfc
->len
);
1083 for(i
=0;i
<src
->ep
->len
;i
++) {
1084 src_ep
= &g_array_index(src
->ep
, LttEventPosition
*, i
);
1085 dest_ep
= &g_array_index(dest
->ep
, LttEventPosition
*, i
);
1086 if(*src_ep
!= NULL
) {
1087 *dest_ep
= ltt_event_position_new();
1088 ltt_event_position_copy(
1094 for(i
=0;i
<src
->tfc
->len
;i
++) {
1095 g_array_index(dest
->tfc
, LttvTracefileContext
*, i
) =
1096 g_array_index(src
->tfc
, LttvTracefileContext
*, i
);
1098 dest
->timestamp
= src
->timestamp
;
1101 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1102 const LttvTracesetContextPosition
*pos
)
1107 if(pos
->ep
->len
== 0) {
1108 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1111 if(lttv_traceset_number(self
->ts
) == 0)
1114 for(i
=0;i
<pos
->ep
->len
;i
++) {
1115 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
1116 LttvTracefileContext
*tfc
=
1117 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
1120 if(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0) {
1124 if(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) == 0) {
1127 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
1129 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1133 if(ret
!= 0) return ret
;
1140 gint
lttv_traceset_context_pos_pos_compare(
1141 const LttvTracesetContextPosition
*pos1
,
1142 const LttvTracesetContextPosition
*pos2
)
1147 if(pos1
->ep
->len
== 0) {
1148 if(pos2
->ep
->len
== 0) return 0;
1151 if(pos2
->ep
->len
== 0)
1154 for(i
=0;i
<pos1
->ep
->len
;i
++) {
1155 LttEventPosition
*ep1
= g_array_index(pos1
->ep
, LttEventPosition
*, i
);
1156 LttvTracefileContext
*tfc1
= g_array_index(pos1
->tfc
,
1157 LttvTracefileContext
*, i
);
1160 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1161 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1162 LttvTracefileContext
*tfc2
= g_array_index(pos2
->tfc
,
1163 LttvTracefileContext
*, j
);
1166 ret
= ltt_event_position_compare(ep1
, ep2
);
1170 if(ret
!= 0) return ret
;
1174 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1175 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1176 LttvTracefileContext
*tfc2
= g_array_index(pos2
->tfc
,
1177 LttvTracefileContext
*, j
);
1179 if(ep2
!= NULL
) ret
= 1;
1188 LttTime
lttv_traceset_context_position_get_time(
1189 const LttvTracesetContextPosition
*pos
)
1191 return pos
->timestamp
;
1195 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1197 GTree
*pqueue
= self
->pqueue
;
1198 LttvTracefileContext
*tfc
= NULL
;
1200 g_tree_foreach(pqueue
, get_first
, &tfc
);
1205 /* lttv_process_traceset_synchronize_tracefiles
1207 * Use the sync_position field of the trace set context to synchronize each
1208 * tracefile with the previously saved position.
1210 * If no previous position has been saved, it simply does nothing.
1212 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1214 g_assert(lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
) == 0);
1220 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1222 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);