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
)
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 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
622 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
623 LttvHooks
*before_traceset
,
624 LttvHooks
*before_trace
,
625 LttvHooks
*before_tracefile
,
627 LttvHooksById
*event_by_id
)
630 /* simply add hooks in context. _before hooks are called by add_hooks. */
631 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
632 lttv_traceset_context_add_hooks(self
,
641 /* Note : a _middle must be preceded from a _seek or another middle */
642 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
645 const LttvTracesetContextPosition
*end_position
)
647 GTree
*pqueue
= self
->pqueue
;
651 LttvTracefileContext
*tfc
;
657 gboolean last_ret
= FALSE
; /* return value of the last hook list called */
659 /* Get the next event from the pqueue, call its hooks,
660 reinsert in the pqueue the following event from the same tracefile
661 unless the tracefile is finished or the event is later than the
666 g_tree_foreach(pqueue
, get_first
, &tfc
);
667 /* End of traceset : tfc is NULL */
668 if(unlikely(tfc
== NULL
))
674 * - the maximum number of events specified?
675 * - the end position ?
677 * then the read is finished. We leave the queue in the same state and
681 if(unlikely(last_ret
== TRUE
||
682 ((count
>= nb_events
) && (nb_events
!= G_MAXULONG
)) ||
683 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
684 end_position
) == 0)||
685 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
690 /* Get the tracefile with an event for the smallest time found. If two
691 or more tracefiles have events for the same time, hope that lookup
692 and remove are consistent. */
694 g_tree_remove(pqueue
, tfc
);
697 e
= ltt_tracefile_get_event(tfc
->tf
);
698 id
= ltt_event_eventtype_id(e
);
699 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
700 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
702 if(likely(!ltt_tracefile_read(tfc
->tf
))) {
703 tfc
->timestamp
= ltt_event_time(e
);
704 g_tree_insert(pqueue
, tfc
, tfc
);
710 void lttv_process_traceset_end(LttvTracesetContext
*self
,
711 LttvHooks
*after_traceset
,
712 LttvHooks
*after_trace
,
713 LttvHooks
*after_tracefile
,
715 LttvHooksById
*event_by_id
)
717 /* Remove hooks from context. _after hooks are called by remove_hooks. */
718 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
719 lttv_traceset_context_remove_hooks(self
,
727 /* Subtile modification :
728 * if tracefile has no event at or after the time requested, it is not put in
729 * the queue, as the next read would fail. */
730 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
732 guint i
, nb_tracefile
;
736 LttvTracefileContext
*tfc
;
738 GTree
*pqueue
= self
->ts_context
->pqueue
;
740 nb_tracefile
= self
->tracefiles
->len
;
742 for(i
= 0 ; i
< nb_tracefile
; i
++) {
743 tfc
= g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
744 ret
= ltt_tracefile_seek_time(tfc
->tf
, start
);
745 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
746 g_tree_remove(pqueue
, tfc
);
748 if(ret
== 0) { /* not ERANGE especially */
749 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
750 g_tree_insert(pqueue
, tfc
, tfc
);
756 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
760 LttvTraceContext
*tc
;
762 nb_trace
= lttv_traceset_number(self
->ts
);
763 for(i
= 0 ; i
< nb_trace
; i
++) {
764 tc
= self
->traces
[i
];
765 lttv_process_trace_seek_time(tc
, start
);
770 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
771 const LttvTracesetContextPosition
*pos
)
774 LttvTraceContext
*tc
;
775 LttvTracefileContext
*tfc
;
777 g_tree_destroy(self
->pqueue
);
778 self
->pqueue
= g_tree_new(compare_tracefile
);
780 for(i
=0;i
<pos
->ep
->len
; i
++) {
781 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
782 LttvTracefileContext
*tfc
=
783 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
784 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
785 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
786 g_tree_insert(self
->pqueue
, tfc
, tfc
);
794 find_field(LttEventType
*et
, const GQuark field
)
805 if(field
== 0) return NULL
;
807 f
= ltt_eventtype_field(et
);
808 t
= ltt_eventtype_type(et
);
809 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
810 nb
= ltt_type_member_number(t
);
811 for(i
= 0 ; i
< nb
; i
++) {
812 ltt_type_member_type(t
, i
, &name
);
813 if(name
== field
) break;
816 return ltt_field_member(f
, i
);
819 LttvTraceHookByFacility
*lttv_trace_hook_get_fac(LttvTraceHook
*th
,
822 return &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, facility_id
);
825 /* Get the first facility corresponding to the name. As the types must be
826 * compatible, it is relevant to use the field name and sizes of the first
827 * facility to create data structures and assume the data will be compatible
828 * thorough the trace */
829 LttvTraceHookByFacility
*lttv_trace_hook_get_first(LttvTraceHook
*th
)
831 g_assert(th
->fac_list
->len
> 0);
832 return g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0);
836 /* Returns 0 on success, -1 if fails. */
838 lttv_trace_find_hook(LttTrace
*t
, GQuark facility
, GQuark event
,
839 GQuark field1
, GQuark field2
, GQuark field3
, LttvHook h
, LttvTraceHook
*th
)
843 LttEventType
*et
, *first_et
;
847 guint i
, fac_id
, ev_id
;
849 LttvTraceHookByFacility
*thf
, *first_thf
;
851 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
853 if(unlikely(facilities
== NULL
)) goto facility_error
;
855 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
856 sizeof(LttvTraceHookByFacility
),
858 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
860 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
861 sizeof(LttvTraceHookByFacility
*),
863 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
865 fac_id
= g_array_index(facilities
, guint
, 0);
866 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
868 et
= ltt_facility_eventtype_get_by_name(f
, event
);
869 if(unlikely(et
== NULL
)) goto event_error
;
871 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
872 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0)
875 ev_id
= ltt_eventtype_id(et
);
878 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
879 thf
->f1
= find_field(et
, field1
);
880 thf
->f2
= find_field(et
, field2
);
881 thf
->f3
= find_field(et
, field3
);
885 /* Check for type compatibility too */
886 for(i
=1;i
<facilities
->len
;i
++) {
887 fac_id
= g_array_index(facilities
, guint
, i
);
888 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
890 et
= ltt_facility_eventtype_get_by_name(f
, ltt_eventtype_name(et
));
891 if(unlikely(et
== NULL
)) goto event_error
;
893 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
894 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
)
896 ev_id
= ltt_eventtype_id(et
);
898 thf
->id
= GET_HOOK_ID(fac_id
, ev_id
);
899 thf
->f1
= find_field(et
, field1
);
900 if(check_fields_compatibility(first_et
, et
,
901 first_thf
->f1
, thf
->f1
))
904 thf
->f2
= find_field(et
, field2
);
905 if(check_fields_compatibility(first_et
, et
,
906 first_thf
->f2
, thf
->f2
))
909 thf
->f3
= find_field(et
, field3
);
910 if(check_fields_compatibility(first_et
, et
,
911 first_thf
->f3
, thf
->f3
))
920 g_error("Event type %s does not exist",
921 g_quark_to_string(ltt_eventtype_name(et
)));
924 g_error("No %s facility", g_quark_to_string(facility
));
927 g_array_free(th
->fac_index
, TRUE
);
928 g_array_free(th
->fac_list
, TRUE
);
929 th
->fac_index
= NULL
;
934 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
936 g_array_free(th
->fac_index
, TRUE
);
937 g_array_free(th
->fac_list
, TRUE
);
941 LttvTracesetContextPosition
*lttv_traceset_context_position_new()
943 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
,1);
944 pos
->ep
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttEventPosition
*),
946 pos
->tfc
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttvTracefileContext
*),
948 pos
->timestamp
= ltt_time_infinite
;
952 gboolean
traverse_get_tfc(gpointer key
, gpointer value
, gpointer data
)
954 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)value
;
955 LttvTracesetContextPosition
*pos
= (LttvTracesetContextPosition
*)data
;
957 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
958 LttEventPosition
*ep
= ltt_event_position_new();
960 ltt_event_position(event
, ep
);
962 g_array_append_val(pos
->ep
, ep
);
963 g_array_append_val(pos
->tfc
, tfc
);
965 if(ltt_time_compare(tfc
->timestamp
, pos
->timestamp
) < 0)
966 pos
->timestamp
= tfc
->timestamp
;
971 /* Subtile modification :
972 * only save the tracefiles that are loaded in the pqueue */
973 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
974 LttvTracesetContextPosition
*pos
)
976 g_tree_foreach(self
->pqueue
, traverse_get_tfc
, pos
);
979 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
982 for(i
=0;i
<pos
->ep
->len
;i
++)
983 g_free(g_array_index(pos
->ep
, LttEventPosition
*, i
));
984 g_array_free(pos
->ep
, TRUE
);
985 g_array_free(pos
->tfc
, TRUE
);
989 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
990 const LttvTracesetContextPosition
*src
)
994 g_array_set_size(dest
->ep
, src
->ep
->len
);
995 g_array_set_size(dest
->tfc
, src
->tfc
->len
);
997 for(i
=0;i
<src
->ep
->len
;i
++) {
998 g_array_index(dest
->ep
, LttEventPosition
*, i
) = ltt_event_position_new();
999 ltt_event_position_copy(
1000 g_array_index(dest
->ep
, LttEventPosition
*, i
),
1001 g_array_index(src
->ep
, LttEventPosition
*, i
));
1003 for(i
=0;i
<src
->tfc
->len
;i
++) {
1004 g_array_index(dest
->tfc
, LttvTracefileContext
*, i
) =
1005 g_array_index(src
->tfc
, LttvTracefileContext
*, i
);
1007 dest
->timestamp
= src
->timestamp
;
1010 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1011 const LttvTracesetContextPosition
*pos
)
1016 for(i
=0;i
<pos
->ep
->len
;i
++) {
1017 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
1018 LttvTracefileContext
*tfc
=
1019 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
1021 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
1023 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1025 if(ret
!= 0) return ret
;
1032 gint
lttv_traceset_context_pos_pos_compare(
1033 const LttvTracesetContextPosition
*pos1
,
1034 const LttvTracesetContextPosition
*pos2
)
1039 for(i
=0;i
<pos1
->ep
->len
;i
++) {
1040 LttEventPosition
*ep1
= g_array_index(pos1
->ep
, LttEventPosition
*, i
);
1041 LttTracefile
*tf1
= ltt_event_position_tracefile(ep1
);
1043 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1044 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1045 LttTracefile
*tf2
= ltt_event_position_tracefile(ep2
);
1048 ret
= ltt_event_position_compare(ep1
, ep2
);
1049 if(ret
!= 0) return ret
;
1058 LttTime
lttv_traceset_context_position_get_time(
1059 const LttvTracesetContextPosition
*pos
)
1061 return pos
->timestamp
;
1065 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1067 GTree
*pqueue
= self
->pqueue
;
1068 LttvTracefileContext
*tfc
= NULL
;
1070 g_tree_foreach(pqueue
, get_first
, &tfc
);