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 nb_trace
= lttv_traceset_number(ts
);
97 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
98 self
->before
= lttv_hooks_new();
99 self
->after
= lttv_hooks_new();
100 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
101 for(i
= 0 ; i
< nb_trace
; i
++) {
102 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
103 self
->traces
[i
] = tc
;
105 tc
->ts_context
= self
;
107 tc
->t
= lttv_traceset_get(ts
, i
);
108 tc
->check
= lttv_hooks_new();
109 tc
->before
= lttv_hooks_new();
110 tc
->after
= lttv_hooks_new();
111 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
112 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
113 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
114 nb_tracefile
= nb_control
+ nb_per_cpu
;
115 tc
->control_tracefiles
= g_new(LttvTracefileContext
*, nb_control
);
116 tc
->per_cpu_tracefiles
= g_new(LttvTracefileContext
*, nb_per_cpu
);
118 for(j
= 0 ; j
< nb_tracefile
; j
++) {
119 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
121 tc
->control_tracefiles
[j
] = tfc
;
124 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
127 tc
->per_cpu_tracefiles
[j
- nb_control
] = tfc
;
128 tfc
->control
= FALSE
;
129 tfc
->index
= j
- nb_control
;
130 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
133 tfc
->check
= lttv_hooks_new();
134 tfc
->before
= lttv_hooks_new();
135 tfc
->after
= lttv_hooks_new();
136 tfc
->check_event
= lttv_hooks_new();
137 tfc
->before_event
= lttv_hooks_new();
138 tfc
->before_event_by_id
= lttv_hooks_by_id_new();
139 tfc
->after_event
= lttv_hooks_new();
140 tfc
->after_event_by_id
= lttv_hooks_by_id_new();
141 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
144 self
->Time_Span
= g_new(TimeInterval
,1);
145 lttv_traceset_context_compute_time_span(self
, self
->Time_Span
);
149 void fini(LttvTracesetContext
*self
)
151 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
153 LttvTraceContext
*tc
;
155 LttvTracefileContext
*tfc
;
157 LttvTraceset
*ts
= self
->ts
;
159 g_free(self
->Time_Span
);
161 lttv_hooks_destroy(self
->before
);
162 lttv_hooks_destroy(self
->after
);
164 // g_object_unref(self->a);
166 nb_trace
= lttv_traceset_number(ts
);
168 for(i
= 0 ; i
< nb_trace
; i
++) {
169 tc
= self
->traces
[i
];
171 lttv_hooks_destroy(tc
->check
);
172 lttv_hooks_destroy(tc
->before
);
173 lttv_hooks_destroy(tc
->after
);
174 g_object_unref(tc
->a
);
176 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
177 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
178 nb_tracefile
= nb_control
+ nb_per_cpu
;
180 for(j
= 0 ; j
< nb_tracefile
; j
++) {
181 if(j
< nb_control
) tfc
= tc
->control_tracefiles
[j
];
182 else tfc
= tc
->per_cpu_tracefiles
[j
- nb_control
];
184 lttv_hooks_destroy(tfc
->check
);
185 lttv_hooks_destroy(tfc
->before
);
186 lttv_hooks_destroy(tfc
->after
);
187 lttv_hooks_destroy(tfc
->check_event
);
188 lttv_hooks_destroy(tfc
->before_event
);
189 lttv_hooks_by_id_destroy(tfc
->before_event_by_id
);
190 lttv_hooks_destroy(tfc
->after_event
);
191 lttv_hooks_by_id_destroy(tfc
->after_event_by_id
);
192 g_object_unref(tfc
->a
);
195 g_free(tc
->control_tracefiles
);
196 g_free(tc
->per_cpu_tracefiles
);
199 g_free(self
->traces
);
203 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
204 LttvHooks
*before_traceset
,
205 LttvHooks
*after_traceset
,
206 LttvHooks
*check_trace
,
207 LttvHooks
*before_trace
,
208 LttvHooks
*after_trace
,
209 LttvHooks
*check_tracefile
,
210 LttvHooks
*before_tracefile
,
211 LttvHooks
*after_tracefile
,
212 LttvHooks
*check_event
,
213 LttvHooks
*before_event
,
214 LttvHooks
*after_event
)
216 LttvTraceset
*ts
= self
->ts
;
218 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
220 LttvTraceContext
*tc
;
222 LttvTracefileContext
*tfc
;
226 lttv_hooks_add_list(self
->before
, before_traceset
);
227 lttv_hooks_add_list(self
->after
, after_traceset
);
228 nb_trace
= lttv_traceset_number(ts
);
230 for(i
= 0 ; i
< nb_trace
; i
++) {
231 tc
= self
->traces
[i
];
232 lttv_hooks_add_list(tc
->check
, check_trace
);
233 lttv_hooks_add_list(tc
->before
, before_trace
);
234 lttv_hooks_add_list(tc
->after
, after_trace
);
235 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
236 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
237 nb_tracefile
= nb_control
+ nb_per_cpu
;
239 for(j
= 0 ; j
< nb_tracefile
; j
++) {
241 tfc
= tc
->control_tracefiles
[j
];
244 tfc
= tc
->per_cpu_tracefiles
[j
-nb_control
];
246 lttv_hooks_add_list(tfc
->check
, check_tracefile
);
247 lttv_hooks_add_list(tfc
->before
, before_tracefile
);
248 lttv_hooks_add_list(tfc
->after
, after_tracefile
);
249 lttv_hooks_add_list(tfc
->check_event
, check_event
);
250 lttv_hooks_add_list(tfc
->before_event
, before_event
);
251 lttv_hooks_add_list(tfc
->after_event
, after_event
);
257 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
258 LttvHooks
*before_traceset
,
259 LttvHooks
*after_traceset
,
260 LttvHooks
*check_trace
,
261 LttvHooks
*before_trace
,
262 LttvHooks
*after_trace
,
263 LttvHooks
*check_tracefile
,
264 LttvHooks
*before_tracefile
,
265 LttvHooks
*after_tracefile
,
266 LttvHooks
*check_event
,
267 LttvHooks
*before_event
,
268 LttvHooks
*after_event
)
270 LttvTraceset
*ts
= self
->ts
;
272 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
274 LttvTraceContext
*tc
;
276 LttvTracefileContext
*tfc
;
280 lttv_hooks_remove_list(self
->before
, before_traceset
);
281 lttv_hooks_remove_list(self
->after
, after_traceset
);
282 nb_trace
= lttv_traceset_number(ts
);
284 for(i
= 0 ; i
< nb_trace
; i
++) {
285 tc
= self
->traces
[i
];
286 lttv_hooks_remove_list(tc
->check
, check_trace
);
287 lttv_hooks_remove_list(tc
->before
, before_trace
);
288 lttv_hooks_remove_list(tc
->after
, after_trace
);
289 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
290 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
291 nb_tracefile
= nb_control
+ nb_per_cpu
;
293 for(j
= 0 ; j
< nb_tracefile
; j
++) {
295 tfc
= tc
->control_tracefiles
[j
];
298 tfc
= tc
->per_cpu_tracefiles
[j
-nb_control
];
300 lttv_hooks_remove_list(tfc
->check
, check_tracefile
);
301 lttv_hooks_remove_list(tfc
->before
, before_tracefile
);
302 lttv_hooks_remove_list(tfc
->after
, after_tracefile
);
303 lttv_hooks_remove_list(tfc
->check_event
, check_event
);
304 lttv_hooks_remove_list(tfc
->before_event
, before_event
);
305 lttv_hooks_remove_list(tfc
->after_event
, after_event
);
311 static LttvTracesetContext
*
312 new_traceset_context(LttvTracesetContext
*self
)
314 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
318 static LttvTraceContext
*
319 new_trace_context(LttvTracesetContext
*self
)
321 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
325 static LttvTracefileContext
*
326 new_tracefile_context(LttvTracesetContext
*self
)
328 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
333 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
335 /* Be careful of anything which would not work well with shallow copies */
340 traceset_context_finalize (LttvTracesetContext
*self
)
342 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
343 ->finalize(G_OBJECT(self
));
348 traceset_context_class_init (LttvTracesetContextClass
*klass
)
350 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
352 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
355 klass
->new_traceset_context
= new_traceset_context
;
356 klass
->new_trace_context
= new_trace_context
;
357 klass
->new_tracefile_context
= new_tracefile_context
;
362 lttv_traceset_context_get_type(void)
364 static GType type
= 0;
366 static const GTypeInfo info
= {
367 sizeof (LttvTracesetContextClass
),
368 NULL
, /* base_init */
369 NULL
, /* base_finalize */
370 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
371 NULL
, /* class_finalize */
372 NULL
, /* class_data */
373 sizeof (LttvTracesetContext
),
375 (GInstanceInitFunc
) traceset_context_instance_init
/* instance_init */
378 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
386 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
388 /* Be careful of anything which would not work well with shallow copies */
393 trace_context_finalize (LttvTraceContext
*self
)
395 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
396 finalize(G_OBJECT(self
));
401 trace_context_class_init (LttvTraceContextClass
*klass
)
403 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
405 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
410 lttv_trace_context_get_type(void)
412 static GType type
= 0;
414 static const GTypeInfo info
= {
415 sizeof (LttvTraceContextClass
),
416 NULL
, /* base_init */
417 NULL
, /* base_finalize */
418 (GClassInitFunc
) trace_context_class_init
, /* class_init */
419 NULL
, /* class_finalize */
420 NULL
, /* class_data */
421 sizeof (LttvTraceContext
),
423 (GInstanceInitFunc
) trace_context_instance_init
/* instance_init */
426 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
434 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
436 /* Be careful of anything which would not work well with shallow copies */
441 tracefile_context_finalize (LttvTracefileContext
*self
)
443 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
444 ->finalize(G_OBJECT(self
));
449 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
451 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
453 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
458 lttv_tracefile_context_get_type(void)
460 static GType type
= 0;
462 static const GTypeInfo info
= {
463 sizeof (LttvTracefileContextClass
),
464 NULL
, /* base_init */
465 NULL
, /* base_finalize */
466 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
467 NULL
, /* class_finalize */
468 NULL
, /* class_data */
469 sizeof (LttvTracefileContext
),
471 (GInstanceInitFunc
) tracefile_context_instance_init
/* instance_init */
474 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
481 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
483 if(((LttvTime
*)a
)->tv_sec
> ((LttvTime
*)b
)->tv_sec
) return 1;
484 if(((LttvTime
*)a
)->tv_sec
< ((LttvTime
*)b
)->tv_sec
) return -1;
485 if(((LttvTime
*)a
)->tv_nsec
> ((LttvTime
*)b
)->tv_nsec
) return 1;
486 if(((LttvTime
*)a
)->tv_nsec
< ((LttvTime
*)b
)->tv_nsec
) return -1;
491 gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
492 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
497 void lttv_process_trace(LttTime start
, LttTime end
, LttvTraceset
*traceset
,
498 LttvTracesetContext
*context
, unsigned maxNumEvents
)
500 GPtrArray
*traces
= g_ptr_array_new();
502 GPtrArray
*tracefiles
= g_ptr_array_new();
504 GTree
*pqueue
= g_tree_new(compare_tracefile
);
506 guint i
, j
, nbi
, nbj
, id
, nb_control
, nb_cpu
;
510 LttvTraceContext
*tc
;
512 LttTracefile
*tracefile
;
514 LttvTracefileContext
*tfc
;
518 LttTime preTimestamp
;
520 /* Call all before_traceset, before_trace, and before_tracefile hooks.
521 For all qualifying tracefiles, seek to the start time, create a context,
522 read one event and insert in the pqueue based on the event time. */
524 lttv_hooks_call(context
->before
, context
);
525 nbi
= lttv_traceset_number(traceset
);
526 // nbi = ltt_trace_set_number(traceset);
528 for(i
= 0 ; i
< nbi
; i
++) {
529 tc
= context
->traces
[i
];
532 if(!lttv_hooks_call_check(tc
->check
, tc
)) {
533 g_ptr_array_add(traces
, tc
);
534 lttv_hooks_call(tc
->before
, tc
);
535 nb_control
= ltt_trace_control_tracefile_number(trace
);
536 nb_cpu
= ltt_trace_per_cpu_tracefile_number(trace
);
537 nbj
= nb_control
+ nb_cpu
;
539 for(j
= 0 ; j
< nbj
; j
++) {
541 tfc
= tc
->control_tracefiles
[j
];
544 tfc
= tc
->per_cpu_tracefiles
[j
- nb_control
];
549 if(!lttv_hooks_call_check(tfc
->check
, tfc
)) {
550 g_ptr_array_add(tracefiles
, tfc
);
551 lttv_hooks_call(tfc
->before
, tfc
);
553 ltt_tracefile_seek_time(tracefile
, start
);
554 event
= ltt_tracefile_read(tracefile
);
558 tfc
->timestamp
= ltt_event_time(event
);
559 g_tree_insert(pqueue
, &(tfc
->timestamp
), tfc
);
566 /* Get the next event from the pqueue, call its hooks,
567 reinsert in the pqueue the following event from the same tracefile
568 unless the tracefile is finished or the event is later than the
573 g_tree_foreach(pqueue
, get_first
, &tfc
);
574 if(tfc
== NULL
) break;
576 /* Get the tracefile with an event for the smallest time found. If two
577 or more tracefiles have events for the same time, hope that lookup
578 and remove are consistent. */
581 if(count
> maxNumEvents
){
582 if(tfc
->timestamp
.tv_sec
== preTimestamp
.tv_sec
&&
583 tfc
->timestamp
.tv_nsec
== preTimestamp
.tv_nsec
) {
588 g_tree_foreach(pqueue
, get_first
, &tfc
);
589 if(tfc
== NULL
) break;
590 g_tree_remove(pqueue
, &(tfc
->timestamp
));
595 preTimestamp
= tfc
->timestamp
;
597 tfc
= g_tree_lookup(pqueue
, &(tfc
->timestamp
));
598 g_tree_remove(pqueue
, &(tfc
->timestamp
));
600 if(!lttv_hooks_call(tfc
->check_event
, tfc
)) {
601 id
= ltt_event_eventtype_id(tfc
->e
);
602 lttv_hooks_call(tfc
->before_event
, tfc
);
603 lttv_hooks_call(lttv_hooks_by_id_get(tfc
->before_event_by_id
, id
), tfc
);
604 lttv_hooks_call(tfc
->after_event
, tfc
);
605 lttv_hooks_call(lttv_hooks_by_id_get(tfc
->after_event_by_id
, id
), tfc
);
608 event
= ltt_tracefile_read(tfc
->tf
);
611 tfc
->timestamp
= ltt_event_time(event
);
612 if(tfc
->timestamp
.tv_sec
< end
.tv_sec
||
613 (tfc
->timestamp
.tv_sec
== end
.tv_sec
&& tfc
->timestamp
.tv_nsec
<= end
.tv_nsec
))
614 g_tree_insert(pqueue
, &(tfc
->timestamp
), tfc
);
618 /* Call all the after_tracefile, after_trace and after_traceset hooks. */
620 for(i
= 0, j
= 0 ; i
< traces
->len
; i
++) {
621 tc
= traces
->pdata
[i
];
622 while(j
< tracefiles
->len
) {
623 tfc
= tracefiles
->pdata
[j
];
625 if(tfc
->t_context
== tc
) {
626 lttv_hooks_call(tfc
->after
, tfc
);
631 lttv_hooks_call(tc
->after
, tc
);
634 g_assert(j
== tracefiles
->len
);
635 lttv_hooks_call(context
->after
, context
);
637 /* Free the traces, tracefiles and pqueue */
639 g_ptr_array_free(tracefiles
, TRUE
);
640 g_ptr_array_free(traces
, TRUE
);
641 g_tree_destroy(pqueue
);
645 find_field(LttEventType
*et
, const char *field
)
655 if(field
== NULL
) return NULL
;
657 f
= ltt_eventtype_field(et
);
658 t
= ltt_eventtype_type(et
);
659 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
660 nb
= ltt_type_member_number(t
);
661 for(i
= 0 ; i
< nb
; i
++) {
662 ltt_type_member_type(t
, i
, &name
);
663 if(strcmp(name
, field
) == 0) break;
666 return ltt_field_member(f
, i
);
671 lttv_trace_find_hook(LttTrace
*t
, char *facility
, char *event_type
,
672 char *field1
, char *field2
, char *field3
, LttvHook h
, LttvTraceHook
*th
)
682 nb
= ltt_trace_facility_find(t
, facility
, &pos
);
683 if(nb
< 1) g_error("No %s facility", facility
);
684 f
= ltt_trace_facility_get(t
, pos
);
685 et
= ltt_facility_eventtype_get_by_name(f
, event_type
);
686 if(et
== NULL
) g_error("Event %s does not exist", event_type
);
689 th
->id
= ltt_eventtype_id(et
);
690 th
->f1
= find_field(et
, field1
);
691 th
->f2
= find_field(et
, field2
);
692 th
->f3
= find_field(et
, field3
);