2 #include <lttv/processTrace.h>
4 #include <ltt/facility.h>
8 void lttv_context_init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
10 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->init(self
, ts
);
14 void lttv_context_fini(LttvTracesetContext
*self
)
16 LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->fini(self
);
21 lttv_context_new_traceset_context(LttvTracesetContext
*self
)
23 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_traceset_context(self
);
30 lttv_context_new_trace_context(LttvTracesetContext
*self
)
32 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
36 LttvTracefileContext
*
37 lttv_context_new_tracefile_context(LttvTracesetContext
*self
)
39 return LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
42 /****************************************************************************
43 * lttv_traceset_context_compute_time_span
45 * Keep the Time_Span is sync with on the fly addition and removal of traces
46 * in a trace set. It must be called each time a trace is added/removed from
47 * the traceset. It could be more efficient to call it only once a bunch
48 * of traces are loaded, but the calculation is not long, so it's not
51 * Author : Xang Xiu Yang
52 * Imported from gtkTraceSet.c by Mathieu Desnoyers
53 ***************************************************************************/
54 static void lttv_traceset_context_compute_time_span(
55 LttvTracesetContext
*self
,
56 TimeInterval
*Time_Span
)
58 LttvTraceset
* traceset
= self
->ts
;
59 int numTraces
= lttv_traceset_number(traceset
);
65 for(i
=0; i
<numTraces
;i
++){
69 ltt_trace_time_span_get(trace
, &s
, &e
);
72 Time_Span
->startTime
= s
;
73 Time_Span
->endTime
= e
;
75 if(s
.tv_sec
< Time_Span
->startTime
.tv_sec
||
76 (s
.tv_sec
== Time_Span
->startTime
.tv_sec
77 && s
.tv_nsec
< Time_Span
->startTime
.tv_nsec
))
78 Time_Span
->startTime
= s
;
79 if(e
.tv_sec
> Time_Span
->endTime
.tv_sec
||
80 (e
.tv_sec
== Time_Span
->endTime
.tv_sec
&&
81 e
.tv_nsec
> Time_Span
->endTime
.tv_nsec
))
82 Time_Span
->endTime
= e
;
89 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
91 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
95 LttvTracefileContext
*tfc
;
97 LttTime null_time
= {0, 0};
99 nb_trace
= lttv_traceset_number(ts
);
101 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
102 self
->before
= lttv_hooks_new();
103 self
->after
= lttv_hooks_new();
104 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
105 self
->ts_a
= lttv_traceset_attribute(ts
);
106 for(i
= 0 ; i
< nb_trace
; i
++) {
107 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
108 self
->traces
[i
] = tc
;
110 tc
->ts_context
= self
;
112 tc
->vt
= lttv_traceset_get(ts
, i
);
113 tc
->t
= lttv_trace(tc
->vt
);
114 tc
->check
= lttv_hooks_new();
115 tc
->before
= lttv_hooks_new();
116 tc
->after
= lttv_hooks_new();
117 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
118 tc
->t_a
= lttv_trace_attribute(tc
->vt
);
119 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
120 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
121 nb_tracefile
= nb_control
+ nb_per_cpu
;
122 tc
->control_tracefiles
= g_new(LttvTracefileContext
*, nb_control
);
123 tc
->per_cpu_tracefiles
= g_new(LttvTracefileContext
*, nb_per_cpu
);
125 for(j
= 0 ; j
< nb_tracefile
; j
++) {
126 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
128 tc
->control_tracefiles
[j
] = tfc
;
131 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
134 tc
->per_cpu_tracefiles
[j
- nb_control
] = tfc
;
135 tfc
->control
= FALSE
;
136 tfc
->index
= j
- nb_control
;
137 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
140 tfc
->check
= lttv_hooks_new();
141 tfc
->before
= lttv_hooks_new();
142 tfc
->after
= lttv_hooks_new();
143 tfc
->check_event
= lttv_hooks_new();
144 tfc
->before_event
= lttv_hooks_new();
145 tfc
->before_event_by_id
= lttv_hooks_by_id_new();
146 tfc
->after_event
= lttv_hooks_new();
147 tfc
->after_event_by_id
= lttv_hooks_by_id_new();
148 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
151 lttv_process_traceset_seek_time(self
, null_time
);
152 /*CHECK why dynamically allocate the time span... and the casing is wroNg*/
153 self
->Time_Span
= g_new(TimeInterval
,1);
154 lttv_traceset_context_compute_time_span(self
, self
->Time_Span
);
158 void fini(LttvTracesetContext
*self
)
160 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
162 LttvTraceContext
*tc
;
164 LttvTracefileContext
*tfc
;
166 LttvTraceset
*ts
= self
->ts
;
168 g_free(self
->Time_Span
);
170 lttv_hooks_destroy(self
->before
);
171 lttv_hooks_destroy(self
->after
);
173 g_object_unref(self
->a
);
175 nb_trace
= lttv_traceset_number(ts
);
177 for(i
= 0 ; i
< nb_trace
; i
++) {
178 tc
= self
->traces
[i
];
180 lttv_hooks_destroy(tc
->check
);
181 lttv_hooks_destroy(tc
->before
);
182 lttv_hooks_destroy(tc
->after
);
183 g_object_unref(tc
->a
);
185 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
186 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
187 nb_tracefile
= nb_control
+ nb_per_cpu
;
189 for(j
= 0 ; j
< nb_tracefile
; j
++) {
190 if(j
< nb_control
) tfc
= tc
->control_tracefiles
[j
];
191 else tfc
= tc
->per_cpu_tracefiles
[j
- nb_control
];
193 lttv_hooks_destroy(tfc
->check
);
194 lttv_hooks_destroy(tfc
->before
);
195 lttv_hooks_destroy(tfc
->after
);
196 lttv_hooks_destroy(tfc
->check_event
);
197 lttv_hooks_destroy(tfc
->before_event
);
198 lttv_hooks_by_id_destroy(tfc
->before_event_by_id
);
199 lttv_hooks_destroy(tfc
->after_event
);
200 lttv_hooks_by_id_destroy(tfc
->after_event_by_id
);
201 g_object_unref(tfc
->a
);
204 g_free(tc
->control_tracefiles
);
205 g_free(tc
->per_cpu_tracefiles
);
208 g_free(self
->traces
);
212 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
213 LttvHooks
*before_traceset
,
214 LttvHooks
*after_traceset
,
215 LttvHooks
*check_trace
,
216 LttvHooks
*before_trace
,
217 LttvHooks
*after_trace
,
218 LttvHooks
*check_tracefile
,
219 LttvHooks
*before_tracefile
,
220 LttvHooks
*after_tracefile
,
221 LttvHooks
*check_event
,
222 LttvHooks
*before_event
,
223 LttvHooks
*after_event
)
225 LttvTraceset
*ts
= self
->ts
;
227 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
229 LttvTraceContext
*tc
;
231 LttvTracefileContext
*tfc
;
235 lttv_hooks_add_list(self
->before
, before_traceset
);
236 lttv_hooks_add_list(self
->after
, after_traceset
);
237 nb_trace
= lttv_traceset_number(ts
);
239 for(i
= 0 ; i
< nb_trace
; i
++) {
240 tc
= self
->traces
[i
];
241 lttv_hooks_add_list(tc
->check
, check_trace
);
242 lttv_hooks_add_list(tc
->before
, before_trace
);
243 lttv_hooks_add_list(tc
->after
, after_trace
);
244 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
245 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
246 nb_tracefile
= nb_control
+ nb_per_cpu
;
248 for(j
= 0 ; j
< nb_tracefile
; j
++) {
250 tfc
= tc
->control_tracefiles
[j
];
253 tfc
= tc
->per_cpu_tracefiles
[j
-nb_control
];
255 lttv_hooks_add_list(tfc
->check
, check_tracefile
);
256 lttv_hooks_add_list(tfc
->before
, before_tracefile
);
257 lttv_hooks_add_list(tfc
->after
, after_tracefile
);
258 lttv_hooks_add_list(tfc
->check_event
, check_event
);
259 lttv_hooks_add_list(tfc
->before_event
, before_event
);
260 lttv_hooks_add_list(tfc
->after_event
, after_event
);
266 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
267 LttvHooks
*before_traceset
,
268 LttvHooks
*after_traceset
,
269 LttvHooks
*check_trace
,
270 LttvHooks
*before_trace
,
271 LttvHooks
*after_trace
,
272 LttvHooks
*check_tracefile
,
273 LttvHooks
*before_tracefile
,
274 LttvHooks
*after_tracefile
,
275 LttvHooks
*check_event
,
276 LttvHooks
*before_event
,
277 LttvHooks
*after_event
)
279 LttvTraceset
*ts
= self
->ts
;
281 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
283 LttvTraceContext
*tc
;
285 LttvTracefileContext
*tfc
;
289 lttv_hooks_remove_list(self
->before
, before_traceset
);
290 lttv_hooks_remove_list(self
->after
, after_traceset
);
291 nb_trace
= lttv_traceset_number(ts
);
293 for(i
= 0 ; i
< nb_trace
; i
++) {
294 tc
= self
->traces
[i
];
295 lttv_hooks_remove_list(tc
->check
, check_trace
);
296 lttv_hooks_remove_list(tc
->before
, before_trace
);
297 lttv_hooks_remove_list(tc
->after
, after_trace
);
298 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
299 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
300 nb_tracefile
= nb_control
+ nb_per_cpu
;
302 for(j
= 0 ; j
< nb_tracefile
; j
++) {
304 tfc
= tc
->control_tracefiles
[j
];
307 tfc
= tc
->per_cpu_tracefiles
[j
-nb_control
];
309 lttv_hooks_remove_list(tfc
->check
, check_tracefile
);
310 lttv_hooks_remove_list(tfc
->before
, before_tracefile
);
311 lttv_hooks_remove_list(tfc
->after
, after_tracefile
);
312 lttv_hooks_remove_list(tfc
->check_event
, check_event
);
313 lttv_hooks_remove_list(tfc
->before_event
, before_event
);
314 lttv_hooks_remove_list(tfc
->after_event
, after_event
);
320 static LttvTracesetContext
*
321 new_traceset_context(LttvTracesetContext
*self
)
323 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
327 static LttvTraceContext
*
328 new_trace_context(LttvTracesetContext
*self
)
330 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
334 static LttvTracefileContext
*
335 new_tracefile_context(LttvTracesetContext
*self
)
337 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
342 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
344 /* Be careful of anything which would not work well with shallow copies */
349 traceset_context_finalize (LttvTracesetContext
*self
)
351 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
352 ->finalize(G_OBJECT(self
));
357 traceset_context_class_init (LttvTracesetContextClass
*klass
)
359 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
361 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
364 klass
->new_traceset_context
= new_traceset_context
;
365 klass
->new_trace_context
= new_trace_context
;
366 klass
->new_tracefile_context
= new_tracefile_context
;
371 lttv_traceset_context_get_type(void)
373 static GType type
= 0;
375 static const GTypeInfo info
= {
376 sizeof (LttvTracesetContextClass
),
377 NULL
, /* base_init */
378 NULL
, /* base_finalize */
379 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
380 NULL
, /* class_finalize */
381 NULL
, /* class_data */
382 sizeof (LttvTracesetContext
),
384 (GInstanceInitFunc
) traceset_context_instance_init
/* instance_init */
387 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
395 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
397 /* Be careful of anything which would not work well with shallow copies */
402 trace_context_finalize (LttvTraceContext
*self
)
404 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
405 finalize(G_OBJECT(self
));
410 trace_context_class_init (LttvTraceContextClass
*klass
)
412 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
414 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
419 lttv_trace_context_get_type(void)
421 static GType type
= 0;
423 static const GTypeInfo info
= {
424 sizeof (LttvTraceContextClass
),
425 NULL
, /* base_init */
426 NULL
, /* base_finalize */
427 (GClassInitFunc
) trace_context_class_init
, /* class_init */
428 NULL
, /* class_finalize */
429 NULL
, /* class_data */
430 sizeof (LttvTraceContext
),
432 (GInstanceInitFunc
) trace_context_instance_init
/* instance_init */
435 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
443 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
445 /* Be careful of anything which would not work well with shallow copies */
450 tracefile_context_finalize (LttvTracefileContext
*self
)
452 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
453 ->finalize(G_OBJECT(self
));
458 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
460 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
462 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
467 lttv_tracefile_context_get_type(void)
469 static GType type
= 0;
471 static const GTypeInfo info
= {
472 sizeof (LttvTracefileContextClass
),
473 NULL
, /* base_init */
474 NULL
, /* base_finalize */
475 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
476 NULL
, /* class_finalize */
477 NULL
, /* class_data */
478 sizeof (LttvTracefileContext
),
480 (GInstanceInitFunc
) tracefile_context_instance_init
/* instance_init */
483 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
490 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
492 return ltt_time_compare(*((LttTime
*)a
), *((LttTime
*)b
));
496 gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
497 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
502 void lttv_process_traceset(LttvTracesetContext
*self
, LttTime end
,
503 unsigned maxNumEvents
)
505 GPtrArray
*traces
= g_ptr_array_new();
507 GPtrArray
*tracefiles
= g_ptr_array_new();
509 GTree
*pqueue
= g_tree_new(compare_tracefile
);
511 guint i
, j
, nbi
, nbj
, id
, nb_control
, nb_cpu
;
515 LttvTraceContext
*tc
;
517 LttTracefile
*tracefile
;
519 LttvTracefileContext
*tfc
;
525 LttTime previous_timestamp
= {0, 0};
527 /* Call all before_traceset, before_trace, and before_tracefile hooks.
528 For all qualifying tracefiles, seek to the start time, create a context,
529 read one event and insert in the pqueue based on the event time. */
531 lttv_hooks_call(self
->before
, self
);
532 nbi
= lttv_traceset_number(self
->ts
);
534 for(i
= 0 ; i
< nbi
; i
++) {
535 tc
= self
->traces
[i
];
538 if(!lttv_hooks_call_check(tc
->check
, tc
)) {
539 g_ptr_array_add(traces
, tc
);
540 lttv_hooks_call(tc
->before
, tc
);
541 nb_control
= ltt_trace_control_tracefile_number(trace
);
542 nb_cpu
= ltt_trace_per_cpu_tracefile_number(trace
);
543 nbj
= nb_control
+ nb_cpu
;
545 for(j
= 0 ; j
< nbj
; j
++) {
547 tfc
= tc
->control_tracefiles
[j
];
550 tfc
= tc
->per_cpu_tracefiles
[j
- nb_control
];
555 if(!lttv_hooks_call_check(tfc
->check
, tfc
)) {
556 g_ptr_array_add(tracefiles
, tfc
);
557 lttv_hooks_call(tfc
->before
, tfc
);
560 g_tree_insert(pqueue
, &(tfc
->timestamp
), tfc
);
567 /* Get the next event from the pqueue, call its hooks,
568 reinsert in the pqueue the following event from the same tracefile
569 unless the tracefile is finished or the event is later than the
574 g_tree_foreach(pqueue
, get_first
, &tfc
);
575 if(tfc
== NULL
) break;
577 /* Have we reached the maximum number of events specified? However,
578 continue for all the events with the same time stamp (CHECK?). Then,
579 empty the queue and break from the loop. */
582 if(count
> maxNumEvents
){
583 if(tfc
->timestamp
.tv_sec
== previous_timestamp
.tv_sec
&&
584 tfc
->timestamp
.tv_nsec
== previous_timestamp
.tv_nsec
) {
589 g_tree_foreach(pqueue
, get_first
, &tfc
);
590 if(tfc
== NULL
) break;
591 g_tree_remove(pqueue
, &(tfc
->timestamp
));
596 previous_timestamp
= tfc
->timestamp
;
599 /* Get the tracefile with an event for the smallest time found. If two
600 or more tracefiles have events for the same time, hope that lookup
601 and remove are consistent. */
603 tfc
= g_tree_lookup(pqueue
, &(tfc
->timestamp
));
604 g_tree_remove(pqueue
, &(tfc
->timestamp
));
606 if(!lttv_hooks_call(tfc
->check_event
, tfc
)) {
607 id
= ltt_event_eventtype_id(tfc
->e
);
608 lttv_hooks_call(tfc
->before_event
, tfc
);
609 lttv_hooks_call(lttv_hooks_by_id_get(tfc
->before_event_by_id
, id
), tfc
);
610 lttv_hooks_call(tfc
->after_event
, tfc
);
611 lttv_hooks_call(lttv_hooks_by_id_get(tfc
->after_event_by_id
, id
), tfc
);
614 event
= ltt_tracefile_read(tfc
->tf
);
617 tfc
->timestamp
= ltt_event_time(event
);
618 if(tfc
->timestamp
.tv_sec
< end
.tv_sec
||
619 (tfc
->timestamp
.tv_sec
== end
.tv_sec
&& tfc
->timestamp
.tv_nsec
<= end
.tv_nsec
))
620 g_tree_insert(pqueue
, &(tfc
->timestamp
), tfc
);
624 /* Call all the after_tracefile, after_trace and after_traceset hooks. */
626 for(i
= 0, j
= 0 ; i
< traces
->len
; i
++) {
627 tc
= traces
->pdata
[i
];
628 while(j
< tracefiles
->len
) {
629 tfc
= tracefiles
->pdata
[j
];
631 if(tfc
->t_context
== tc
) {
632 lttv_hooks_call(tfc
->after
, tfc
);
637 lttv_hooks_call(tc
->after
, tc
);
640 g_assert(j
== tracefiles
->len
);
641 lttv_hooks_call(self
->after
, self
);
643 /* Free the traces, tracefiles and pqueue */
645 g_ptr_array_free(tracefiles
, TRUE
);
646 g_ptr_array_free(traces
, TRUE
);
647 g_tree_destroy(pqueue
);
651 void lttv_process_trace_seek_time(LttvTraceContext
*self
, LttTime start
)
653 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
655 LttvTracefileContext
*tfc
;
659 nb_control
= ltt_trace_control_tracefile_number(self
->t
);
660 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->t
);
661 nb_tracefile
= nb_control
+ nb_per_cpu
;
662 for(i
= 0 ; i
< nb_tracefile
; i
++) {
663 if(i
< nb_control
) tfc
= self
->control_tracefiles
[i
];
664 else tfc
= self
->per_cpu_tracefiles
[i
- nb_control
];
666 ltt_tracefile_seek_time(tfc
->tf
, start
);
667 event
= ltt_tracefile_read(tfc
->tf
);
669 if(event
!= NULL
) tfc
->timestamp
= ltt_event_time(event
);
674 void lttv_process_traceset_seek_time(LttvTracesetContext
*self
, LttTime start
)
678 LttvTraceContext
*tc
;
680 nb_trace
= lttv_traceset_number(self
->ts
);
681 for(i
= 0 ; i
< nb_trace
; i
++) {
682 tc
= self
->traces
[i
];
683 lttv_process_trace_seek_time(tc
, start
);
689 find_field(LttEventType
*et
, const char *field
)
699 if(field
== NULL
) return NULL
;
701 f
= ltt_eventtype_field(et
);
702 t
= ltt_eventtype_type(et
);
703 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
704 nb
= ltt_type_member_number(t
);
705 for(i
= 0 ; i
< nb
; i
++) {
706 ltt_type_member_type(t
, i
, &name
);
707 if(strcmp(name
, field
) == 0) break;
710 return ltt_field_member(f
, i
);
715 lttv_trace_find_hook(LttTrace
*t
, char *facility
, char *event_type
,
716 char *field1
, char *field2
, char *field3
, LttvHook h
, LttvTraceHook
*th
)
726 nb
= ltt_trace_facility_find(t
, facility
, &pos
);
727 if(nb
< 1) g_error("No %s facility", facility
);
728 f
= ltt_trace_facility_get(t
, pos
);
729 et
= ltt_facility_eventtype_get_by_name(f
, event_type
);
730 if(et
== NULL
) g_error("Event %s does not exist", event_type
);
733 th
->id
= ltt_eventtype_id(et
);
734 th
->f1
= find_field(et
, field1
);
735 th
->f2
= find_field(et
, field2
);
736 th
->f3
= find_field(et
, field3
);