2 #include <lttv/processTrace.h>
4 #include <ltt/facility.h>
6 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
8 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
12 void lttv_context_fini(LttvTracesetContext
*self
)
14 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
19 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
21 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
28 lttv_context_new_trace_context(LttvTracesetContext
*self
)
30 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
34 LttvTracefileContext
*
35 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
37 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
40 /****************************************************************************
41 * lttv_traceset_context_compute_time_span
43 * Keep the Time_Span is sync with on the fly addition and removal of traces
44 * in a trace set. It must be called each time a trace is added/removed from
45 * the traceset. It could be more efficient to call it only once a bunch
46 * of traces are loaded, but the calculation is not long, so it's not
49 * Author : Xang Xiu Yang
50 * Imported from gtkTraceSet.c by Mathieu Desnoyers
51 ***************************************************************************/
52 static void lttv_traceset_context_compute_time_span(
53 LttvTracesetContext
*self
,
54 TimeInterval
*Time_Span
)
56 LttvTraceset
* traceset
= self
->ts
;
57 int numTraces
= lttv_traceset_number(traceset
);
63 for(i
=0; i
<numTraces
;i
++){
67 ltt_trace_time_span_get(trace
, &s
, &e
);
70 Time_Span
->startTime
= s
;
71 Time_Span
->endTime
= e
;
73 if(s
.tv_sec
< Time_Span
->startTime
.tv_sec
||
74 (s
.tv_sec
== Time_Span
->startTime
.tv_sec
75 && s
.tv_nsec
< Time_Span
->startTime
.tv_nsec
))
76 Time_Span
->startTime
= s
;
77 if(e
.tv_sec
> Time_Span
->endTime
.tv_sec
||
78 (e
.tv_sec
== Time_Span
->endTime
.tv_sec
&&
79 e
.tv_nsec
> Time_Span
->endTime
.tv_nsec
))
80 Time_Span
->endTime
= e
;
87 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
89 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
93 LttvTracefileContext
*tfc
;
95 LttTime null_time
= {0, 0};
97 nb_trace
= lttv_traceset_number(ts
);
99 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
100 self
->before
= lttv_hooks_new();
101 self
->after
= lttv_hooks_new();
102 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
103 self
->ts_a
= lttv_traceset_attribute(ts
);
104 for(i
= 0 ; i
< nb_trace
; i
++) {
105 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
106 self
->traces
[i
] = tc
;
108 tc
->ts_context
= self
;
110 tc
->vt
= lttv_traceset_get(ts
, i
);
111 tc
->t
= lttv_trace(tc
->vt
);
112 tc
->check
= lttv_hooks_new();
113 tc
->before
= lttv_hooks_new();
114 tc
->after
= lttv_hooks_new();
115 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
116 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
117 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
118 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
119 nb_tracefile
= nb_control
+ nb_per_cpu
;
120 tc
->control_tracefiles
= g_new(LttvTracefileContext
*, nb_control
);
121 tc
->per_cpu_tracefiles
= g_new(LttvTracefileContext
*, nb_per_cpu
);
123 for(j
= 0 ; j
< nb_tracefile
; j
++) {
124 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
126 tc
->control_tracefiles
[j
] = tfc
;
129 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
132 tc
->per_cpu_tracefiles
[j
- nb_control
] = tfc
;
133 tfc
->control
= FALSE
;
134 tfc
->index
= j
- nb_control
;
135 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
138 tfc
->check
= lttv_hooks_new();
139 tfc
->before
= lttv_hooks_new();
140 tfc
->after
= lttv_hooks_new();
141 tfc
->check_event
= lttv_hooks_new();
142 tfc
->before_event
= lttv_hooks_new();
143 tfc
->before_event_by_id
= lttv_hooks_by_id_new();
144 tfc
->after_event
= lttv_hooks_new();
145 tfc
->after_event_by_id
= lttv_hooks_by_id_new();
146 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
149 lttv_process_traceset_seek_time(self
, null_time
);
150 /*CHECK why dynamically allocate the time span... and the casing is wroNg*/
151 self
->Time_Span
= g_new(TimeInterval
,1);
152 lttv_traceset_context_compute_time_span(self
, self
->Time_Span
);
156 void fini(LttvTracesetContext
*self
)
158 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
160 LttvTraceContext
*tc
;
162 LttvTracefileContext
*tfc
;
164 LttvTraceset
*ts
= self
->ts
;
166 g_free(self
->Time_Span
);
168 lttv_hooks_destroy(self
->before
);
169 lttv_hooks_destroy(self
->after
);
171 g_object_unref(self
->a
);
173 nb_trace
= lttv_traceset_number(ts
);
175 for(i
= 0 ; i
< nb_trace
; i
++) {
176 tc
= self
->traces
[i
];
178 lttv_hooks_destroy(tc
->check
);
179 lttv_hooks_destroy(tc
->before
);
180 lttv_hooks_destroy(tc
->after
);
181 g_object_unref(tc
->a
);
183 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
184 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
185 nb_tracefile
= nb_control
+ nb_per_cpu
;
187 for(j
= 0 ; j
< nb_tracefile
; j
++) {
188 if(j
< nb_control
) tfc
= tc
->control_tracefiles
[j
];
189 else tfc
= tc
->per_cpu_tracefiles
[j
- nb_control
];
191 lttv_hooks_destroy(tfc
->check
);
192 lttv_hooks_destroy(tfc
->before
);
193 lttv_hooks_destroy(tfc
->after
);
194 lttv_hooks_destroy(tfc
->check_event
);
195 lttv_hooks_destroy(tfc
->before_event
);
196 lttv_hooks_by_id_destroy(tfc
->before_event_by_id
);
197 lttv_hooks_destroy(tfc
->after_event
);
198 lttv_hooks_by_id_destroy(tfc
->after_event_by_id
);
199 g_object_unref(tfc
->a
);
202 g_free(tc
->control_tracefiles
);
203 g_free(tc
->per_cpu_tracefiles
);
206 g_free(self
->traces
);
210 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
211 LttvHooks
*before_traceset
,
212 LttvHooks
*after_traceset
,
213 LttvHooks
*check_trace
,
214 LttvHooks
*before_trace
,
215 LttvHooks
*after_trace
,
216 LttvHooks
*check_tracefile
,
217 LttvHooks
*before_tracefile
,
218 LttvHooks
*after_tracefile
,
219 LttvHooks
*check_event
,
220 LttvHooks
*before_event
,
221 LttvHooks
*after_event
)
223 LttvTraceset
*ts
= self
->ts
;
225 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
227 LttvTraceContext
*tc
;
229 LttvTracefileContext
*tfc
;
233 lttv_hooks_add_list(self
->before
, before_traceset
);
234 lttv_hooks_add_list(self
->after
, after_traceset
);
235 nb_trace
= lttv_traceset_number(ts
);
237 for(i
= 0 ; i
< nb_trace
; i
++) {
238 tc
= self
->traces
[i
];
239 lttv_hooks_add_list(tc
->check
, check_trace
);
240 lttv_hooks_add_list(tc
->before
, before_trace
);
241 lttv_hooks_add_list(tc
->after
, after_trace
);
242 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
243 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
244 nb_tracefile
= nb_control
+ nb_per_cpu
;
246 for(j
= 0 ; j
< nb_tracefile
; j
++) {
248 tfc
= tc
->control_tracefiles
[j
];
251 tfc
= tc
->per_cpu_tracefiles
[j
-nb_control
];
253 lttv_hooks_add_list(tfc
->check
, check_tracefile
);
254 lttv_hooks_add_list(tfc
->before
, before_tracefile
);
255 lttv_hooks_add_list(tfc
->after
, after_tracefile
);
256 lttv_hooks_add_list(tfc
->check_event
, check_event
);
257 lttv_hooks_add_list(tfc
->before_event
, before_event
);
258 lttv_hooks_add_list(tfc
->after_event
, after_event
);
264 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
265 LttvHooks
*before_traceset
,
266 LttvHooks
*after_traceset
,
267 LttvHooks
*check_trace
,
268 LttvHooks
*before_trace
,
269 LttvHooks
*after_trace
,
270 LttvHooks
*check_tracefile
,
271 LttvHooks
*before_tracefile
,
272 LttvHooks
*after_tracefile
,
273 LttvHooks
*check_event
,
274 LttvHooks
*before_event
,
275 LttvHooks
*after_event
)
277 LttvTraceset
*ts
= self
->ts
;
279 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
281 LttvTraceContext
*tc
;
283 LttvTracefileContext
*tfc
;
287 lttv_hooks_remove_list(self
->before
, before_traceset
);
288 lttv_hooks_remove_list(self
->after
, after_traceset
);
289 nb_trace
= lttv_traceset_number(ts
);
291 for(i
= 0 ; i
< nb_trace
; i
++) {
292 tc
= self
->traces
[i
];
293 lttv_hooks_remove_list(tc
->check
, check_trace
);
294 lttv_hooks_remove_list(tc
->before
, before_trace
);
295 lttv_hooks_remove_list(tc
->after
, after_trace
);
296 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
297 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
298 nb_tracefile
= nb_control
+ nb_per_cpu
;
300 for(j
= 0 ; j
< nb_tracefile
; j
++) {
302 tfc
= tc
->control_tracefiles
[j
];
305 tfc
= tc
->per_cpu_tracefiles
[j
-nb_control
];
307 lttv_hooks_remove_list(tfc
->check
, check_tracefile
);
308 lttv_hooks_remove_list(tfc
->before
, before_tracefile
);
309 lttv_hooks_remove_list(tfc
->after
, after_tracefile
);
310 lttv_hooks_remove_list(tfc
->check_event
, check_event
);
311 lttv_hooks_remove_list(tfc
->before_event
, before_event
);
312 lttv_hooks_remove_list(tfc
->after_event
, after_event
);
318 static LttvTracesetContext
*
319 new_traceset_context(LttvTracesetContext
*self
)
321 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
325 static LttvTraceContext
*
326 new_trace_context(LttvTracesetContext
*self
)
328 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
332 static LttvTracefileContext
*
333 new_tracefile_context(LttvTracesetContext
*self
)
335 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
340 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
342 /* Be careful of anything which would not work well with shallow copies */
347 traceset_context_finalize (LttvTracesetContext
*self
)
349 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
350 ->finalize(G_OBJECT(self
));
355 traceset_context_class_init (LttvTracesetContextClass
*klass
)
357 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
359 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
362 klass
->new_traceset_context
= new_traceset_context
;
363 klass
->new_trace_context
= new_trace_context
;
364 klass
->new_tracefile_context
= new_tracefile_context
;
369 lttv_traceset_context_get_type(void)
371 static GType type
= 0;
373 static const GTypeInfo info
= {
374 sizeof (LttvTracesetContextClass
),
375 NULL
, /* base_init */
376 NULL
, /* base_finalize */
377 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
378 NULL
, /* class_finalize */
379 NULL
, /* class_data */
380 sizeof (LttvTracesetContext
),
382 (GInstanceInitFunc
) traceset_context_instance_init
/* instance_init */
385 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
393 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
395 /* Be careful of anything which would not work well with shallow copies */
400 trace_context_finalize (LttvTraceContext
*self
)
402 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
403 finalize(G_OBJECT(self
));
408 trace_context_class_init (LttvTraceContextClass
*klass
)
410 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
412 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
417 lttv_trace_context_get_type(void)
419 static GType type
= 0;
421 static const GTypeInfo info
= {
422 sizeof (LttvTraceContextClass
),
423 NULL
, /* base_init */
424 NULL
, /* base_finalize */
425 (GClassInitFunc
) trace_context_class_init
, /* class_init */
426 NULL
, /* class_finalize */
427 NULL
, /* class_data */
428 sizeof (LttvTraceContext
),
430 (GInstanceInitFunc
) trace_context_instance_init
/* instance_init */
433 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
441 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
443 /* Be careful of anything which would not work well with shallow copies */
448 tracefile_context_finalize (LttvTracefileContext
*self
)
450 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
451 ->finalize(G_OBJECT(self
));
456 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
458 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
460 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
465 lttv_tracefile_context_get_type(void)
467 static GType type
= 0;
469 static const GTypeInfo info
= {
470 sizeof (LttvTracefileContextClass
),
471 NULL
, /* base_init */
472 NULL
, /* base_finalize */
473 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
474 NULL
, /* class_finalize */
475 NULL
, /* class_data */
476 sizeof (LttvTracefileContext
),
478 (GInstanceInitFunc
) tracefile_context_instance_init
/* instance_init */
481 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
488 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
490 return ltt_time_compare(*((LttTime
*)a
), *((LttTime
*)b
));
494 gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
495 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
500 void lttv_process_traceset(LttvTracesetContext
*self
, LttTime end
,
501 unsigned maxNumEvents
)
503 GPtrArray
*traces
= g_ptr_array_new();
505 GPtrArray
*tracefiles
= g_ptr_array_new();
507 GTree
*pqueue
= g_tree_new(compare_tracefile
);
509 guint i
, j
, nbi
, nbj
, id
, nb_control
, nb_cpu
;
513 LttvTraceContext
*tc
;
515 LttTracefile
*tracefile
;
517 LttvTracefileContext
*tfc
;
523 LttTime previous_timestamp
= {0, 0};
525 /* Call all before_traceset, before_trace, and before_tracefile hooks.
526 For all qualifying tracefiles, seek to the start time, create a context,
527 read one event and insert in the pqueue based on the event time. */
529 lttv_hooks_call(self
->before
, self
);
530 nbi
= lttv_traceset_number(self
->ts
);
532 for(i
= 0 ; i
< nbi
; i
++) {
533 tc
= self
->traces
[i
];
536 if(!lttv_hooks_call_check(tc
->check
, tc
)) {
537 g_ptr_array_add(traces
, tc
);
538 lttv_hooks_call(tc
->before
, tc
);
539 nb_control
= ltt_trace_control_tracefile_number(trace
);
540 nb_cpu
= ltt_trace_per_cpu_tracefile_number(trace
);
541 nbj
= nb_control
+ nb_cpu
;
543 for(j
= 0 ; j
< nbj
; j
++) {
545 tfc
= tc
->control_tracefiles
[j
];
548 tfc
= tc
->per_cpu_tracefiles
[j
- nb_control
];
553 if(!lttv_hooks_call_check(tfc
->check
, tfc
)) {
554 g_ptr_array_add(tracefiles
, tfc
);
555 lttv_hooks_call(tfc
->before
, tfc
);
558 g_tree_insert(pqueue
, &(tfc
->timestamp
), tfc
);
565 /* Get the next event from the pqueue, call its hooks,
566 reinsert in the pqueue the following event from the same tracefile
567 unless the tracefile is finished or the event is later than the
572 g_tree_foreach(pqueue
, get_first
, &tfc
);
573 if(tfc
== NULL
) break;
575 /* Have we reached the maximum number of events specified? However,
576 continue for all the events with the same time stamp (CHECK?). Then,
577 empty the queue and break from the loop. */
580 if(count
> maxNumEvents
){
581 if(tfc
->timestamp
.tv_sec
== previous_timestamp
.tv_sec
&&
582 tfc
->timestamp
.tv_nsec
== previous_timestamp
.tv_nsec
) {
587 g_tree_foreach(pqueue
, get_first
, &tfc
);
588 if(tfc
== NULL
) break;
589 g_tree_remove(pqueue
, &(tfc
->timestamp
));
594 previous_timestamp
= tfc
->timestamp
;
597 /* Get the tracefile with an event for the smallest time found. If two
598 or more tracefiles have events for the same time, hope that lookup
599 and remove are consistent. */
601 tfc
= g_tree_lookup(pqueue
, &(tfc
->timestamp
));
602 g_tree_remove(pqueue
, &(tfc
->timestamp
));
604 if(!lttv_hooks_call(tfc
->check_event
, tfc
)) {
605 id
= ltt_event_eventtype_id(tfc
->e
);
606 lttv_hooks_call(tfc
->before_event
, tfc
);
607 lttv_hooks_call(lttv_hooks_by_id_get(tfc
->before_event_by_id
, id
), tfc
);
608 lttv_hooks_call(tfc
->after_event
, tfc
);
609 lttv_hooks_call(lttv_hooks_by_id_get(tfc
->after_event_by_id
, id
), tfc
);
612 event
= ltt_tracefile_read(tfc
->tf
);
615 tfc
->timestamp
= ltt_event_time(event
);
616 if(tfc
->timestamp
.tv_sec
< end
.tv_sec
||
617 (tfc
->timestamp
.tv_sec
== end
.tv_sec
&& tfc
->timestamp
.tv_nsec
<= end
.tv_nsec
))
618 g_tree_insert(pqueue
, &(tfc
->timestamp
), tfc
);
622 /* Call all the after_tracefile, after_trace and after_traceset hooks. */
624 for(i
= 0, j
= 0 ; i
< traces
->len
; i
++) {
625 tc
= traces
->pdata
[i
];
626 while(j
< tracefiles
->len
) {
627 tfc
= tracefiles
->pdata
[j
];
629 if(tfc
->t_context
== tc
) {
630 lttv_hooks_call(tfc
->after
, tfc
);
635 lttv_hooks_call(tc
->after
, tc
);
638 g_assert(j
== tracefiles
->len
);
639 lttv_hooks_call(self
->after
, self
);
641 /* Free the traces, tracefiles and pqueue */
643 g_ptr_array_free(tracefiles
, TRUE
);
644 g_ptr_array_free(traces
, TRUE
);
645 g_tree_destroy(pqueue
);
649 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
651 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
653 LttvTracefileContext
*tfc
;
657 nb_control
= ltt_trace_control_tracefile_number(self
->t
);
658 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->t
);
659 nb_tracefile
= nb_control
+ nb_per_cpu
;
660 for(i
= 0 ; i
< nb_tracefile
; i
++) {
661 if(i
< nb_control
) tfc
= self
->control_tracefiles
[i
];
662 else tfc
= self
->per_cpu_tracefiles
[i
- nb_control
];
664 ltt_tracefile_seek_time(tfc
->tf
, start
);
665 event
= ltt_tracefile_read(tfc
->tf
);
667 if(event
!= NULL
) tfc
->timestamp
= ltt_event_time(event
);
672 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
676 LttvTraceContext
*tc
;
678 nb_trace
= lttv_traceset_number(self
->ts
);
679 for(i
= 0 ; i
< nb_trace
; i
++) {
680 tc
= self
->traces
[i
];
681 lttv_process_trace_seek_time(tc
, start
);
687 find_field(LttEventType
*et
, const char *field
)
697 if(field
== NULL
) return NULL
;
699 f
= ltt_eventtype_field(et
);
700 t
= ltt_eventtype_type(et
);
701 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
702 nb
= ltt_type_member_number(t
);
703 for(i
= 0 ; i
< nb
; i
++) {
704 ltt_type_member_type(t
, i
, &name
);
705 if(strcmp(name
, field
) == 0) break;
708 return ltt_field_member(f
, i
);
713 lttv_trace_find_hook(LttTrace
*t
, char *facility
, char *event_type
,
714 char *field1
, char *field2
, char *field3
, LttvHook h
, LttvTraceHook
*th
)
724 nb
= ltt_trace_facility_find(t
, facility
, &pos
);
725 if(nb
< 1) g_error("No %s facility", facility
);
726 f
= ltt_trace_facility_get(t
, pos
);
727 et
= ltt_facility_eventtype_get_by_name(f
, event_type
);
728 if(et
== NULL
) g_error("Event %s does not exist", event_type
);
731 th
->id
= ltt_eventtype_id(et
);
732 th
->f1
= find_field(et
, field1
);
733 th
->f2
= find_field(et
, field2
);
734 th
->f3
= find_field(et
, field3
);