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
, nb_control
, nb_per_cpu
, nb_tracefile
;
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
);
196 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
199 g_datalist_foreach(tracefiles_groups
,
200 (GDataForeachFunc
)compute_tracefile_group
,
204 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
205 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
206 nb_tracefile
= nb_control
+ nb_per_cpu
;
207 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
209 for(j
= 0 ; j
< nb_tracefile
; j
++) {
210 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
211 tc
->tracefiles
[j
] = tfc
;
216 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
219 tfc
->control
= FALSE
;
220 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
224 tfc
->e
= ltt_event_new();
225 tfc
->event
= lttv_hooks_new();
226 tfc
->event_by_id
= lttv_hooks_by_id_new();
227 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
232 self
->pqueue
= g_tree_new(compare_tracefile
);
233 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
234 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
239 void fini(LttvTracesetContext
*self
)
241 guint i
, j
, nb_trace
, nb_tracefile
;
243 LttvTraceContext
*tc
;
245 LttvTracefileContext
**tfc
;
247 LttvTraceset
*ts
= self
->ts
;
251 g_tree_destroy(self
->pqueue
);
252 g_object_unref(self
->a
);
254 nb_trace
= lttv_traceset_number(ts
);
256 for(i
= 0 ; i
< nb_trace
; i
++) {
257 tc
= self
->traces
[i
];
259 g_object_unref(tc
->a
);
261 nb_tracefile
= tc
->tracefiles
->len
;
263 for(j
= 0 ; j
< nb_tracefile
; j
++) {
264 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
265 lttv_hooks_destroy((*tfc
)->event
);
266 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
267 g_object_unref((*tfc
)->a
);
268 g_object_unref(*tfc
);
270 g_array_free(tc
->tracefiles
, TRUE
);
273 g_free(self
->traces
);
277 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
278 LttvHooks
*before_traceset
,
279 LttvHooks
*before_trace
,
280 LttvHooks
*before_tracefile
,
282 LttvHooksById
*event_by_id
)
284 LttvTraceset
*ts
= self
->ts
;
288 LttvTraceContext
*tc
;
290 lttv_hooks_call(before_traceset
, self
);
292 nb_trace
= lttv_traceset_number(ts
);
294 for(i
= 0 ; i
< nb_trace
; i
++) {
295 tc
= self
->traces
[i
];
296 lttv_trace_context_add_hooks(tc
,
305 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
306 LttvHooks
*after_traceset
,
307 LttvHooks
*after_trace
,
308 LttvHooks
*after_tracefile
,
310 LttvHooksById
*event_by_id
)
313 LttvTraceset
*ts
= self
->ts
;
317 LttvTraceContext
*tc
;
319 nb_trace
= lttv_traceset_number(ts
);
321 for(i
= 0 ; i
< nb_trace
; i
++) {
322 tc
= self
->traces
[i
];
323 lttv_trace_context_remove_hooks(tc
,
330 lttv_hooks_call(after_traceset
, self
);
335 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
336 LttvHooks
*before_trace
,
337 LttvHooks
*before_tracefile
,
339 LttvHooksById
*event_by_id
)
341 guint i
, nb_tracefile
;
343 LttvTracefileContext
**tfc
;
345 lttv_hooks_call(before_trace
, self
);
347 nb_tracefile
= self
->tracefiles
->len
;
349 for(i
= 0 ; i
< nb_tracefile
; i
++) {
350 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
351 lttv_tracefile_context_add_hooks(*tfc
,
360 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
361 LttvHooks
*after_trace
,
362 LttvHooks
*after_tracefile
,
364 LttvHooksById
*event_by_id
)
366 guint i
, nb_tracefile
;
368 LttvTracefileContext
**tfc
;
370 nb_tracefile
= self
->tracefiles
->len
;
372 for(i
= 0 ; i
< nb_tracefile
; i
++) {
373 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
374 lttv_tracefile_context_remove_hooks(*tfc
,
380 lttv_hooks_call(after_trace
, self
);
383 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
384 LttvHooks
*before_tracefile
,
386 LttvHooksById
*event_by_id
)
392 lttv_hooks_call(before_tracefile
, self
);
393 lttv_hooks_add_list(self
->event
, event
);
394 if(event_by_id
!= NULL
) {
395 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
396 index
= g_array_index(event_by_id
->array
, guint
, i
);
397 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
398 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
403 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
404 LttvHooks
*after_tracefile
,
406 LttvHooksById
*event_by_id
)
412 lttv_hooks_remove_list(self
->event
, event
);
413 if(event_by_id
!= NULL
) {
414 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
415 index
= g_array_index(event_by_id
->array
, guint
, i
);
416 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
418 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
422 lttv_hooks_call(after_tracefile
, self
);
427 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext
*tfc
,
429 LttvHooks
*event_by_id
)
432 h
= lttv_hooks_by_id_find(tfc
->event_by_id
, i
);
433 lttv_hooks_add_list(h
, event_by_id
);
436 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext
*tfc
,
439 lttv_hooks_by_id_remove(tfc
->event_by_id
, i
);
442 static LttvTracesetContext
*
443 new_traceset_context(LttvTracesetContext
*self
)
445 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
449 static LttvTraceContext
*
450 new_trace_context(LttvTracesetContext
*self
)
452 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
456 static LttvTracefileContext
*
457 new_tracefile_context(LttvTracesetContext
*self
)
459 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
464 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
466 /* Be careful of anything which would not work well with shallow copies */
471 traceset_context_finalize (LttvTracesetContext
*self
)
473 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
474 ->finalize(G_OBJECT(self
));
479 traceset_context_class_init (LttvTracesetContextClass
*klass
)
481 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
483 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
486 klass
->new_traceset_context
= new_traceset_context
;
487 klass
->new_trace_context
= new_trace_context
;
488 klass
->new_tracefile_context
= new_tracefile_context
;
493 lttv_traceset_context_get_type(void)
495 static GType type
= 0;
497 static const GTypeInfo info
= {
498 sizeof (LttvTracesetContextClass
),
499 NULL
, /* base_init */
500 NULL
, /* base_finalize */
501 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
502 NULL
, /* class_finalize */
503 NULL
, /* class_data */
504 sizeof (LttvTracesetContext
),
506 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
507 NULL
/* Value handling */
510 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
518 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
520 /* Be careful of anything which would not work well with shallow copies */
525 trace_context_finalize (LttvTraceContext
*self
)
527 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
528 finalize(G_OBJECT(self
));
533 trace_context_class_init (LttvTraceContextClass
*klass
)
535 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
537 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
542 lttv_trace_context_get_type(void)
544 static GType type
= 0;
546 static const GTypeInfo info
= {
547 sizeof (LttvTraceContextClass
),
548 NULL
, /* base_init */
549 NULL
, /* base_finalize */
550 (GClassInitFunc
) trace_context_class_init
, /* class_init */
551 NULL
, /* class_finalize */
552 NULL
, /* class_data */
553 sizeof (LttvTraceContext
),
555 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
556 NULL
/* Value handling */
559 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
567 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
569 /* Be careful of anything which would not work well with shallow copies */
574 tracefile_context_finalize (LttvTracefileContext
*self
)
576 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
577 ->finalize(G_OBJECT(self
));
582 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
584 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
586 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
591 lttv_tracefile_context_get_type(void)
593 static GType type
= 0;
595 static const GTypeInfo info
= {
596 sizeof (LttvTracefileContextClass
),
597 NULL
, /* base_init */
598 NULL
, /* base_finalize */
599 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
600 NULL
, /* class_finalize */
601 NULL
, /* class_data */
602 sizeof (LttvTracefileContext
),
604 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
605 NULL
/* Value handling */
608 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
616 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
617 g_assert(key
== value
);
618 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
622 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
624 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
626 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
627 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
628 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
629 tfc
->index
, tfc
->t_context
->index
);
631 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
632 g_assert(compare_tracefile(user_data
, value
) == 0);
634 g_assert(compare_tracefile(user_data
, value
) != 0);
636 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
642 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
643 LttvHooks
*before_traceset
,
644 LttvHooks
*before_trace
,
645 LttvHooks
*before_tracefile
,
647 LttvHooksById
*event_by_id
)
650 /* simply add hooks in context. _before hooks are called by add_hooks. */
651 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
652 lttv_traceset_context_add_hooks(self
,
661 /* Note : a _middle must be preceded from a _seek or another middle */
662 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
665 const LttvTracesetContextPosition
*end_position
)
667 GTree
*pqueue
= self
->pqueue
;
669 guint fac_id
, ev_id
, id
;
671 LttvTracefileContext
*tfc
;
677 guint read_ret
= FALSE
;
679 gboolean last_ret
= FALSE
; /* return value of the last hook list called */
681 /* Get the next event from the pqueue, call its hooks,
682 reinsert in the pqueue the following event from the same tracefile
683 unless the tracefile is finished or the event is later than the
688 g_tree_foreach(pqueue
, get_first
, &tfc
);
689 /* End of traceset : tfc is NULL */
690 if(unlikely(tfc
== NULL
))
696 * - the maximum number of events specified?
697 * - the end position ?
699 * then the read is finished. We leave the queue in the same state and
703 if(unlikely(last_ret
== TRUE
||
704 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
705 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
706 end_position
) == 0)||
707 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
712 /* Get the tracefile with an event for the smallest time found. If two
713 or more tracefiles have events for the same time, hope that lookup
714 and remove are consistent. */
717 g_debug("test tree before remove");
718 g_tree_foreach(pqueue
, test_tree
, tfc
);
720 g_tree_remove(pqueue
, tfc
);
723 g_debug("test tree after remove");
724 g_tree_foreach(pqueue
, test_tree
, tfc
);
729 e
= ltt_tracefile_get_event(tfc
->tf
);
730 fac_id
= ltt_event_facility_id(e
);
731 ev_id
= ltt_event_eventtype_id(e
);
732 id
= GET_HOOK_ID(fac_id
, ev_id
);
733 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
734 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
736 read_ret
= ltt_tracefile_read(tfc
->tf
);
738 if(likely(!read_ret
)) {
739 g_debug("An event is ready");
740 tfc
->timestamp
= ltt_event_time(e
);
742 g_tree_insert(pqueue
, tfc
, tfc
);
744 tfc
->timestamp
= ltt_time_infinite
;
746 if(read_ret
== ERANGE
)
747 g_debug("End of trace");
749 g_error("Error happened in lttv_process_traceset_middle");
755 void lttv_process_traceset_end(LttvTracesetContext
*self
,
756 LttvHooks
*after_traceset
,
757 LttvHooks
*after_trace
,
758 LttvHooks
*after_tracefile
,
760 LttvHooksById
*event_by_id
)
762 /* Remove hooks from context. _after hooks are called by remove_hooks. */
763 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
764 lttv_traceset_context_remove_hooks(self
,
772 /* Subtile modification :
773 * if tracefile has no event at or after the time requested, it is not put in
774 * the queue, as the next read would fail. */
775 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
777 guint i
, nb_tracefile
;
781 LttvTracefileContext
**tfc
;
783 GTree
*pqueue
= self
->ts_context
->pqueue
;
785 nb_tracefile
= self
->tracefiles
->len
;
787 for(i
= 0 ; i
< nb_tracefile
; i
++) {
788 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
790 g_tree_remove(pqueue
, *tfc
);
792 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
793 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
795 if(ret
== 0) { /* not ERANGE especially */
796 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
797 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
799 (*tfc
)->timestamp
= ltt_time_infinite
;
805 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
809 LttvTraceContext
*tc
;
811 nb_trace
= lttv_traceset_number(self
->ts
);
812 for(i
= 0 ; i
< nb_trace
; i
++) {
813 tc
= self
->traces
[i
];
814 lttv_process_trace_seek_time(tc
, start
);
819 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
820 const LttvTracesetContextPosition
*pos
)
823 LttvTraceContext
*tc
;
824 LttvTracefileContext
*tfc
;
826 g_tree_destroy(self
->pqueue
);
827 self
->pqueue
= g_tree_new(compare_tracefile
);
829 for(i
=0;i
<pos
->ep
->len
; i
++) {
830 LttEventPosition
**ep
= &g_array_index(pos
->ep
, LttEventPosition
*, i
);
831 LttvTracefileContext
**tfc
=
832 &g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
834 g_assert(ltt_tracefile_seek_position((*tfc
)->tf
, *ep
) == 0);
835 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
836 g_tree_insert(self
->pqueue
, (*tfc
), (*tfc
));
838 (*tfc
)->timestamp
= ltt_time_infinite
;
847 find_field(LttEventType
*et
, const GQuark field
)
858 if(field
== 0) return NULL
;
860 f
= ltt_eventtype_field(et
);
861 t
= ltt_eventtype_type(et
);
862 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
863 nb
= ltt_type_member_number(t
);
864 for(i
= 0 ; i
< nb
; i
++) {
865 ltt_type_member_type(t
, i
, &name
);
866 if(name
== field
) break;
869 return ltt_field_member(f
, i
);
872 LttvTraceHookByFacility
*lttv_trace_hook_get_fac(LttvTraceHook
*th
,
875 return &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, facility_id
);
878 /* Get the first facility corresponding to the name. As the types must be
879 * compatible, it is relevant to use the field name and sizes of the first
880 * facility to create data structures and assume the data will be compatible
881 * thorough the trace */
882 LttvTraceHookByFacility
*lttv_trace_hook_get_first(LttvTraceHook
*th
)
884 g_assert(th
->fac_list
->len
> 0);
885 return g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0);
889 /* Returns 0 on success, -1 if fails. */
891 lttv_trace_find_hook(LttTrace
*t
, GQuark facility
, GQuark event
,
892 GQuark field1
, GQuark field2
, GQuark field3
, LttvHook h
, LttvTraceHook
*th
)
896 LttEventType
*et
, *first_et
;
900 guint i
, fac_id
, ev_id
;
902 LttvTraceHookByFacility
*thf
, *first_thf
;
904 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
906 if(unlikely(facilities
== NULL
)) goto facility_error
;
908 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
909 sizeof(LttvTraceHookByFacility
),
911 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
913 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
914 sizeof(LttvTraceHookByFacility
*),
916 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
918 fac_id
= g_array_index(facilities
, guint
, 0);
919 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
921 et
= ltt_facility_eventtype_get_by_name(f
, event
);
922 if(unlikely(et
== NULL
)) goto event_error
;
924 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
925 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0) = thf
;
927 ev_id
= ltt_eventtype_id(et
);
930 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
931 thf
->f1
= find_field(et
, field1
);
932 thf
->f2
= find_field(et
, field2
);
933 thf
->f3
= find_field(et
, field3
);
937 /* Check for type compatibility too */
938 for(i
=1;i
<facilities
->len
;i
++) {
939 fac_id
= g_array_index(facilities
, guint
, i
);
940 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
942 et
= ltt_facility_eventtype_get_by_name(f
, ltt_eventtype_name(et
));
943 if(unlikely(et
== NULL
)) goto event_error
;
945 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
946 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
) = thf
;
947 ev_id
= ltt_eventtype_id(et
);
949 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
950 thf
->f1
= find_field(et
, field1
);
951 if(check_fields_compatibility(first_et
, et
,
952 first_thf
->f1
, thf
->f1
))
955 thf
->f2
= find_field(et
, field2
);
956 if(check_fields_compatibility(first_et
, et
,
957 first_thf
->f2
, thf
->f2
))
960 thf
->f3
= find_field(et
, field3
);
961 if(check_fields_compatibility(first_et
, et
,
962 first_thf
->f3
, thf
->f3
))
971 g_error("Event type %s does not exist",
972 g_quark_to_string(ltt_eventtype_name(et
)));
975 g_error("No %s facility", g_quark_to_string(facility
));
978 g_array_free(th
->fac_index
, TRUE
);
979 g_array_free(th
->fac_list
, TRUE
);
980 th
->fac_index
= NULL
;
985 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
987 g_array_free(th
->fac_index
, TRUE
);
988 g_array_free(th
->fac_list
, TRUE
);
992 LttvTracesetContextPosition
*lttv_traceset_context_position_new()
994 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
,1);
995 pos
->ep
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttEventPosition
*),
997 pos
->tfc
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttvTracefileContext
*),
999 pos
->timestamp
= ltt_time_infinite
;
1003 /* Save all positions, the ones not in the pqueue will have NULL
1005 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1006 LttvTracesetContextPosition
*pos
)
1009 guint num_traces
= lttv_traceset_number(self
->ts
);
1011 for(i
=0; i
<num_traces
;i
++) {
1012 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1014 guint num_tracefiles
= tracefiles
->len
;
1016 for(j
=0;j
<num_tracefiles
;j
++) {
1017 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1018 LttvTracefileContext
*, j
);
1020 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1021 LttEventPosition
*ep
;
1023 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1024 ep
= ltt_event_position_new();
1025 ltt_event_position(event
, ep
);
1026 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1027 pos
->timestamp
= (*tfc
)->timestamp
;
1031 g_array_append_val(pos
->tfc
, *tfc
);
1032 g_array_append_val(pos
->ep
, ep
);
1038 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1041 LttEventPosition
**ep
;
1043 for(i
=0;i
<pos
->ep
->len
;i
++) {
1044 ep
= &g_array_index(pos
->ep
, LttEventPosition
*, i
);
1048 g_array_free(pos
->ep
, TRUE
);
1049 g_array_free(pos
->tfc
, TRUE
);
1053 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1054 const LttvTracesetContextPosition
*src
)
1057 LttEventPosition
**src_ep
, **dest_ep
;
1059 g_array_set_size(dest
->ep
, src
->ep
->len
);
1060 g_array_set_size(dest
->tfc
, src
->tfc
->len
);
1062 for(i
=0;i
<src
->ep
->len
;i
++) {
1063 src_ep
= &g_array_index(src
->ep
, LttEventPosition
*, i
);
1064 dest_ep
= &g_array_index(dest
->ep
, LttEventPosition
*, i
);
1065 if(*src_ep
!= NULL
) {
1066 *dest_ep
= ltt_event_position_new();
1067 ltt_event_position_copy(
1073 for(i
=0;i
<src
->tfc
->len
;i
++) {
1074 g_array_index(dest
->tfc
, LttvTracefileContext
*, i
) =
1075 g_array_index(src
->tfc
, LttvTracefileContext
*, i
);
1077 dest
->timestamp
= src
->timestamp
;
1080 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1081 const LttvTracesetContextPosition
*pos
)
1086 for(i
=0;i
<pos
->ep
->len
;i
++) {
1087 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
1088 LttvTracefileContext
*tfc
=
1089 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
1092 if(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0) {
1096 if(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) == 0) {
1099 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
1101 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1105 if(ret
!= 0) return ret
;
1112 gint
lttv_traceset_context_pos_pos_compare(
1113 const LttvTracesetContextPosition
*pos1
,
1114 const LttvTracesetContextPosition
*pos2
)
1119 for(i
=0;i
<pos1
->ep
->len
;i
++) {
1120 LttEventPosition
*ep1
= g_array_index(pos1
->ep
, LttEventPosition
*, i
);
1121 LttvTracefileContext
*tfc1
= g_array_index(pos1
->tfc
,
1122 LttvTracefileContext
*, i
);
1125 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1126 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1127 LttvTracefileContext
*tfc2
= g_array_index(pos2
->tfc
,
1128 LttvTracefileContext
*, j
);
1131 ret
= ltt_event_position_compare(ep1
, ep2
);
1135 if(ret
!= 0) return ret
;
1139 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1140 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1141 LttvTracefileContext
*tfc2
= g_array_index(pos2
->tfc
,
1142 LttvTracefileContext
*, j
);
1144 if(ep2
!= NULL
) ret
= 1;
1153 LttTime
lttv_traceset_context_position_get_time(
1154 const LttvTracesetContextPosition
*pos
)
1156 return pos
->timestamp
;
1160 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1162 GTree
*pqueue
= self
->pqueue
;
1163 LttvTracefileContext
*tfc
= NULL
;
1165 g_tree_foreach(pqueue
, get_first
, &tfc
);