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 */
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
)
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 // self->sync_position = lttv_traceset_context_position_new();
182 for(i
= 0 ; i
< nb_trace
; i
++) {
183 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
184 self
->traces
[i
] = tc
;
186 tc
->ts_context
= self
;
188 tc
->vt
= lttv_traceset_get(ts
, i
);
189 tc
->t
= lttv_trace(tc
->vt
);
190 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
191 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
192 tc
->tracefiles
= g_array_sized_new(FALSE
, TRUE
,
193 sizeof(LttvTracefileContext
*), 10);
195 tracefiles_groups
= ltt_trace_get_tracefiles_groups(tc
->t
);
196 if(tracefiles_groups
!= NULL
) {
197 args
.func
= (ForEachTraceFileFunc
)init_tracefile_context
;
200 g_datalist_foreach(tracefiles_groups
,
201 (GDataForeachFunc
)compute_tracefile_group
,
206 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
207 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
208 nb_tracefile
= nb_control
+ nb_per_cpu
;
209 tc
->tracefiles
= g_new(LttvTracefileContext
*, nb_tracefile
);
211 for(j
= 0 ; j
< nb_tracefile
; j
++) {
212 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
213 tc
->tracefiles
[j
] = tfc
;
218 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
221 tfc
->control
= FALSE
;
222 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
226 tfc
->e
= ltt_event_new();
227 tfc
->event
= lttv_hooks_new();
228 tfc
->event_by_id
= lttv_hooks_by_id_new();
229 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
234 self
->pqueue
= g_tree_new(compare_tracefile
);
235 lttv_process_traceset_seek_time(self
, ltt_time_zero
);
236 lttv_traceset_context_compute_time_span(self
, &self
->time_span
);
241 void fini(LttvTracesetContext
*self
)
243 guint i
, j
, nb_trace
, nb_tracefile
;
245 LttvTraceContext
*tc
;
247 LttvTracefileContext
**tfc
;
249 LttvTraceset
*ts
= self
->ts
;
251 g_tree_destroy(self
->pqueue
);
252 g_object_unref(self
->a
);
253 // lttv_traceset_context_position_destroy(self->sync_position);
255 nb_trace
= lttv_traceset_number(ts
);
257 for(i
= 0 ; i
< nb_trace
; i
++) {
258 tc
= self
->traces
[i
];
260 g_object_unref(tc
->a
);
262 nb_tracefile
= tc
->tracefiles
->len
;
264 for(j
= 0 ; j
< nb_tracefile
; j
++) {
265 tfc
= &g_array_index(tc
->tracefiles
, LttvTracefileContext
*, j
);
266 lttv_hooks_destroy((*tfc
)->event
);
267 lttv_hooks_by_id_destroy((*tfc
)->event_by_id
);
268 g_object_unref((*tfc
)->a
);
269 g_object_unref(*tfc
);
271 g_array_free(tc
->tracefiles
, TRUE
);
274 g_free(self
->traces
);
278 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
279 LttvHooks
*before_traceset
,
280 LttvHooks
*before_trace
,
281 LttvHooks
*before_tracefile
,
283 LttvHooksById
*event_by_id
)
285 LttvTraceset
*ts
= self
->ts
;
289 LttvTraceContext
*tc
;
291 lttv_hooks_call(before_traceset
, self
);
293 nb_trace
= lttv_traceset_number(ts
);
295 for(i
= 0 ; i
< nb_trace
; i
++) {
296 tc
= self
->traces
[i
];
297 lttv_trace_context_add_hooks(tc
,
306 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
307 LttvHooks
*after_traceset
,
308 LttvHooks
*after_trace
,
309 LttvHooks
*after_tracefile
,
311 LttvHooksById
*event_by_id
)
314 LttvTraceset
*ts
= self
->ts
;
318 LttvTraceContext
*tc
;
320 nb_trace
= lttv_traceset_number(ts
);
322 for(i
= 0 ; i
< nb_trace
; i
++) {
323 tc
= self
->traces
[i
];
324 lttv_trace_context_remove_hooks(tc
,
331 lttv_hooks_call(after_traceset
, self
);
336 void lttv_trace_context_add_hooks(LttvTraceContext
*self
,
337 LttvHooks
*before_trace
,
338 LttvHooks
*before_tracefile
,
340 LttvHooksById
*event_by_id
)
342 guint i
, nb_tracefile
;
344 LttvTracefileContext
**tfc
;
346 lttv_hooks_call(before_trace
, self
);
348 nb_tracefile
= self
->tracefiles
->len
;
350 for(i
= 0 ; i
< nb_tracefile
; i
++) {
351 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
352 lttv_tracefile_context_add_hooks(*tfc
,
361 void lttv_trace_context_remove_hooks(LttvTraceContext
*self
,
362 LttvHooks
*after_trace
,
363 LttvHooks
*after_tracefile
,
365 LttvHooksById
*event_by_id
)
367 guint i
, nb_tracefile
;
369 LttvTracefileContext
**tfc
;
371 nb_tracefile
= self
->tracefiles
->len
;
373 for(i
= 0 ; i
< nb_tracefile
; i
++) {
374 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
375 lttv_tracefile_context_remove_hooks(*tfc
,
381 lttv_hooks_call(after_trace
, self
);
384 void lttv_tracefile_context_add_hooks(LttvTracefileContext
*self
,
385 LttvHooks
*before_tracefile
,
387 LttvHooksById
*event_by_id
)
393 lttv_hooks_call(before_tracefile
, self
);
394 lttv_hooks_add_list(self
->event
, event
);
395 if(event_by_id
!= NULL
) {
396 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
397 index
= g_array_index(event_by_id
->array
, guint
, i
);
398 hook
= lttv_hooks_by_id_find(self
->event_by_id
, index
);
399 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
404 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
405 LttvHooks
*after_tracefile
,
407 LttvHooksById
*event_by_id
)
413 lttv_hooks_remove_list(self
->event
, event
);
414 if(event_by_id
!= NULL
) {
415 for(i
= 0; i
< event_by_id
->array
->len
; i
++) {
416 index
= g_array_index(event_by_id
->array
, guint
, i
);
417 hook
= lttv_hooks_by_id_get(self
->event_by_id
, index
);
419 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, index
));
423 lttv_hooks_call(after_tracefile
, self
);
428 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext
*tfc
,
430 LttvHooks
*event_by_id
)
433 h
= lttv_hooks_by_id_find(tfc
->event_by_id
, i
);
434 lttv_hooks_add_list(h
, event_by_id
);
437 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext
*tfc
,
440 lttv_hooks_by_id_remove(tfc
->event_by_id
, i
);
443 static LttvTracesetContext
*
444 new_traceset_context(LttvTracesetContext
*self
)
446 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
450 static LttvTraceContext
*
451 new_trace_context(LttvTracesetContext
*self
)
453 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
457 static LttvTracefileContext
*
458 new_tracefile_context(LttvTracesetContext
*self
)
460 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
465 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
467 /* Be careful of anything which would not work well with shallow copies */
472 traceset_context_finalize (LttvTracesetContext
*self
)
474 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
475 ->finalize(G_OBJECT(self
));
480 traceset_context_class_init (LttvTracesetContextClass
*klass
)
482 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
484 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
487 klass
->new_traceset_context
= new_traceset_context
;
488 klass
->new_trace_context
= new_trace_context
;
489 klass
->new_tracefile_context
= new_tracefile_context
;
494 lttv_traceset_context_get_type(void)
496 static GType type
= 0;
498 static const GTypeInfo info
= {
499 sizeof (LttvTracesetContextClass
),
500 NULL
, /* base_init */
501 NULL
, /* base_finalize */
502 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
503 NULL
, /* class_finalize */
504 NULL
, /* class_data */
505 sizeof (LttvTracesetContext
),
507 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
508 NULL
/* Value handling */
511 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
519 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
521 /* Be careful of anything which would not work well with shallow copies */
526 trace_context_finalize (LttvTraceContext
*self
)
528 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
529 finalize(G_OBJECT(self
));
534 trace_context_class_init (LttvTraceContextClass
*klass
)
536 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
538 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
543 lttv_trace_context_get_type(void)
545 static GType type
= 0;
547 static const GTypeInfo info
= {
548 sizeof (LttvTraceContextClass
),
549 NULL
, /* base_init */
550 NULL
, /* base_finalize */
551 (GClassInitFunc
) trace_context_class_init
, /* class_init */
552 NULL
, /* class_finalize */
553 NULL
, /* class_data */
554 sizeof (LttvTraceContext
),
556 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
557 NULL
/* Value handling */
560 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
568 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
570 /* Be careful of anything which would not work well with shallow copies */
575 tracefile_context_finalize (LttvTracefileContext
*self
)
577 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
578 ->finalize(G_OBJECT(self
));
583 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
585 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
587 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
592 lttv_tracefile_context_get_type(void)
594 static GType type
= 0;
596 static const GTypeInfo info
= {
597 sizeof (LttvTracefileContextClass
),
598 NULL
, /* base_init */
599 NULL
, /* base_finalize */
600 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
601 NULL
, /* class_finalize */
602 NULL
, /* class_data */
603 sizeof (LttvTracefileContext
),
605 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
606 NULL
/* Value handling */
609 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
617 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
618 g_assert(key
== value
);
619 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
623 static gboolean
test_tree(gpointer key
, gpointer value
, gpointer user_data
) {
625 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)key
;
627 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
628 g_quark_to_string(ltt_tracefile_name(tfc
->tf
)),
629 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
,
630 tfc
->index
, tfc
->t_context
->index
);
632 if(((LttvTracefileContext
*)user_data
) == (LttvTracefileContext
*)value
) {
633 g_assert(compare_tracefile(user_data
, value
) == 0);
635 g_assert(compare_tracefile(user_data
, value
) != 0);
637 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
643 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
644 LttvHooks
*before_traceset
,
645 LttvHooks
*before_trace
,
646 LttvHooks
*before_tracefile
,
648 LttvHooksById
*event_by_id
)
651 /* simply add hooks in context. _before hooks are called by add_hooks. */
652 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
653 lttv_traceset_context_add_hooks(self
,
662 /* Note : a _middle must be preceded from a _seek or another middle */
663 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
666 const LttvTracesetContextPosition
*end_position
)
668 GTree
*pqueue
= self
->pqueue
;
670 guint fac_id
, ev_id
, id
;
672 LttvTracefileContext
*tfc
;
678 guint read_ret
= FALSE
;
680 gboolean last_ret
= FALSE
; /* return value of the last hook list called */
682 /* Get the next event from the pqueue, call its hooks,
683 reinsert in the pqueue the following event from the same tracefile
684 unless the tracefile is finished or the event is later than the
689 g_tree_foreach(pqueue
, get_first
, &tfc
);
690 /* End of traceset : tfc is NULL */
691 if(unlikely(tfc
== NULL
))
697 * - the maximum number of events specified?
698 * - the end position ?
700 * then the read is finished. We leave the queue in the same state and
704 if(unlikely(last_ret
== TRUE
||
705 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
706 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
707 end_position
) == 0)||
708 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
713 /* Get the tracefile with an event for the smallest time found. If two
714 or more tracefiles have events for the same time, hope that lookup
715 and remove are consistent. */
718 g_debug("test tree before remove");
719 g_tree_foreach(pqueue
, test_tree
, tfc
);
721 g_tree_remove(pqueue
, tfc
);
724 g_debug("test tree after remove");
725 g_tree_foreach(pqueue
, test_tree
, tfc
);
730 e
= ltt_tracefile_get_event(tfc
->tf
);
731 fac_id
= ltt_event_facility_id(e
);
732 ev_id
= ltt_event_eventtype_id(e
);
733 id
= GET_HOOK_ID(fac_id
, ev_id
);
734 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
735 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
737 read_ret
= ltt_tracefile_read(tfc
->tf
);
739 if(likely(!read_ret
)) {
740 g_debug("An event is ready");
741 tfc
->timestamp
= ltt_event_time(e
);
743 g_tree_insert(pqueue
, tfc
, tfc
);
745 tfc
->timestamp
= ltt_time_infinite
;
747 if(read_ret
== ERANGE
)
748 g_debug("End of trace");
750 g_error("Error happened in lttv_process_traceset_middle");
756 void lttv_process_traceset_end(LttvTracesetContext
*self
,
757 LttvHooks
*after_traceset
,
758 LttvHooks
*after_trace
,
759 LttvHooks
*after_tracefile
,
761 LttvHooksById
*event_by_id
)
763 /* Remove hooks from context. _after hooks are called by remove_hooks. */
764 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
765 lttv_traceset_context_remove_hooks(self
,
773 /* Subtile modification :
774 * if tracefile has no event at or after the time requested, it is not put in
775 * the queue, as the next read would fail. */
776 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
778 guint i
, nb_tracefile
;
782 LttvTracefileContext
**tfc
;
784 GTree
*pqueue
= self
->ts_context
->pqueue
;
786 nb_tracefile
= self
->tracefiles
->len
;
788 for(i
= 0 ; i
< nb_tracefile
; i
++) {
789 tfc
= &g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
791 g_tree_remove(pqueue
, *tfc
);
793 ret
= ltt_tracefile_seek_time((*tfc
)->tf
, start
);
794 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
796 if(ret
== 0) { /* not ERANGE especially */
797 (*tfc
)->timestamp
= ltt_event_time(ltt_tracefile_get_event((*tfc
)->tf
));
798 g_tree_insert(pqueue
, (*tfc
), (*tfc
));
800 (*tfc
)->timestamp
= ltt_time_infinite
;
806 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
810 LttvTraceContext
*tc
;
812 nb_trace
= lttv_traceset_number(self
->ts
);
813 for(i
= 0 ; i
< nb_trace
; i
++) {
814 tc
= self
->traces
[i
];
815 lttv_process_trace_seek_time(tc
, start
);
820 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
821 const LttvTracesetContextPosition
*pos
)
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 if(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
, gpointer hook_data
,
897 LttEventType
*et
, *first_et
;
901 guint i
, fac_id
, ev_id
;
903 LttvTraceHookByFacility
*thf
, *first_thf
;
905 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
907 if(unlikely(facilities
== NULL
)) goto facility_error
;
909 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
910 sizeof(LttvTraceHookByFacility
),
912 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
914 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
915 sizeof(LttvTraceHookByFacility
*),
917 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
919 fac_id
= g_array_index(facilities
, guint
, 0);
920 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
922 et
= ltt_facility_eventtype_get_by_name(f
, event
);
923 if(unlikely(et
== NULL
)) goto event_error
;
925 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
926 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0) = thf
;
928 ev_id
= ltt_eventtype_id(et
);
931 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
932 thf
->f1
= find_field(et
, field1
);
933 thf
->f2
= find_field(et
, field2
);
934 thf
->f3
= find_field(et
, field3
);
935 thf
->hook_data
= hook_data
;
940 /* Check for type compatibility too */
941 for(i
=1;i
<facilities
->len
;i
++) {
942 fac_id
= g_array_index(facilities
, guint
, i
);
943 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
945 et
= ltt_facility_eventtype_get_by_name(f
, ltt_eventtype_name(et
));
946 if(unlikely(et
== NULL
)) goto event_error
;
948 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
949 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
) = thf
;
950 ev_id
= ltt_eventtype_id(et
);
952 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
953 thf
->f1
= find_field(et
, field1
);
954 if(check_fields_compatibility(first_et
, et
,
955 first_thf
->f1
, thf
->f1
))
958 thf
->f2
= find_field(et
, field2
);
959 if(check_fields_compatibility(first_et
, et
,
960 first_thf
->f2
, thf
->f2
))
963 thf
->f3
= find_field(et
, field3
);
964 if(check_fields_compatibility(first_et
, et
,
965 first_thf
->f3
, thf
->f3
))
967 thf
->hook_data
= hook_data
;
975 g_error("Event type %s does not exist",
976 g_quark_to_string(ltt_eventtype_name(et
)));
979 g_error("No %s facility", g_quark_to_string(facility
));
982 g_array_free(th
->fac_index
, TRUE
);
983 g_array_free(th
->fac_list
, TRUE
);
984 th
->fac_index
= NULL
;
989 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
991 g_array_free(th
->fac_index
, TRUE
);
992 g_array_free(th
->fac_list
, TRUE
);
996 LttvTracesetContextPosition
*lttv_traceset_context_position_new()
998 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
,1);
999 pos
->ep
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttEventPosition
*),
1001 pos
->tfc
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttvTracefileContext
*),
1003 pos
->timestamp
= ltt_time_infinite
;
1007 /* Save all positions, the ones not in the pqueue will have NULL
1009 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1010 LttvTracesetContextPosition
*pos
)
1013 guint num_traces
= lttv_traceset_number(self
->ts
);
1015 for(i
=0; i
<num_traces
;i
++) {
1016 GArray
* tracefiles
= self
->traces
[i
]->tracefiles
;
1018 guint num_tracefiles
= tracefiles
->len
;
1020 for(j
=0;j
<num_tracefiles
;j
++) {
1021 LttvTracefileContext
**tfc
= &g_array_index(tracefiles
,
1022 LttvTracefileContext
*, j
);
1024 LttEvent
*event
= ltt_tracefile_get_event((*tfc
)->tf
);
1025 LttEventPosition
*ep
;
1027 if(ltt_time_compare((*tfc
)->timestamp
, ltt_time_infinite
) != 0) {
1028 ep
= ltt_event_position_new();
1029 ltt_event_position(event
, ep
);
1030 if(ltt_time_compare((*tfc
)->timestamp
, pos
->timestamp
) < 0)
1031 pos
->timestamp
= (*tfc
)->timestamp
;
1035 g_array_append_val(pos
->tfc
, *tfc
);
1036 g_array_append_val(pos
->ep
, ep
);
1042 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1045 LttEventPosition
**ep
;
1047 for(i
=0;i
<pos
->ep
->len
;i
++) {
1048 ep
= &g_array_index(pos
->ep
, LttEventPosition
*, i
);
1052 g_array_free(pos
->ep
, TRUE
);
1053 g_array_free(pos
->tfc
, TRUE
);
1057 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1058 const LttvTracesetContextPosition
*src
)
1061 LttEventPosition
**src_ep
, **dest_ep
;
1063 g_array_set_size(dest
->ep
, src
->ep
->len
);
1064 g_array_set_size(dest
->tfc
, src
->tfc
->len
);
1066 for(i
=0;i
<src
->ep
->len
;i
++) {
1067 src_ep
= &g_array_index(src
->ep
, LttEventPosition
*, i
);
1068 dest_ep
= &g_array_index(dest
->ep
, LttEventPosition
*, i
);
1069 if(*src_ep
!= NULL
) {
1070 *dest_ep
= ltt_event_position_new();
1071 ltt_event_position_copy(
1077 for(i
=0;i
<src
->tfc
->len
;i
++) {
1078 g_array_index(dest
->tfc
, LttvTracefileContext
*, i
) =
1079 g_array_index(src
->tfc
, LttvTracefileContext
*, i
);
1081 dest
->timestamp
= src
->timestamp
;
1084 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1085 const LttvTracesetContextPosition
*pos
)
1090 if(pos
->ep
->len
== 0) {
1091 if(lttv_traceset_number(self
->ts
) == 0) return 0;
1094 if(lttv_traceset_number(self
->ts
) == 0)
1097 for(i
=0;i
<pos
->ep
->len
;i
++) {
1098 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
1099 LttvTracefileContext
*tfc
=
1100 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
1103 if(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0) {
1107 if(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) == 0) {
1110 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
1112 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1116 if(ret
!= 0) return ret
;
1123 gint
lttv_traceset_context_pos_pos_compare(
1124 const LttvTracesetContextPosition
*pos1
,
1125 const LttvTracesetContextPosition
*pos2
)
1130 if(pos1
->ep
->len
== 0) {
1131 if(pos2
->ep
->len
== 0) return 0;
1134 if(pos2
->ep
->len
== 0)
1137 for(i
=0;i
<pos1
->ep
->len
;i
++) {
1138 LttEventPosition
*ep1
= g_array_index(pos1
->ep
, LttEventPosition
*, i
);
1139 LttvTracefileContext
*tfc1
= g_array_index(pos1
->tfc
,
1140 LttvTracefileContext
*, i
);
1143 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1144 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1145 LttvTracefileContext
*tfc2
= g_array_index(pos2
->tfc
,
1146 LttvTracefileContext
*, j
);
1149 ret
= ltt_event_position_compare(ep1
, ep2
);
1153 if(ret
!= 0) return ret
;
1157 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1158 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1159 LttvTracefileContext
*tfc2
= g_array_index(pos2
->tfc
,
1160 LttvTracefileContext
*, j
);
1162 if(ep2
!= NULL
) ret
= 1;
1171 LttTime
lttv_traceset_context_position_get_time(
1172 const LttvTracesetContextPosition
*pos
)
1174 return pos
->timestamp
;
1178 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1180 GTree
*pqueue
= self
->pqueue
;
1181 LttvTracefileContext
*tfc
= NULL
;
1183 g_tree_foreach(pqueue
, get_first
, &tfc
);
1188 /* lttv_process_traceset_synchronize_tracefiles
1190 * Use the sync_position field of the trace set context to synchronize each
1191 * tracefile with the previously saved position.
1193 * If no previous position has been saved, it simply does nothing.
1195 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext
*tsc
)
1197 g_assert(lttv_process_traceset_seek_position(tsc
, tsc
->sync_position
) == 0);
1203 void lttv_process_traceset_get_sync_data(LttvTracesetContext
*tsc
)
1205 lttv_traceset_context_position_save(tsc
, tsc
->sync_position
);