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
< lttv_hooks_by_id_max_id(event_by_id
); i
++) {
396 hook
= lttv_hooks_by_id_find(self
->event_by_id
, i
);
397 lttv_hooks_add_list(hook
, lttv_hooks_by_id_get(event_by_id
, i
));
402 void lttv_tracefile_context_remove_hooks(LttvTracefileContext
*self
,
403 LttvHooks
*after_tracefile
,
405 LttvHooksById
*event_by_id
)
412 lttv_hooks_remove_list(self
->event
, event
);
413 if(event_by_id
!= NULL
)
414 for(i
= 0; i
< lttv_hooks_by_id_max_id(event_by_id
); i
++) {
415 hook
= lttv_hooks_by_id_get(self
->event_by_id
, i
);
417 lttv_hooks_remove_list(hook
, lttv_hooks_by_id_get(event_by_id
, i
));
420 lttv_hooks_call(after_tracefile
, self
);
425 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext
*tfc
,
427 LttvHooks
*event_by_id
)
430 h
= lttv_hooks_by_id_find(tfc
->event_by_id
, i
);
431 lttv_hooks_add_list(h
, event_by_id
);
434 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext
*tfc
,
437 lttv_hooks_by_id_remove(tfc
->event_by_id
, i
);
440 static LttvTracesetContext
*
441 new_traceset_context(LttvTracesetContext
*self
)
443 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
447 static LttvTraceContext
*
448 new_trace_context(LttvTracesetContext
*self
)
450 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
454 static LttvTracefileContext
*
455 new_tracefile_context(LttvTracesetContext
*self
)
457 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
462 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
464 /* Be careful of anything which would not work well with shallow copies */
469 traceset_context_finalize (LttvTracesetContext
*self
)
471 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
472 ->finalize(G_OBJECT(self
));
477 traceset_context_class_init (LttvTracesetContextClass
*klass
)
479 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
481 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
484 klass
->new_traceset_context
= new_traceset_context
;
485 klass
->new_trace_context
= new_trace_context
;
486 klass
->new_tracefile_context
= new_tracefile_context
;
491 lttv_traceset_context_get_type(void)
493 static GType type
= 0;
495 static const GTypeInfo info
= {
496 sizeof (LttvTracesetContextClass
),
497 NULL
, /* base_init */
498 NULL
, /* base_finalize */
499 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
500 NULL
, /* class_finalize */
501 NULL
, /* class_data */
502 sizeof (LttvTracesetContext
),
504 (GInstanceInitFunc
) traceset_context_instance_init
, /* instance_init */
505 NULL
/* Value handling */
508 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
516 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
518 /* Be careful of anything which would not work well with shallow copies */
523 trace_context_finalize (LttvTraceContext
*self
)
525 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
526 finalize(G_OBJECT(self
));
531 trace_context_class_init (LttvTraceContextClass
*klass
)
533 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
535 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
540 lttv_trace_context_get_type(void)
542 static GType type
= 0;
544 static const GTypeInfo info
= {
545 sizeof (LttvTraceContextClass
),
546 NULL
, /* base_init */
547 NULL
, /* base_finalize */
548 (GClassInitFunc
) trace_context_class_init
, /* class_init */
549 NULL
, /* class_finalize */
550 NULL
, /* class_data */
551 sizeof (LttvTraceContext
),
553 (GInstanceInitFunc
) trace_context_instance_init
, /* instance_init */
554 NULL
/* Value handling */
557 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
565 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
567 /* Be careful of anything which would not work well with shallow copies */
572 tracefile_context_finalize (LttvTracefileContext
*self
)
574 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
575 ->finalize(G_OBJECT(self
));
580 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
582 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
584 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
589 lttv_tracefile_context_get_type(void)
591 static GType type
= 0;
593 static const GTypeInfo info
= {
594 sizeof (LttvTracefileContextClass
),
595 NULL
, /* base_init */
596 NULL
, /* base_finalize */
597 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
598 NULL
, /* class_finalize */
599 NULL
, /* class_data */
600 sizeof (LttvTracefileContext
),
602 (GInstanceInitFunc
) tracefile_context_instance_init
, /* instance_init */
603 NULL
/* Value handling */
606 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
614 static gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
615 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
620 void lttv_process_traceset_begin(LttvTracesetContext
*self
,
621 LttvHooks
*before_traceset
,
622 LttvHooks
*before_trace
,
623 LttvHooks
*before_tracefile
,
625 LttvHooksById
*event_by_id
)
628 /* simply add hooks in context. _before hooks are called by add_hooks. */
629 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
630 lttv_traceset_context_add_hooks(self
,
639 /* Note : a _middle must be preceded from a _seek or another middle */
640 guint
lttv_process_traceset_middle(LttvTracesetContext
*self
,
643 const LttvTracesetContextPosition
*end_position
)
645 GTree
*pqueue
= self
->pqueue
;
649 LttvTracefileContext
*tfc
;
655 gboolean last_ret
= FALSE
; /* return value of the last hook list called */
657 /* Get the next event from the pqueue, call its hooks,
658 reinsert in the pqueue the following event from the same tracefile
659 unless the tracefile is finished or the event is later than the
664 g_tree_foreach(pqueue
, get_first
, &tfc
);
665 /* End of traceset : tfc is NULL */
666 if(unlikely(tfc
== NULL
))
672 * - the maximum number of events specified?
673 * - the end position ?
675 * then the read is finished. We leave the queue in the same state and
679 if(unlikely(last_ret
== TRUE
||
680 count
>= nb_events
||
681 (end_position
!=NULL
&<tv_traceset_context_ctx_pos_compare(self
,
682 end_position
) == 0)||
683 ltt_time_compare(end
, tfc
->timestamp
) <= 0))
688 /* Get the tracefile with an event for the smallest time found. If two
689 or more tracefiles have events for the same time, hope that lookup
690 and remove are consistent. */
692 g_tree_remove(pqueue
, tfc
);
695 e
= ltt_tracefile_get_event(tfc
->tf
);
696 id
= ltt_event_eventtype_id(e
);
697 last_ret
= lttv_hooks_call_merge(tfc
->event
, tfc
,
698 lttv_hooks_by_id_get(tfc
->event_by_id
, id
), tfc
);
700 if(likely(!ltt_tracefile_read(tfc
->tf
))) {
701 tfc
->timestamp
= ltt_event_time(e
);
702 g_tree_insert(pqueue
, tfc
, tfc
);
708 void lttv_process_traceset_end(LttvTracesetContext
*self
,
709 LttvHooks
*after_traceset
,
710 LttvHooks
*after_trace
,
711 LttvHooks
*after_tracefile
,
713 LttvHooksById
*event_by_id
)
715 /* Remove hooks from context. _after hooks are called by remove_hooks. */
716 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
717 lttv_traceset_context_remove_hooks(self
,
725 /* Subtile modification :
726 * if tracefile has no event at or after the time requested, it is not put in
727 * the queue, as the next read would fail. */
728 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
730 guint i
, nb_tracefile
;
734 LttvTracefileContext
*tfc
;
736 GTree
*pqueue
= self
->ts_context
->pqueue
;
738 nb_tracefile
= self
->tracefiles
->len
;
740 for(i
= 0 ; i
< nb_tracefile
; i
++) {
741 tfc
= g_array_index(self
->tracefiles
, LttvTracefileContext
*, i
);
742 ret
= ltt_tracefile_seek_time(tfc
->tf
, start
);
743 if(ret
== EPERM
) g_error("error in lttv_process_trace_seek_time seek");
744 g_tree_remove(pqueue
, tfc
);
746 if(ret
== 0) { /* not ERANGE especially */
747 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
748 g_tree_insert(pqueue
, tfc
, tfc
);
754 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
758 LttvTraceContext
*tc
;
760 nb_trace
= lttv_traceset_number(self
->ts
);
761 for(i
= 0 ; i
< nb_trace
; i
++) {
762 tc
= self
->traces
[i
];
763 lttv_process_trace_seek_time(tc
, start
);
768 gboolean
lttv_process_traceset_seek_position(LttvTracesetContext
*self
,
769 const LttvTracesetContextPosition
*pos
)
772 LttvTraceContext
*tc
;
773 LttvTracefileContext
*tfc
;
775 g_tree_destroy(self
->pqueue
);
776 self
->pqueue
= g_tree_new(compare_tracefile
);
778 for(i
=0;i
<pos
->ep
->len
; i
++) {
779 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
780 LttvTracefileContext
*tfc
=
781 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
782 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
783 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
784 g_tree_insert(self
->pqueue
, tfc
, tfc
);
792 find_field(LttEventType
*et
, const GQuark field
)
803 if(field
== 0) return NULL
;
805 f
= ltt_eventtype_field(et
);
806 t
= ltt_eventtype_type(et
);
807 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
808 nb
= ltt_type_member_number(t
);
809 for(i
= 0 ; i
< nb
; i
++) {
810 ltt_type_member_type(t
, i
, &name
);
811 if(name
== field
) break;
814 return ltt_field_member(f
, i
);
817 LttvTraceHookByFacility
*lttv_trace_hook_get_fac(LttvTraceHook
*th
,
820 return &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, facility_id
);
823 /* Get the first facility corresponding to the name. As the types must be
824 * compatible, it is relevant to use the field name and sizes of the first
825 * facility to create data structures and assume the data will be compatible
826 * thorough the trace */
827 LttvTraceHookByFacility
*lttv_trace_hook_get_first(LttvTraceHook
*th
)
829 g_assert(th
->fac_list
->len
> 0);
830 return g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0);
834 /* Returns 0 on success, -1 if fails. */
836 lttv_trace_find_hook(LttTrace
*t
, GQuark facility
, GQuark event
,
837 GQuark field1
, GQuark field2
, GQuark field3
, LttvHook h
, LttvTraceHook
*th
)
841 LttEventType
*et
, *first_et
;
847 LttvTraceHookByFacility
*thf
, *first_thf
;
849 facilities
= ltt_trace_facility_get_by_name(t
, facility
);
851 if(unlikely(facilities
== NULL
)) goto facility_error
;
853 th
->fac_index
= g_array_sized_new(FALSE
, TRUE
,
854 sizeof(LttvTraceHookByFacility
),
856 th
->fac_index
= g_array_set_size(th
->fac_index
, NUM_FACILITIES
);
858 th
->fac_list
= g_array_sized_new(FALSE
, TRUE
,
859 sizeof(LttvTraceHookByFacility
*),
861 th
->fac_list
= g_array_set_size(th
->fac_list
, facilities
->len
);
863 fac_id
= g_array_index(facilities
, guint
, 0);
864 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
866 et
= ltt_facility_eventtype_get_by_name(f
, event
);
867 if(unlikely(et
== NULL
)) goto event_error
;
869 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
870 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, 0)
873 thf
->id
= ltt_eventtype_id(et
);
874 thf
->f1
= find_field(et
, field1
);
875 thf
->f2
= find_field(et
, field2
);
876 thf
->f3
= find_field(et
, field3
);
880 /* Check for type compatibility too */
881 for(i
=1;i
<facilities
->len
;i
++) {
882 fac_id
= g_array_index(facilities
, guint
, i
);
883 f
= ltt_trace_get_facility_by_num(t
, fac_id
);
885 et
= ltt_facility_eventtype_get_by_name(f
, ltt_eventtype_name(et
));
886 if(unlikely(et
== NULL
)) goto event_error
;
888 thf
= &g_array_index(th
->fac_index
, LttvTraceHookByFacility
, fac_id
);
889 g_array_index(th
->fac_list
, LttvTraceHookByFacility
*, i
)
892 thf
->id
= ltt_eventtype_id(et
);
893 thf
->f1
= find_field(et
, field1
);
894 if(check_fields_compatibility(first_et
, et
,
895 first_thf
->f1
, thf
->f1
))
898 thf
->f2
= find_field(et
, field2
);
899 if(check_fields_compatibility(first_et
, et
,
900 first_thf
->f2
, thf
->f2
))
903 thf
->f3
= find_field(et
, field3
);
904 if(check_fields_compatibility(first_et
, et
,
905 first_thf
->f3
, thf
->f3
))
914 g_error("Event type %s does not exist",
915 g_quark_to_string(ltt_eventtype_name(et
)));
918 g_error("No %s facility", g_quark_to_string(facility
));
921 g_array_free(th
->fac_index
, TRUE
);
922 g_array_free(th
->fac_list
, TRUE
);
923 th
->fac_index
= NULL
;
928 void lttv_trace_hook_destroy(LttvTraceHook
*th
)
930 g_array_free(th
->fac_index
, TRUE
);
931 g_array_free(th
->fac_list
, TRUE
);
935 LttvTracesetContextPosition
*lttv_traceset_context_position_new()
937 LttvTracesetContextPosition
*pos
= g_new(LttvTracesetContextPosition
,1);
938 pos
->ep
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttEventPosition
*),
940 pos
->tfc
= g_array_sized_new(FALSE
, TRUE
, sizeof(LttvTracefileContext
*),
942 pos
->timestamp
= ltt_time_infinite
;
946 gboolean
traverse_get_tfc(gpointer key
, gpointer value
, gpointer data
)
948 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)value
;
949 LttvTracesetContextPosition
*pos
= (LttvTracesetContextPosition
*)data
;
951 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
952 LttEventPosition
*ep
= ltt_event_position_new();
954 ltt_event_position(event
, ep
);
956 g_array_append_val(pos
->ep
, ep
);
957 g_array_append_val(pos
->tfc
, tfc
);
959 if(ltt_time_compare(tfc
->timestamp
, pos
->timestamp
) < 0)
960 pos
->timestamp
= tfc
->timestamp
;
965 /* Subtile modification :
966 * only save the tracefiles that are loaded in the pqueue */
967 void lttv_traceset_context_position_save(const LttvTracesetContext
*self
,
968 LttvTracesetContextPosition
*pos
)
970 g_tree_foreach(self
->pqueue
, traverse_get_tfc
, pos
);
973 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition
*pos
)
976 for(i
=0;i
<pos
->ep
->len
;i
++)
977 g_free(g_array_index(pos
->ep
, LttEventPosition
*, i
));
978 g_array_free(pos
->ep
, TRUE
);
979 g_array_free(pos
->tfc
, TRUE
);
983 void lttv_traceset_context_position_copy(LttvTracesetContextPosition
*dest
,
984 const LttvTracesetContextPosition
*src
)
988 g_array_set_size(dest
->ep
, src
->ep
->len
);
989 g_array_set_size(dest
->tfc
, src
->tfc
->len
);
991 for(i
=0;i
<src
->ep
->len
;i
++) {
992 g_array_index(dest
->ep
, LttEventPosition
*, i
) = ltt_event_position_new();
993 ltt_event_position_copy(
994 g_array_index(dest
->ep
, LttEventPosition
*, i
),
995 g_array_index(src
->ep
, LttEventPosition
*, i
));
997 for(i
=0;i
<src
->tfc
->len
;i
++) {
998 g_array_index(dest
->tfc
, LttvTracefileContext
*, i
) =
999 g_array_index(src
->tfc
, LttvTracefileContext
*, i
);
1001 dest
->timestamp
= src
->timestamp
;
1004 gint
lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext
*self
,
1005 const LttvTracesetContextPosition
*pos
)
1010 for(i
=0;i
<pos
->ep
->len
;i
++) {
1011 LttEventPosition
*ep
= g_array_index(pos
->ep
, LttEventPosition
*, i
);
1012 LttvTracefileContext
*tfc
=
1013 g_array_index(pos
->tfc
, LttvTracefileContext
*, i
);
1015 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
1017 ret
= ltt_event_position_compare((LttEventPosition
*)event
,
1019 if(ret
!= 0) return ret
;
1026 gint
lttv_traceset_context_pos_pos_compare(
1027 const LttvTracesetContextPosition
*pos1
,
1028 const LttvTracesetContextPosition
*pos2
)
1033 for(i
=0;i
<pos1
->ep
->len
;i
++) {
1034 LttEventPosition
*ep1
= g_array_index(pos1
->ep
, LttEventPosition
*, i
);
1035 LttTracefile
*tf1
= ltt_event_position_tracefile(ep1
);
1037 for(j
=0;j
<pos2
->ep
->len
;j
++) {
1038 LttEventPosition
*ep2
= g_array_index(pos2
->ep
, LttEventPosition
*, j
);
1039 LttTracefile
*tf2
= ltt_event_position_tracefile(ep2
);
1042 ret
= ltt_event_position_compare(ep1
, ep2
);
1043 if(ret
!= 0) return ret
;
1052 LttTime
lttv_traceset_context_position_get_time(
1053 const LttvTracesetContextPosition
*pos
)
1055 return pos
->timestamp
;
1059 LttvTracefileContext
*lttv_traceset_context_get_current_tfc(LttvTracesetContext
*self
)
1061 GTree
*pqueue
= self
->pqueue
;
1062 LttvTracefileContext
*tfc
= NULL
;
1064 g_tree_foreach(pqueue
, get_first
, &tfc
);