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
);
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. */
716 g_debug("test tree before remove");
717 g_tree_foreach(pqueue
, test_tree
, tfc
);
719 g_tree_remove(pqueue
, tfc
);
721 g_debug("test tree after remove");
722 g_tree_foreach(pqueue
, test_tree
, tfc
);
726 e
= ltt_tracefile_get_event(tfc
->tf
);
727 fac_id
= ltt_event_facility_id(e
);
728 ev_id
= ltt_event_eventtype_id(e
);
729 id
= GET_HOOK_ID(fac_id
, ev_id
);
730 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
731 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
733 read_ret
= ltt_tracefile_read(tfc
->tf
);
735 if(likely(!read_ret
)) {
736 g_debug("An event is ready");
737 tfc
->timestamp
= ltt_event_time(e
);
739 g_tree_insert(pqueue
, tfc
, tfc
);
741 if(read_ret
== ERANGE
)
742 g_debug("End of trace");
744 g_error("Error happened in lttv_process_traceset_middle");
750 void lttv_process_traceset_end(LttvTracesetContext
*self
,
751 LttvHooks
*after_traceset
,
752 LttvHooks
*after_trace
,
753 LttvHooks
*after_tracefile
,
755 LttvHooksById
*event_by_id
)
757 /* Remove hooks from context. _after hooks are called by remove_hooks. */
758 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
759 lttv_traceset_context_remove_hooks(self
,
767 /* Subtile modification :
768 * if tracefile has no event at or after the time requested, it is not put in
769 * the queue, as the next read would fail. */
770 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
772 guint i
, nb_tracefile
;
776 LttvTracefileContext
*tfc
;
778 GTree
*pqueue
= self
->ts_context
->pqueue
;
780 nb_tracefile
= self
->tracefiles
->len
;
782 for(i
= 0 ; i
< nb_tracefile
; i
++) {
783 tfc
= g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
785 g_tree_remove(pqueue
, tfc
);
787 ret
= ltt_tracefile_seek_time(tfc
->tf
, start
);
788 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
790 if(ret
== 0) { /* not ERANGE especially */
791 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
792 g_tree_insert(pqueue
, tfc
, tfc
);
798 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
802 LttvTraceContext
*tc
;
804 nb_trace
= lttv_traceset_number(self
->ts
);
805 for(i
= 0 ; i
< nb_trace
; i
++) {
806 tc
= self
->traces
[i
];
807 lttv_process_trace_seek_time(tc
, start
);
812 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
813 const LttvTracesetContextPosition
*pos
)
816 LttvTraceContext
*tc
;
817 LttvTracefileContext
*tfc
;
819 g_tree_destroy(self
->pqueue
);
820 self
->pqueue
= g_tree_new(compare_tracefile
);
822 for(i
=0;i
<pos
->ep
->len
; i
++) {
823 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
824 LttvTracefileContext
*tfc
=
825 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
826 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
827 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
828 g_tree_insert(self
->pqueue
, tfc
, tfc
);
836 find_field(LttEventType
*et
, const GQuark field
)
847 if(field
== 0) return NULL
;
849 f
= ltt_eventtype_field(et
);
850 t
= ltt_eventtype_type(et
);
851 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
852 nb
= ltt_type_member_number(t
);
853 for(i
= 0 ; i
< nb
; i
++) {
854 ltt_type_member_type(t
, i
, &name
);
855 if(name
== field
) break;
858 return ltt_field_member(f
, i
);
861 LttvTraceHookByFacility
*lttv_trace_hook_get_fac(LttvTraceHook
*th
,
864 return &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, facility_id
);
867 /* Get the first facility corresponding to the name. As the types must be
868 * compatible, it is relevant to use the field name and sizes of the first
869 * facility to create data structures and assume the data will be compatible
870 * thorough the trace */
871 LttvTraceHookByFacility
*lttv_trace_hook_get_first(LttvTraceHook
*th
)
873 g_assert(th
->fac_list
->len
> 0);
874 return g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0);
878 /* Returns 0 on success, -1 if fails. */
880 lttv_trace_find_hook(LttTrace
*t
, GQuark facility
, GQuark event
,
881 GQuark field1
, GQuark field2
, GQuark field3
, LttvHook h
, LttvTraceHook
*th
)
885 LttEventType
*et
, *first_et
;
889 guint i
, fac_id
, ev_id
;
891 LttvTraceHookByFacility
*thf
, *first_thf
;
893 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
895 if(unlikely(facilities
== NULL
)) goto facility_error
;
897 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
898 sizeof(LttvTraceHookByFacility
),
900 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
902 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
903 sizeof(LttvTraceHookByFacility
*),
905 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
907 fac_id
= g_array_index(facilities
, guint
, 0);
908 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
910 et
= ltt_facility_eventtype_get_by_name(f
, event
);
911 if(unlikely(et
== NULL
)) goto event_error
;
913 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
914 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0)
917 ev_id
= ltt_eventtype_id(et
);
920 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
921 thf
->f1
= find_field(et
, field1
);
922 thf
->f2
= find_field(et
, field2
);
923 thf
->f3
= find_field(et
, field3
);
927 /* Check for type compatibility too */
928 for(i
=1;i
<facilities
->len
;i
++) {
929 fac_id
= g_array_index(facilities
, guint
, i
);
930 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
932 et
= ltt_facility_eventtype_get_by_name(f
, ltt_eventtype_name(et
));
933 if(unlikely(et
== NULL
)) goto event_error
;
935 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
936 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
)
938 ev_id
= ltt_eventtype_id(et
);
940 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
941 thf
->f1
= find_field(et
, field1
);
942 if(check_fields_compatibility(first_et
, et
,
943 first_thf
->f1
, thf
->f1
))
946 thf
->f2
= find_field(et
, field2
);
947 if(check_fields_compatibility(first_et
, et
,
948 first_thf
->f2
, thf
->f2
))
951 thf
->f3
= find_field(et
, field3
);
952 if(check_fields_compatibility(first_et
, et
,
953 first_thf
->f3
, thf
->f3
))
962 g_error("Event type %s does not exist",
963 g_quark_to_string(ltt_eventtype_name(et
)));
966 g_error("No %s facility", g_quark_to_string(facility
));
969 g_array_free(th
->fac_index
, TRUE
);
970 g_array_free(th
->fac_list
, TRUE
);
971 th
->fac_index
= NULL
;
976 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
978 g_array_free(th
->fac_index
, TRUE
);
979 g_array_free(th
->fac_list
, TRUE
);
983 LttvTracesetContextPosition
*lttv_traceset_context_position_new()
985 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
,1);
986 pos
->ep
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttEventPosition
*),
988 pos
->tfc
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttvTracefileContext
*),
990 pos
->timestamp
= ltt_time_infinite
;
994 gboolean
traverse_get_tfc(gpointer key
, gpointer value
, gpointer data
)
996 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)value
;
997 LttvTracesetContextPosition
*pos
= (LttvTracesetContextPosition
*)data
;
999 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
1000 LttEventPosition
*ep
= ltt_event_position_new();
1002 ltt_event_position(event
, ep
);
1004 g_array_append_val(pos
->ep
, ep
);
1005 g_array_append_val(pos
->tfc
, tfc
);
1007 if(ltt_time_compare(tfc
->timestamp
, pos
->timestamp
) < 0)
1008 pos
->timestamp
= tfc
->timestamp
;
1013 /* Subtile modification :
1014 * only save the tracefiles that are loaded in the pqueue */
1015 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
1016 LttvTracesetContextPosition
*pos
)
1018 g_tree_foreach(self
->pqueue
, traverse_get_tfc
, pos
);
1021 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
1024 for(i
=0;i
<pos
->ep
->len
;i
++)
1025 g_free(g_array_index(pos
->ep
, LttEventPosition
*, i
));
1026 g_array_free(pos
->ep
, TRUE
);
1027 g_array_free(pos
->tfc
, TRUE
);
1031 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
1032 const LttvTracesetContextPosition
*src
)
1036 g_array_set_size(dest
->ep
, src
->ep
->len
);
1037 g_array_set_size(dest
->tfc
, src
->tfc
->len
);
1039 for(i
=0;i
<src
->ep
->len
;i
++) {
1040 g_array_index(dest
->ep
, LttEventPosition
*, i
) = ltt_event_position_new();
1041 ltt_event_position_copy(
1042 g_array_index(dest
->ep
, LttEventPosition
*, i
),
1043 g_array_index(src
->ep
, LttEventPosition
*, i
));
1045 for(i
=0;i
<src
->tfc
->len
;i
++) {
1046 g_array_index(dest
->tfc
, LttvTracefileContext
*, i
) =
1047 g_array_index(src
->tfc
, LttvTracefileContext
*, i
);
1049 dest
->timestamp
= src
->timestamp
;
1052 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1053 const LttvTracesetContextPosition
*pos
)
1058 for(i
=0;i
<pos
->ep
->len
;i
++) {
1059 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
1060 LttvTracefileContext
*tfc
=
1061 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
1063 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
1065 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1067 if(ret
!= 0) return ret
;
1074 gint
lttv_traceset_context_pos_pos_compare(
1075 const LttvTracesetContextPosition
*pos1
,
1076 const LttvTracesetContextPosition
*pos2
)
1081 for(i
=0;i
<pos1
->ep
->len
;i
++) {
1082 LttEventPosition
*ep1
= g_array_index(pos1
->ep
, LttEventPosition
*, i
);
1083 LttTracefile
*tf1
= ltt_event_position_tracefile(ep1
);
1085 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1086 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1087 LttTracefile
*tf2
= ltt_event_position_tracefile(ep2
);
1090 ret
= ltt_event_position_compare(ep1
, ep2
);
1091 if(ret
!= 0) return ret
;
1100 LttTime
lttv_traceset_context_position_get_time(
1101 const LttvTracesetContextPosition
*pos
)
1103 return pos
->timestamp
;
1107 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1109 GTree
*pqueue
= self
->pqueue
;
1110 LttvTracefileContext
*tfc
= NULL
;
1112 g_tree_foreach(pqueue
, get_first
, &tfc
);