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
);
42 init(LttvTracesetContext
*self
, LttvTraceset
*ts
)
44 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
48 LttvTracefileContext
*tfc
;
50 nb_trace
= lttv_traceset_number(ts
);
52 self
->traces
= g_new(LttvTraceContext
*, nb_trace
);
53 self
->before
= lttv_hooks_new();
54 self
->after
= lttv_hooks_new();
55 self
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
56 for(i
= 0 ; i
< nb_trace
; i
++) {
57 tc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_trace_context(self
);
60 tc
->ts_context
= self
;
62 tc
->t
= lttv_traceset_get(ts
, i
);
63 tc
->check
= lttv_hooks_new();
64 tc
->before
= lttv_hooks_new();
65 tc
->after
= lttv_hooks_new();
66 tc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
67 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
68 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
69 nb_tracefile
= nb_control
+ nb_per_cpu
;
70 tc
->control_tracefiles
= g_new(LttvTracefileContext
*, nb_control
);
71 tc
->per_cpu_tracefiles
= g_new(LttvTracefileContext
*, nb_per_cpu
);
73 for(j
= 0 ; j
< nb_tracefile
; j
++) {
74 tfc
= LTTV_TRACESET_CONTEXT_GET_CLASS(self
)->new_tracefile_context(self
);
76 tc
->control_tracefiles
[j
] = tfc
;
79 tfc
->tf
= ltt_trace_control_tracefile_get(tc
->t
, j
);
82 tc
->per_cpu_tracefiles
[j
- nb_control
] = tfc
;
84 tfc
->index
= j
- nb_control
;
85 tfc
->tf
= ltt_trace_per_cpu_tracefile_get(tc
->t
, j
- nb_control
);
88 tfc
->check
= lttv_hooks_new();
89 tfc
->before
= lttv_hooks_new();
90 tfc
->after
= lttv_hooks_new();
91 tfc
->check_event
= lttv_hooks_new();
92 tfc
->before_event
= lttv_hooks_new();
93 tfc
->before_event_by_id
= lttv_hooks_by_id_new();
94 tfc
->after_event
= lttv_hooks_new();
95 tfc
->after_event_by_id
= lttv_hooks_by_id_new();
96 tfc
->a
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
102 void fini(LttvTracesetContext
*self
)
104 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
106 LttvTraceContext
*tc
;
108 LttvTracefileContext
*tfc
;
110 LttvTraceset
*ts
= self
->ts
;
112 lttv_hooks_destroy(self
->before
);
113 lttv_hooks_destroy(self
->after
);
114 g_object_unref(self
->a
);
116 nb_trace
= lttv_traceset_number(ts
);
118 for(i
= 0 ; i
< nb_trace
; i
++) {
119 tc
= self
->traces
[i
];
121 lttv_hooks_destroy(tc
->check
);
122 lttv_hooks_destroy(tc
->before
);
123 lttv_hooks_destroy(tc
->after
);
124 g_object_unref(tc
->a
);
126 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
127 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
128 nb_tracefile
= nb_control
+ nb_per_cpu
;
130 for(j
= 0 ; j
< nb_tracefile
; j
++) {
131 if(j
< nb_control
) tfc
= tc
->control_tracefiles
[j
];
132 else tfc
= tc
->per_cpu_tracefiles
[j
- nb_control
];
134 lttv_hooks_destroy(tfc
->check
);
135 lttv_hooks_destroy(tfc
->before
);
136 lttv_hooks_destroy(tfc
->after
);
137 lttv_hooks_destroy(tfc
->check_event
);
138 lttv_hooks_destroy(tfc
->before_event
);
139 lttv_hooks_by_id_destroy(tfc
->before_event_by_id
);
140 lttv_hooks_destroy(tfc
->after_event
);
141 lttv_hooks_by_id_destroy(tfc
->after_event_by_id
);
142 g_object_unref(tfc
->a
);
145 g_free(tc
->control_tracefiles
);
146 g_free(tc
->per_cpu_tracefiles
);
149 g_free(self
->traces
);
153 void lttv_traceset_context_add_hooks(LttvTracesetContext
*self
,
154 LttvHooks
*before_traceset
,
155 LttvHooks
*after_traceset
,
156 LttvHooks
*check_trace
,
157 LttvHooks
*before_trace
,
158 LttvHooks
*after_trace
,
159 LttvHooks
*check_tracefile
,
160 LttvHooks
*before_tracefile
,
161 LttvHooks
*after_tracefile
,
162 LttvHooks
*check_event
,
163 LttvHooks
*before_event
,
164 LttvHooks
*after_event
)
166 LttvTraceset
*ts
= self
->ts
;
168 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
170 LttvTraceContext
*tc
;
172 LttvTracefileContext
*tfc
;
176 lttv_hooks_add_list(self
->before
, before_traceset
);
177 lttv_hooks_add_list(self
->after
, after_traceset
);
178 nb_trace
= lttv_traceset_number(ts
);
180 for(i
= 0 ; i
< nb_trace
; i
++) {
181 tc
= self
->traces
[i
];
182 lttv_hooks_add_list(tc
->check
, check_trace
);
183 lttv_hooks_add_list(tc
->before
, before_trace
);
184 lttv_hooks_add_list(tc
->after
, after_trace
);
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
++) {
191 tfc
= tc
->control_tracefiles
[j
];
194 tfc
= tc
->per_cpu_tracefiles
[j
-nb_control
];
196 lttv_hooks_add_list(tfc
->check
, check_tracefile
);
197 lttv_hooks_add_list(tfc
->before
, before_tracefile
);
198 lttv_hooks_add_list(tfc
->after
, after_tracefile
);
199 lttv_hooks_add_list(tfc
->check_event
, check_event
);
200 lttv_hooks_add_list(tfc
->before_event
, before_event
);
201 lttv_hooks_add_list(tfc
->after_event
, after_event
);
207 void lttv_traceset_context_remove_hooks(LttvTracesetContext
*self
,
208 LttvHooks
*before_traceset
,
209 LttvHooks
*after_traceset
,
210 LttvHooks
*check_trace
,
211 LttvHooks
*before_trace
,
212 LttvHooks
*after_trace
,
213 LttvHooks
*check_tracefile
,
214 LttvHooks
*before_tracefile
,
215 LttvHooks
*after_tracefile
,
216 LttvHooks
*check_event
,
217 LttvHooks
*before_event
,
218 LttvHooks
*after_event
)
220 LttvTraceset
*ts
= self
->ts
;
222 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
224 LttvTraceContext
*tc
;
226 LttvTracefileContext
*tfc
;
230 lttv_hooks_remove_list(self
->before
, before_traceset
);
231 lttv_hooks_remove_list(self
->after
, after_traceset
);
232 nb_trace
= lttv_traceset_number(ts
);
234 for(i
= 0 ; i
< nb_trace
; i
++) {
235 tc
= self
->traces
[i
];
236 lttv_hooks_remove_list(tc
->check
, check_trace
);
237 lttv_hooks_remove_list(tc
->before
, before_trace
);
238 lttv_hooks_remove_list(tc
->after
, after_trace
);
239 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
240 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
241 nb_tracefile
= nb_control
+ nb_per_cpu
;
243 for(j
= 0 ; j
< nb_tracefile
; j
++) {
245 tfc
= tc
->control_tracefiles
[j
];
248 tfc
= tc
->per_cpu_tracefiles
[j
-nb_control
];
250 lttv_hooks_remove_list(tfc
->check
, check_tracefile
);
251 lttv_hooks_remove_list(tfc
->before
, before_tracefile
);
252 lttv_hooks_remove_list(tfc
->after
, after_tracefile
);
253 lttv_hooks_remove_list(tfc
->check_event
, check_event
);
254 lttv_hooks_remove_list(tfc
->before_event
, before_event
);
255 lttv_hooks_remove_list(tfc
->after_event
, after_event
);
261 static LttvTracesetContext
*
262 new_traceset_context(LttvTracesetContext
*self
)
264 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE
, NULL
);
268 static LttvTraceContext
*
269 new_trace_context(LttvTracesetContext
*self
)
271 return g_object_new(LTTV_TRACE_CONTEXT_TYPE
, NULL
);
275 static LttvTracefileContext
*
276 new_tracefile_context(LttvTracesetContext
*self
)
278 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE
, NULL
);
283 traceset_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
285 /* Be careful of anything which would not work well with shallow copies */
290 traceset_context_finalize (LttvTracesetContext
*self
)
292 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE
)))
293 ->finalize(G_OBJECT(self
));
298 traceset_context_class_init (LttvTracesetContextClass
*klass
)
300 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
302 gobject_class
->finalize
= (void (*)(GObject
*self
))traceset_context_finalize
;
305 klass
->new_traceset_context
= new_traceset_context
;
306 klass
->new_trace_context
= new_trace_context
;
307 klass
->new_tracefile_context
= new_tracefile_context
;
312 lttv_traceset_context_get_type(void)
314 static GType type
= 0;
316 static const GTypeInfo info
= {
317 sizeof (LttvTracesetContextClass
),
318 NULL
, /* base_init */
319 NULL
, /* base_finalize */
320 (GClassInitFunc
) traceset_context_class_init
, /* class_init */
321 NULL
, /* class_finalize */
322 NULL
, /* class_data */
323 sizeof (LttvTracesetContext
),
325 (GInstanceInitFunc
) traceset_context_instance_init
/* instance_init */
328 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracesetContextType",
336 trace_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
338 /* Be careful of anything which would not work well with shallow copies */
343 trace_context_finalize (LttvTraceContext
*self
)
345 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE
)))->
346 finalize(G_OBJECT(self
));
351 trace_context_class_init (LttvTraceContextClass
*klass
)
353 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
355 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_context_finalize
;
360 lttv_trace_context_get_type(void)
362 static GType type
= 0;
364 static const GTypeInfo info
= {
365 sizeof (LttvTraceContextClass
),
366 NULL
, /* base_init */
367 NULL
, /* base_finalize */
368 (GClassInitFunc
) trace_context_class_init
, /* class_init */
369 NULL
, /* class_finalize */
370 NULL
, /* class_data */
371 sizeof (LttvTraceContext
),
373 (GInstanceInitFunc
) trace_context_instance_init
/* instance_init */
376 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTraceContextType",
384 tracefile_context_instance_init (GTypeInstance
*instance
, gpointer g_class
)
386 /* Be careful of anything which would not work well with shallow copies */
391 tracefile_context_finalize (LttvTracefileContext
*self
)
393 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE
)))
394 ->finalize(G_OBJECT(self
));
399 tracefile_context_class_init (LttvTracefileContextClass
*klass
)
401 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
403 gobject_class
->finalize
= (void (*)(GObject
*self
))tracefile_context_finalize
;
408 lttv_tracefile_context_get_type(void)
410 static GType type
= 0;
412 static const GTypeInfo info
= {
413 sizeof (LttvTracefileContextClass
),
414 NULL
, /* base_init */
415 NULL
, /* base_finalize */
416 (GClassInitFunc
) tracefile_context_class_init
, /* class_init */
417 NULL
, /* class_finalize */
418 NULL
, /* class_data */
419 sizeof (LttvTracefileContext
),
421 (GInstanceInitFunc
) tracefile_context_instance_init
/* instance_init */
424 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvTracefileContextType",
431 gint
compare_tracefile(gconstpointer a
, gconstpointer b
)
433 if(((LttvTime
*)a
)->tv_sec
> ((LttvTime
*)b
)->tv_sec
) return 1;
434 if(((LttvTime
*)a
)->tv_sec
< ((LttvTime
*)b
)->tv_sec
) return -1;
435 if(((LttvTime
*)a
)->tv_nsec
> ((LttvTime
*)b
)->tv_nsec
) return 1;
436 if(((LttvTime
*)a
)->tv_nsec
< ((LttvTime
*)b
)->tv_nsec
) return -1;
441 gboolean
get_first(gpointer key
, gpointer value
, gpointer user_data
) {
442 *((LttvTracefileContext
**)user_data
) = (LttvTracefileContext
*)value
;
447 void lttv_process_trace(LttTime start
, LttTime end
, LttvTraceset
*traceset
,
448 LttvTracesetContext
*context
, unsigned maxNumEvents
)
450 GPtrArray
*traces
= g_ptr_array_new();
452 GPtrArray
*tracefiles
= g_ptr_array_new();
454 GTree
*pqueue
= g_tree_new(compare_tracefile
);
456 guint i
, j
, nbi
, nbj
, id
, nb_control
, nb_cpu
;
460 LttvTraceContext
*tc
;
462 LttTracefile
*tracefile
;
464 LttvTracefileContext
*tfc
;
468 LttTime preTimestamp
;
470 /* Call all before_traceset, before_trace, and before_tracefile hooks.
471 For all qualifying tracefiles, seek to the start time, create a context,
472 read one event and insert in the pqueue based on the event time. */
474 lttv_hooks_call(context
->before
, context
);
475 nbi
= lttv_traceset_number(traceset
);
476 // nbi = ltt_trace_set_number(traceset);
478 for(i
= 0 ; i
< nbi
; i
++) {
479 tc
= context
->traces
[i
];
482 if(!lttv_hooks_call_check(tc
->check
, tc
)) {
483 g_ptr_array_add(traces
, tc
);
484 lttv_hooks_call(tc
->before
, tc
);
485 nb_control
= ltt_trace_control_tracefile_number(trace
);
486 nb_cpu
= ltt_trace_per_cpu_tracefile_number(trace
);
487 nbj
= nb_control
+ nb_cpu
;
489 for(j
= 0 ; j
< nbj
; j
++) {
491 tfc
= tc
->control_tracefiles
[j
];
494 tfc
= tc
->per_cpu_tracefiles
[j
- nb_control
];
499 if(!lttv_hooks_call_check(tfc
->check
, tfc
)) {
500 g_ptr_array_add(tracefiles
, tfc
);
501 lttv_hooks_call(tfc
->before
, tfc
);
503 ltt_tracefile_seek_time(tracefile
, start
);
504 event
= ltt_tracefile_read(tracefile
);
508 tfc
->timestamp
= ltt_event_time(event
);
509 g_tree_insert(pqueue
, &(tfc
->timestamp
), tfc
);
516 /* Get the next event from the pqueue, call its hooks,
517 reinsert in the pqueue the following event from the same tracefile
518 unless the tracefile is finished or the event is later than the
523 g_tree_foreach(pqueue
, get_first
, &tfc
);
524 if(tfc
== NULL
) break;
526 /* Get the tracefile with an event for the smallest time found. If two
527 or more tracefiles have events for the same time, hope that lookup
528 and remove are consistent. */
531 if(count
> maxNumEvents
){
532 if(tfc
->timestamp
.tv_sec
== preTimestamp
.tv_sec
&&
533 tfc
->timestamp
.tv_nsec
== preTimestamp
.tv_nsec
) {
538 g_tree_foreach(pqueue
, get_first
, &tfc
);
539 if(tfc
== NULL
) break;
540 g_tree_remove(pqueue
, &(tfc
->timestamp
));
545 preTimestamp
= tfc
->timestamp
;
547 tfc
= g_tree_lookup(pqueue
, &(tfc
->timestamp
));
548 g_tree_remove(pqueue
, &(tfc
->timestamp
));
550 if(!lttv_hooks_call(tfc
->check_event
, tfc
)) {
551 id
= ltt_event_eventtype_id(tfc
->e
);
552 lttv_hooks_call(tfc
->before_event
, tfc
);
553 lttv_hooks_call(lttv_hooks_by_id_get(tfc
->before_event_by_id
, id
), tfc
);
554 lttv_hooks_call(tfc
->after_event
, tfc
);
555 lttv_hooks_call(lttv_hooks_by_id_get(tfc
->after_event_by_id
, id
), tfc
);
558 event
= ltt_tracefile_read(tfc
->tf
);
561 tfc
->timestamp
= ltt_event_time(event
);
562 if(tfc
->timestamp
.tv_sec
< end
.tv_sec
||
563 (tfc
->timestamp
.tv_sec
== end
.tv_sec
&& tfc
->timestamp
.tv_nsec
<= end
.tv_nsec
))
564 g_tree_insert(pqueue
, &(tfc
->timestamp
), tfc
);
568 /* Call all the after_tracefile, after_trace and after_traceset hooks. */
570 for(i
= 0, j
= 0 ; i
< traces
->len
; i
++) {
571 tc
= traces
->pdata
[i
];
572 while(j
< tracefiles
->len
) {
573 tfc
= tracefiles
->pdata
[j
];
575 if(tfc
->t_context
== tc
) {
576 lttv_hooks_call(tfc
->after
, tfc
);
581 lttv_hooks_call(tc
->after
, tc
);
584 g_assert(j
== tracefiles
->len
);
585 lttv_hooks_call(context
->after
, context
);
587 /* Free the traces, tracefiles and pqueue */
589 g_ptr_array_free(tracefiles
, TRUE
);
590 g_ptr_array_free(traces
, TRUE
);
591 g_tree_destroy(pqueue
);
595 find_field(LttEventType
*et
, const char *field
)
605 if(field
== NULL
) return NULL
;
607 f
= ltt_eventtype_field(et
);
608 t
= ltt_eventtype_type(et
);
609 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
610 nb
= ltt_type_member_number(t
);
611 for(i
= 0 ; i
< nb
; i
++) {
612 ltt_type_member_type(t
, i
, &name
);
613 if(strcmp(name
, field
) == 0) break;
616 return ltt_field_member(f
, i
);
621 lttv_trace_find_hook(LttTrace
*t
, char *facility
, char *event_type
,
622 char *field1
, char *field2
, char *field3
, LttvHook h
, LttvTraceHook
*th
)
632 nb
= ltt_trace_facility_find(t
, facility
, &pos
);
633 if(nb
< 1) g_error("No %s facility", facility
);
634 f
= ltt_trace_facility_get(t
, pos
);
635 et
= ltt_facility_eventtype_get_by_name(f
, event_type
);
636 if(et
== NULL
) g_error("Event %s does not exist", event_type
);
639 th
->id
= ltt_eventtype_id(et
);
640 th
->f1
= find_field(et
, field1
);
641 th
->f2
= find_field(et
, field2
);
642 th
->f3
= find_field(et
, field3
);