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_b
->timestamp
, trace_a
->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 */
62 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
64 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
68 void lttv_context_fini(LttvTracesetContext
*self
)
70 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
75 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
77 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
84 lttv_context_new_trace_context(LttvTracesetContext
*self
)
86 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
90 LttvTracefileContext
*
91 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
93 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
96 /****************************************************************************
97 * lttv_traceset_context_compute_time_span
99 * Keep the time span is sync with on the fly addition and removal of traces
100 * in a trace set. It must be called each time a trace is added/removed from
101 * the traceset. It could be more efficient to call it only once a bunch
102 * of traces are loaded, but the calculation is not long, so it's not
105 * Author : Xang Xiu Yang
106 ***************************************************************************/
107 static void lttv_traceset_context_compute_time_span(
108 LttvTracesetContext
*self
,
109 TimeInterval
*time_span
)
111 LttvTraceset
* traceset
= self
->ts
;
112 int numTraces
= lttv_traceset_number(traceset
);
115 LttvTraceContext
*tc
;
118 time_span
->start_time
.tv_sec
= 0;
119 time_span
->start_time
.tv_nsec
= 0;
120 time_span
->end_time
.tv_sec
= 0;
121 time_span
->end_time
.tv_nsec
= 0;
123 for(i
=0; i
<numTraces
;i
++){
124 tc
= self
->traces
[i
];
127 ltt_trace_time_span_get(trace
, &s
, &e
);
130 time_span
->start_time
= s
;
131 time_span
->end_time
= e
;
133 if(s
.tv_sec
< time_span
->start_time
.tv_sec
134 || (s
.tv_sec
== time_span
->start_time
.tv_sec
135 && s
.tv_nsec
< time_span
->start_time
.tv_nsec
))
136 time_span
->start_time
= s
;
137 if(e
.tv_sec
> time_span
->end_time
.tv_sec
138 || (e
.tv_sec
== time_span
->end_time
.tv_sec
139 && e
.tv_nsec
> time_span
->end_time
.tv_nsec
))
140 time_span
->end_time
= e
;
145 static void init_tracefile_context(LttTracefile
*tracefile
,
146 LttvTraceContext
*tc
)
148 LttvTracefileContext
*tfc
;
149 LttvTracesetContext
*tsc
= tc
->ts_context
;
151 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(tsc
)->new_tracefile_context(tsc
);
153 tfc
->index
= tc
->tracefiles
->len
;
154 tc
->tracefiles
= g_array_append_val(tc
->tracefiles
, tfc
);
159 tfc
->event
= lttv_hooks_new();
160 tfc
->event_by_id
= lttv_hooks_by_id_new();
161 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
166 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
168 guint i
, j
, nb_trace
;
170 LttvTraceContext
*tc
;
172 GData
**tracefiles_groups
;
174 struct compute_tracefile_group_args args
;
176 nb_trace
= lttv_traceset_number(ts
);
178 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
179 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
180 self
->ts_a
= lttv_traceset_attribute(ts
);
181 for(i
= 0 ; i
< nb_trace
; i
++) {
182 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
183 self
->traces
[i
] = tc
;
185 tc
->ts_context
= self
;
187 tc
->vt
= lttv_traceset_get(ts
, i
);
188 tc
->t
= lttv_trace(tc
->vt
);
189 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
190 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
191 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
192 sizeof(LttvTracefileContext
*), 10);
194 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
195 if(tracefiles_groups
!= NULL
) {
196 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
199 g_datalist_foreach(tracefiles_groups
,
200 (GDataForeachFunc
)compute_tracefile_group
,
205 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
206 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
207 nb_tracefile
= nb_control
+ nb_per_cpu
;
208 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
210 for(j
= 0 ; j
< nb_tracefile
; j
++) {
211 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
212 tc
->tracefiles
[j
] = tfc
;
217 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
220 tfc
->control
= FALSE
;
221 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
225 tfc
->e
= ltt_event_new();
226 tfc
->event
= lttv_hooks_new();
227 tfc
->event_by_id
= lttv_hooks_by_id_new();
228 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
233 self
->pqueue
= g_tree_new(compare_tracefile
);
234 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
235 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
240 void fini(LttvTracesetContext
*self
)
242 guint i
, j
, nb_trace
, nb_tracefile
;
244 LttvTraceContext
*tc
;
246 LttvTracefileContext
**tfc
;
248 LttvTraceset
*ts
= self
->ts
;
250 g_tree_destroy(self
->pqueue
);
251 g_object_unref(self
->a
);
253 nb_trace
= lttv_traceset_number(ts
);
255 for(i
= 0 ; i
< nb_trace
; i
++) {
256 tc
= self
->traces
[i
];
258 g_object_unref(tc
->a
);
260 nb_tracefile
= tc
->tracefiles
->len
;
262 for(j
= 0 ; j
< nb_tracefile
; j
++) {
263 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
264 lttv_hooks_destroy((*tfc
)->event
);
265 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
266 g_object_unref((*tfc
)->a
);
267 g_object_unref(*tfc
);
269 g_array_free(tc
->tracefiles
, TRUE
);
272 g_free(self
->traces
);
276 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
277 LttvHooks
*before_traceset
,
278 LttvHooks
*before_trace
,
279 LttvHooks
*before_tracefile
,
281 LttvHooksById
*event_by_id
)
283 LttvTraceset
*ts
= self
->ts
;
287 LttvTraceContext
*tc
;
289 lttv_hooks_call(before_traceset
, self
);
291 nb_trace
= lttv_traceset_number(ts
);
293 for(i
= 0 ; i
< nb_trace
; i
++) {
294 tc
= self
->traces
[i
];
295 lttv_trace_context_add_hooks(tc
,
304 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
305 LttvHooks
*after_traceset
,
306 LttvHooks
*after_trace
,
307 LttvHooks
*after_tracefile
,
309 LttvHooksById
*event_by_id
)
312 LttvTraceset
*ts
= self
->ts
;
316 LttvTraceContext
*tc
;
318 nb_trace
= lttv_traceset_number(ts
);
320 for(i
= 0 ; i
< nb_trace
; i
++) {
321 tc
= self
->traces
[i
];
322 lttv_trace_context_remove_hooks(tc
,
329 lttv_hooks_call(after_traceset
, self
);
334 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
335 LttvHooks
*before_trace
,
336 LttvHooks
*before_tracefile
,
338 LttvHooksById
*event_by_id
)
340 guint i
, nb_tracefile
;
342 LttvTracefileContext
**tfc
;
344 lttv_hooks_call(before_trace
, self
);
346 nb_tracefile
= self
->tracefiles
->len
;
348 for(i
= 0 ; i
< nb_tracefile
; i
++) {
349 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
350 lttv_tracefile_context_add_hooks(*tfc
,
359 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
360 LttvHooks
*after_trace
,
361 LttvHooks
*after_tracefile
,
363 LttvHooksById
*event_by_id
)
365 guint i
, nb_tracefile
;
367 LttvTracefileContext
**tfc
;
369 nb_tracefile
= self
->tracefiles
->len
;
371 for(i
= 0 ; i
< nb_tracefile
; i
++) {
372 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
373 lttv_tracefile_context_remove_hooks(*tfc
,
379 lttv_hooks_call(after_trace
, self
);
382 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
383 LttvHooks
*before_tracefile
,
385 LttvHooksById
*event_by_id
)
391 lttv_hooks_call(before_tracefile
, self
);
392 lttv_hooks_add_list(self
->event
, event
);
393 if(event_by_id
!= NULL
) {
394 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
395 index
= g_array_index(event_by_id
->array
, guint
, i
);
396 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
397 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
402 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
403 LttvHooks
*after_tracefile
,
405 LttvHooksById
*event_by_id
)
411 lttv_hooks_remove_list(self
->event
, event
);
412 if(event_by_id
!= NULL
) {
413 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
414 index
= g_array_index(event_by_id
->array
, guint
, i
);
415 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
417 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
421 lttv_hooks_call(after_tracefile
, self
);
426 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext
*tfc
,
428 LttvHooks
*event_by_id
)
431 h
= lttv_hooks_by_id_find(tfc
->event_by_id
, i
);
432 lttv_hooks_add_list(h
, event_by_id
);
435 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext
*tfc
,
438 lttv_hooks_by_id_remove(tfc
->event_by_id
, i
);
441 static LttvTracesetContext
*
442 new_traceset_context(LttvTracesetContext
*self
)
444 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
448 static LttvTraceContext
*
449 new_trace_context(LttvTracesetContext
*self
)
451 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
455 static LttvTracefileContext
*
456 new_tracefile_context(LttvTracesetContext
*self
)
458 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
463 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
465 /* Be careful of anything which would not work well with shallow copies */
470 traceset_context_finalize (LttvTracesetContext
*self
)
472 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
473 ->finalize(G_OBJECT(self
));
478 traceset_context_class_init (LttvTracesetContextClass
*klass
)
480 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
482 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
485 klass
->new_traceset_context
= new_traceset_context
;
486 klass
->new_trace_context
= new_trace_context
;
487 klass
->new_tracefile_context
= new_tracefile_context
;
492 lttv_traceset_context_get_type(void)
494 static GType type
= 0;
496 static const GTypeInfo info
= {
497 sizeof (LttvTracesetContextClass
),
498 NULL
, /* base_init */
499 NULL
, /* base_finalize */
500 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
501 NULL
, /* class_finalize */
502 NULL
, /* class_data */
503 sizeof (LttvTracesetContext
),
505 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
506 NULL
/* Value handling */
509 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
517 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
519 /* Be careful of anything which would not work well with shallow copies */
524 trace_context_finalize (LttvTraceContext
*self
)
526 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
527 finalize(G_OBJECT(self
));
532 trace_context_class_init (LttvTraceContextClass
*klass
)
534 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
536 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
541 lttv_trace_context_get_type(void)
543 static GType type
= 0;
545 static const GTypeInfo info
= {
546 sizeof (LttvTraceContextClass
),
547 NULL
, /* base_init */
548 NULL
, /* base_finalize */
549 (GClassInitFunc
) trace_context_class_init
, /* class_init */
550 NULL
, /* class_finalize */
551 NULL
, /* class_data */
552 sizeof (LttvTraceContext
),
554 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
555 NULL
/* Value handling */
558 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
566 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
568 /* Be careful of anything which would not work well with shallow copies */
573 tracefile_context_finalize (LttvTracefileContext
*self
)
575 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
576 ->finalize(G_OBJECT(self
));
581 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
583 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
585 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
590 lttv_tracefile_context_get_type(void)
592 static GType type
= 0;
594 static const GTypeInfo info
= {
595 sizeof (LttvTracefileContextClass
),
596 NULL
, /* base_init */
597 NULL
, /* base_finalize */
598 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
599 NULL
, /* class_finalize */
600 NULL
, /* class_data */
601 sizeof (LttvTracefileContext
),
603 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
604 NULL
/* Value handling */
607 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
615 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
616 g_assert(key
== value
);
617 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
621 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
623 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
625 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
626 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
627 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
628 tfc
->index
, tfc
->t_context
->index
);
630 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
631 g_assert(compare_tracefile(user_data
, value
) == 0);
633 g_assert(compare_tracefile(user_data
, value
) != 0);
635 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
641 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
642 LttvHooks
*before_traceset
,
643 LttvHooks
*before_trace
,
644 LttvHooks
*before_tracefile
,
646 LttvHooksById
*event_by_id
)
649 /* simply add hooks in context. _before hooks are called by add_hooks. */
650 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
651 lttv_traceset_context_add_hooks(self
,
660 /* Note : a _middle must be preceded from a _seek or another middle */
661 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
664 const LttvTracesetContextPosition
*end_position
)
666 GTree
*pqueue
= self
->pqueue
;
668 guint fac_id
, ev_id
, id
;
670 LttvTracefileContext
*tfc
;
676 guint read_ret
= FALSE
;
678 gboolean last_ret
= FALSE
; /* return value of the last hook list called */
680 /* Get the next event from the pqueue, call its hooks,
681 reinsert in the pqueue the following event from the same tracefile
682 unless the tracefile is finished or the event is later than the
687 g_tree_foreach(pqueue
, get_first
, &tfc
);
688 /* End of traceset : tfc is NULL */
689 if(unlikely(tfc
== NULL
))
695 * - the maximum number of events specified?
696 * - the end position ?
698 * then the read is finished. We leave the queue in the same state and
702 if(unlikely(last_ret
== TRUE
||
703 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
704 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
705 end_position
) == 0)||
706 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
711 /* Get the tracefile with an event for the smallest time found. If two
712 or more tracefiles have events for the same time, hope that lookup
713 and remove are consistent. */
716 g_debug("test tree before remove");
717 g_tree_foreach(pqueue
, test_tree
, tfc
);
719 g_tree_remove(pqueue
, tfc
);
722 g_debug("test tree after remove");
723 g_tree_foreach(pqueue
, test_tree
, tfc
);
728 e
= ltt_tracefile_get_event(tfc
->tf
);
729 fac_id
= ltt_event_facility_id(e
);
730 ev_id
= ltt_event_eventtype_id(e
);
731 id
= GET_HOOK_ID(fac_id
, ev_id
);
732 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
733 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
735 read_ret
= ltt_tracefile_read(tfc
->tf
);
737 if(likely(!read_ret
)) {
738 g_debug("An event is ready");
739 tfc
->timestamp
= ltt_event_time(e
);
741 g_tree_insert(pqueue
, tfc
, tfc
);
743 tfc
->timestamp
= ltt_time_infinite
;
745 if(read_ret
== ERANGE
)
746 g_debug("End of trace");
748 g_error("Error happened in lttv_process_traceset_middle");
754 void lttv_process_traceset_end(LttvTracesetContext
*self
,
755 LttvHooks
*after_traceset
,
756 LttvHooks
*after_trace
,
757 LttvHooks
*after_tracefile
,
759 LttvHooksById
*event_by_id
)
761 /* Remove hooks from context. _after hooks are called by remove_hooks. */
762 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
763 lttv_traceset_context_remove_hooks(self
,
771 /* Subtile modification :
772 * if tracefile has no event at or after the time requested, it is not put in
773 * the queue, as the next read would fail. */
774 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
776 guint i
, nb_tracefile
;
780 LttvTracefileContext
**tfc
;
782 GTree
*pqueue
= self
->ts_context
->pqueue
;
784 nb_tracefile
= self
->tracefiles
->len
;
786 for(i
= 0 ; i
< nb_tracefile
; i
++) {
787 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
789 g_tree_remove(pqueue
, *tfc
);
791 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
792 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
794 if(ret
== 0) { /* not ERANGE especially */
795 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
796 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
798 (*tfc
)->timestamp
= ltt_time_infinite
;
804 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
808 LttvTraceContext
*tc
;
810 nb_trace
= lttv_traceset_number(self
->ts
);
811 for(i
= 0 ; i
< nb_trace
; i
++) {
812 tc
= self
->traces
[i
];
813 lttv_process_trace_seek_time(tc
, start
);
818 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
819 const LttvTracesetContextPosition
*pos
)
822 LttvTraceContext
*tc
;
823 LttvTracefileContext
*tfc
;
825 g_tree_destroy(self
->pqueue
);
826 self
->pqueue
= g_tree_new(compare_tracefile
);
828 for(i
=0;i
<pos
->ep
->len
; i
++) {
829 LttEventPosition
**ep
= &g_array_index(pos
->ep
, LttEventPosition
*, i
);
830 LttvTracefileContext
**tfc
=
831 &g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
833 g_assert(ltt_tracefile_seek_position((*tfc
)->tf
, *ep
) == 0);
834 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
835 g_tree_insert(self
->pqueue
, (*tfc
), (*tfc
));
837 (*tfc
)->timestamp
= ltt_time_infinite
;
846 find_field(LttEventType
*et
, const GQuark field
)
857 if(field
== 0) return NULL
;
859 f
= ltt_eventtype_field(et
);
860 t
= ltt_eventtype_type(et
);
861 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
862 nb
= ltt_type_member_number(t
);
863 for(i
= 0 ; i
< nb
; i
++) {
864 ltt_type_member_type(t
, i
, &name
);
865 if(name
== field
) break;
868 return ltt_field_member(f
, i
);
871 LttvTraceHookByFacility
*lttv_trace_hook_get_fac(LttvTraceHook
*th
,
874 return &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, facility_id
);
877 /* Get the first facility corresponding to the name. As the types must be
878 * compatible, it is relevant to use the field name and sizes of the first
879 * facility to create data structures and assume the data will be compatible
880 * thorough the trace */
881 LttvTraceHookByFacility
*lttv_trace_hook_get_first(LttvTraceHook
*th
)
883 g_assert(th
->fac_list
->len
> 0);
884 return g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0);
888 /* Returns 0 on success, -1 if fails. */
890 lttv_trace_find_hook(LttTrace
*t
, GQuark facility
, GQuark event
,
891 GQuark field1
, GQuark field2
, GQuark field3
, LttvHook h
, LttvTraceHook
*th
)
895 LttEventType
*et
, *first_et
;
899 guint i
, fac_id
, ev_id
;
901 LttvTraceHookByFacility
*thf
, *first_thf
;
903 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
905 if(unlikely(facilities
== NULL
)) goto facility_error
;
907 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
908 sizeof(LttvTraceHookByFacility
),
910 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
912 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
913 sizeof(LttvTraceHookByFacility
*),
915 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
917 fac_id
= g_array_index(facilities
, guint
, 0);
918 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
920 et
= ltt_facility_eventtype_get_by_name(f
, event
);
921 if(unlikely(et
== NULL
)) goto event_error
;
923 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
924 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0) = thf
;
926 ev_id
= ltt_eventtype_id(et
);
929 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
930 thf
->f1
= find_field(et
, field1
);
931 thf
->f2
= find_field(et
, field2
);
932 thf
->f3
= find_field(et
, field3
);
936 /* Check for type compatibility too */
937 for(i
=1;i
<facilities
->len
;i
++) {
938 fac_id
= g_array_index(facilities
, guint
, i
);
939 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
941 et
= ltt_facility_eventtype_get_by_name(f
, ltt_eventtype_name(et
));
942 if(unlikely(et
== NULL
)) goto event_error
;
944 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
945 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
) = thf
;
946 ev_id
= ltt_eventtype_id(et
);
948 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
949 thf
->f1
= find_field(et
, field1
);
950 if(check_fields_compatibility(first_et
, et
,
951 first_thf
->f1
, thf
->f1
))
954 thf
->f2
= find_field(et
, field2
);
955 if(check_fields_compatibility(first_et
, et
,
956 first_thf
->f2
, thf
->f2
))
959 thf
->f3
= find_field(et
, field3
);
960 if(check_fields_compatibility(first_et
, et
,
961 first_thf
->f3
, thf
->f3
))
970 g_error("Event type %s does not exist",
971 g_quark_to_string(ltt_eventtype_name(et
)));
974 g_error("No %s facility", g_quark_to_string(facility
));
977 g_array_free(th
->fac_index
, TRUE
);
978 g_array_free(th
->fac_list
, TRUE
);
979 th
->fac_index
= NULL
;
984 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
986 g_array_free(th
->fac_index
, TRUE
);
987 g_array_free(th
->fac_list
, TRUE
);
991 LttvTracesetContextPosition
*lttv_traceset_context_position_new()
993 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
,1);
994 pos
->ep
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttEventPosition
*),
996 pos
->tfc
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttvTracefileContext
*),
998 pos
->timestamp
= ltt_time_infinite
;
1002 /* Save all positions, the ones not in the pqueue will have NULL
1004 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1005 LttvTracesetContextPosition
*pos
)
1008 guint num_traces
= lttv_traceset_number(self
->ts
);
1010 for(i
=0; i
<num_traces
;i
++) {
1011 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1013 guint num_tracefiles
= tracefiles
->len
;
1015 for(j
=0;j
<num_tracefiles
;j
++) {
1016 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1017 LttvTracefileContext
*, j
);
1019 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1020 LttEventPosition
*ep
;
1022 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1023 ep
= ltt_event_position_new();
1024 ltt_event_position(event
, ep
);
1025 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1026 pos
->timestamp
= (*tfc
)->timestamp
;
1030 g_array_append_val(pos
->tfc
, *tfc
);
1031 g_array_append_val(pos
->ep
, ep
);
1037 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1040 LttEventPosition
**ep
;
1042 for(i
=0;i
<pos
->ep
->len
;i
++) {
1043 ep
= &g_array_index(pos
->ep
, LttEventPosition
*, i
);
1047 g_array_free(pos
->ep
, TRUE
);
1048 g_array_free(pos
->tfc
, TRUE
);
1052 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1053 const LttvTracesetContextPosition
*src
)
1056 LttEventPosition
**src_ep
, **dest_ep
;
1058 g_array_set_size(dest
->ep
, src
->ep
->len
);
1059 g_array_set_size(dest
->tfc
, src
->tfc
->len
);
1061 for(i
=0;i
<src
->ep
->len
;i
++) {
1062 src_ep
= &g_array_index(src
->ep
, LttEventPosition
*, i
);
1063 dest_ep
= &g_array_index(dest
->ep
, LttEventPosition
*, i
);
1064 if(*src_ep
!= NULL
) {
1065 *dest_ep
= ltt_event_position_new();
1066 ltt_event_position_copy(
1072 for(i
=0;i
<src
->tfc
->len
;i
++) {
1073 g_array_index(dest
->tfc
, LttvTracefileContext
*, i
) =
1074 g_array_index(src
->tfc
, LttvTracefileContext
*, i
);
1076 dest
->timestamp
= src
->timestamp
;
1079 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1080 const LttvTracesetContextPosition
*pos
)
1085 for(i
=0;i
<pos
->ep
->len
;i
++) {
1086 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
1087 LttvTracefileContext
*tfc
=
1088 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
1091 if(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0) {
1095 if(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) == 0) {
1098 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
1100 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1104 if(ret
!= 0) return ret
;
1111 gint
lttv_traceset_context_pos_pos_compare(
1112 const LttvTracesetContextPosition
*pos1
,
1113 const LttvTracesetContextPosition
*pos2
)
1118 for(i
=0;i
<pos1
->ep
->len
;i
++) {
1119 LttEventPosition
*ep1
= g_array_index(pos1
->ep
, LttEventPosition
*, i
);
1120 LttvTracefileContext
*tfc1
= g_array_index(pos1
->tfc
,
1121 LttvTracefileContext
*, i
);
1124 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1125 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1126 LttvTracefileContext
*tfc2
= g_array_index(pos2
->tfc
,
1127 LttvTracefileContext
*, j
);
1130 ret
= ltt_event_position_compare(ep1
, ep2
);
1134 if(ret
!= 0) return ret
;
1138 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1139 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1140 LttvTracefileContext
*tfc2
= g_array_index(pos2
->tfc
,
1141 LttvTracefileContext
*, j
);
1143 if(ep2
!= NULL
) ret
= 1;
1152 LttTime
lttv_traceset_context_position_get_time(
1153 const LttvTracesetContextPosition
*pos
)
1155 return pos
->timestamp
;
1159 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1161 GTree
*pqueue
= self
->pqueue
;
1162 LttvTracefileContext
*tfc
= NULL
;
1164 g_tree_foreach(pqueue
, get_first
, &tfc
);