fix GET_HOOK_ID
[lttv.git] / ltt / branches / poly / lttv / lttv / tracecontext.c
... / ...
CommitLineData
1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
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;
7 *
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.
12 *
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,
16 * MA 02111-1307, USA.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include <string.h>
24#include <lttv/tracecontext.h>
25#include <ltt/event.h>
26#include <ltt/facility.h>
27#include <ltt/trace.h>
28#include <ltt/type.h>
29#include <errno.h>
30
31
32
33
34gint compare_tracefile(gconstpointer a, gconstpointer b)
35{
36 gint comparison = 0;
37
38 const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
39 const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
40
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)
47 comparison = -1;
48 else if(trace_a->t_context->index > trace_b->t_context->index)
49 comparison = 1;
50 }
51 }
52 return comparison;
53}
54
55struct _LttvTracesetContextPosition {
56 GArray *ep; /* Array of LttEventPosition */
57 GArray *tfc; /* Array of corresponding
58 TracefileContext* */
59 LttTime timestamp; /* Current time at the saved position */
60};
61
62void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
63{
64 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
65}
66
67
68void lttv_context_fini(LttvTracesetContext *self)
69{
70 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
71}
72
73
74LttvTracesetContext *
75lttv_context_new_traceset_context(LttvTracesetContext *self)
76{
77 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
78}
79
80
81
82
83LttvTraceContext *
84lttv_context_new_trace_context(LttvTracesetContext *self)
85{
86 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
87}
88
89
90LttvTracefileContext *
91lttv_context_new_tracefile_context(LttvTracesetContext *self)
92{
93 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
94}
95
96/****************************************************************************
97 * lttv_traceset_context_compute_time_span
98 *
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
103 * critical.
104 *
105 * Author : Xang Xiu Yang
106 ***************************************************************************/
107static void lttv_traceset_context_compute_time_span(
108 LttvTracesetContext *self,
109 TimeInterval *time_span)
110{
111 LttvTraceset * traceset = self->ts;
112 int numTraces = lttv_traceset_number(traceset);
113 int i;
114 LttTime s, e;
115 LttvTraceContext *tc;
116 LttTrace * trace;
117
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;
122
123 for(i=0; i<numTraces;i++){
124 tc = self->traces[i];
125 trace = tc->t;
126
127 ltt_trace_time_span_get(trace, &s, &e);
128
129 if(i==0){
130 time_span->start_time = s;
131 time_span->end_time = e;
132 }else{
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;
141 }
142 }
143}
144
145static void init_tracefile_context(LttTracefile *tracefile,
146 LttvTraceContext *tc)
147{
148 LttvTracefileContext *tfc;
149 LttvTracesetContext *tsc = tc->ts_context;
150
151 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(tsc)->new_tracefile_context(tsc);
152
153 tfc->index = tc->tracefiles->len;
154 tc->tracefiles = g_array_append_val(tc->tracefiles, tfc);
155
156 tfc->tf = tracefile;
157
158 tfc->t_context = tc;
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);
162}
163
164
165static void
166init(LttvTracesetContext *self, LttvTraceset *ts)
167{
168 guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile;
169
170 LttvTraceContext *tc;
171
172 GData **tracefiles_groups;
173
174 struct compute_tracefile_group_args args;
175
176 nb_trace = lttv_traceset_number(ts);
177 self->ts = 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;
184
185 tc->ts_context = self;
186 tc->index = i;
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);
193
194 tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t);
195
196 args.func = (ForEachTraceFileFunc)init_tracefile_context;
197 args.func_args = tc;
198
199 g_datalist_foreach(tracefiles_groups,
200 (GDataForeachFunc)compute_tracefile_group,
201 &args);
202
203#if 0
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);
208
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;
212 tfc->index = j;
213
214 if(j < nb_control) {
215 tfc->control = TRUE;
216 tfc->tf = ltt_trace_control_tracefile_get(tc->t, j);
217 }
218 else {
219 tfc->control = FALSE;
220 tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
221 }
222
223 tfc->t_context = tc;
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);
228 }
229#endif //0
230
231 }
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);
235
236}
237
238
239void fini(LttvTracesetContext *self)
240{
241 guint i, j, nb_trace, nb_tracefile;
242
243 LttvTraceContext *tc;
244
245 LttvTracefileContext *tfc;
246
247 LttvTraceset *ts = self->ts;
248
249 //FIXME : segfault
250
251 g_tree_destroy(self->pqueue);
252 g_object_unref(self->a);
253
254 nb_trace = lttv_traceset_number(ts);
255
256 for(i = 0 ; i < nb_trace ; i++) {
257 tc = self->traces[i];
258
259 g_object_unref(tc->a);
260
261 nb_tracefile = tc->tracefiles->len;
262
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);
268 g_object_unref(tfc);
269 }
270 g_array_free(tc->tracefiles, TRUE);
271 g_object_unref(tc);
272 }
273 g_free(self->traces);
274}
275
276
277void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
278 LttvHooks *before_traceset,
279 LttvHooks *before_trace,
280 LttvHooks *before_tracefile,
281 LttvHooks *event,
282 LttvHooksById *event_by_id)
283{
284 LttvTraceset *ts = self->ts;
285
286 guint i, nb_trace;
287
288 LttvTraceContext *tc;
289
290 lttv_hooks_call(before_traceset, self);
291
292 nb_trace = lttv_traceset_number(ts);
293
294 for(i = 0 ; i < nb_trace ; i++) {
295 tc = self->traces[i];
296 lttv_trace_context_add_hooks(tc,
297 before_trace,
298 before_tracefile,
299 event,
300 event_by_id);
301 }
302}
303
304
305void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
306 LttvHooks *after_traceset,
307 LttvHooks *after_trace,
308 LttvHooks *after_tracefile,
309 LttvHooks *event,
310 LttvHooksById *event_by_id)
311{
312
313 LttvTraceset *ts = self->ts;
314
315 guint i, nb_trace;
316
317 LttvTraceContext *tc;
318
319 nb_trace = lttv_traceset_number(ts);
320
321 for(i = 0 ; i < nb_trace ; i++) {
322 tc = self->traces[i];
323 lttv_trace_context_remove_hooks(tc,
324 after_trace,
325 after_tracefile,
326 event,
327 event_by_id);
328 }
329
330 lttv_hooks_call(after_traceset, self);
331
332
333}
334
335void lttv_trace_context_add_hooks(LttvTraceContext *self,
336 LttvHooks *before_trace,
337 LttvHooks *before_tracefile,
338 LttvHooks *event,
339 LttvHooksById *event_by_id)
340{
341 guint i, nb_tracefile;
342
343 LttvTracefileContext *tfc;
344
345 lttv_hooks_call(before_trace, self);
346
347 nb_tracefile = self->tracefiles->len;
348
349 for(i = 0 ; i < nb_tracefile ; i++) {
350 tfc = g_array_index(self->tracefiles, LttvTracefileContext*, i);
351 lttv_tracefile_context_add_hooks(tfc,
352 before_tracefile,
353 event,
354 event_by_id);
355 }
356}
357
358
359
360void lttv_trace_context_remove_hooks(LttvTraceContext *self,
361 LttvHooks *after_trace,
362 LttvHooks *after_tracefile,
363 LttvHooks *event,
364 LttvHooksById *event_by_id)
365{
366 guint i, nb_tracefile;
367
368 LttvTracefileContext *tfc;
369
370 nb_tracefile = self->tracefiles->len;
371
372 for(i = 0 ; i < nb_tracefile ; i++) {
373 tfc = g_array_index(self->tracefiles, LttvTracefileContext*, i);
374 lttv_tracefile_context_remove_hooks(tfc,
375 after_tracefile,
376 event,
377 event_by_id);
378 }
379
380 lttv_hooks_call(after_trace, self);
381}
382
383void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
384 LttvHooks *before_tracefile,
385 LttvHooks *event,
386 LttvHooksById *event_by_id)
387{
388 guint i, index;
389
390 LttvHooks *hook;
391
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 < event_by_id->array->len; i++) {
396 index = g_array_index(event_by_id->array, guint, i);
397 hook = lttv_hooks_by_id_find(self->event_by_id, index);
398 lttv_hooks_add_list(hook, lttv_hooks_by_id_get(event_by_id, index));
399 }
400 }
401}
402
403void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
404 LttvHooks *after_tracefile,
405 LttvHooks *event,
406 LttvHooksById *event_by_id)
407{
408 guint i, index;
409
410 LttvHooks *hook;
411
412 lttv_hooks_remove_list(self->event, event);
413 if(event_by_id != NULL) {
414 for(i = 0; i < event_by_id->array->len; i++) {
415 index = g_array_index(event_by_id->array, guint, i);
416 hook = lttv_hooks_by_id_get(self->event_by_id, index);
417 if(hook != NULL)
418 lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, index));
419 }
420 }
421
422 lttv_hooks_call(after_tracefile, self);
423}
424
425
426
427void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext *tfc,
428 unsigned i,
429 LttvHooks *event_by_id)
430{
431 LttvHooks * h;
432 h = lttv_hooks_by_id_find(tfc->event_by_id, i);
433 lttv_hooks_add_list(h, event_by_id);
434}
435
436void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext *tfc,
437 unsigned i)
438{
439 lttv_hooks_by_id_remove(tfc->event_by_id, i);
440}
441
442static LttvTracesetContext *
443new_traceset_context(LttvTracesetContext *self)
444{
445 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
446}
447
448
449static LttvTraceContext *
450new_trace_context(LttvTracesetContext *self)
451{
452 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
453}
454
455
456static LttvTracefileContext *
457new_tracefile_context(LttvTracesetContext *self)
458{
459 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
460}
461
462
463static void
464traceset_context_instance_init (GTypeInstance *instance, gpointer g_class)
465{
466 /* Be careful of anything which would not work well with shallow copies */
467}
468
469
470static void
471traceset_context_finalize (LttvTracesetContext *self)
472{
473 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE)))
474 ->finalize(G_OBJECT(self));
475}
476
477
478static void
479traceset_context_class_init (LttvTracesetContextClass *klass)
480{
481 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
482
483 gobject_class->finalize = (void (*)(GObject *self))traceset_context_finalize;
484 klass->init = init;
485 klass->fini = fini;
486 klass->new_traceset_context = new_traceset_context;
487 klass->new_trace_context = new_trace_context;
488 klass->new_tracefile_context = new_tracefile_context;
489}
490
491
492GType
493lttv_traceset_context_get_type(void)
494{
495 static GType type = 0;
496 if (type == 0) {
497 static const GTypeInfo info = {
498 sizeof (LttvTracesetContextClass),
499 NULL, /* base_init */
500 NULL, /* base_finalize */
501 (GClassInitFunc) traceset_context_class_init, /* class_init */
502 NULL, /* class_finalize */
503 NULL, /* class_data */
504 sizeof (LttvTracesetContext),
505 0, /* n_preallocs */
506 (GInstanceInitFunc) traceset_context_instance_init, /* instance_init */
507 NULL /* Value handling */
508 };
509
510 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType",
511 &info, 0);
512 }
513 return type;
514}
515
516
517static void
518trace_context_instance_init (GTypeInstance *instance, gpointer g_class)
519{
520 /* Be careful of anything which would not work well with shallow copies */
521}
522
523
524static void
525trace_context_finalize (LttvTraceContext *self)
526{
527 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))->
528 finalize(G_OBJECT(self));
529}
530
531
532static void
533trace_context_class_init (LttvTraceContextClass *klass)
534{
535 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
536
537 gobject_class->finalize = (void (*)(GObject *self)) trace_context_finalize;
538}
539
540
541GType
542lttv_trace_context_get_type(void)
543{
544 static GType type = 0;
545 if (type == 0) {
546 static const GTypeInfo info = {
547 sizeof (LttvTraceContextClass),
548 NULL, /* base_init */
549 NULL, /* base_finalize */
550 (GClassInitFunc) trace_context_class_init, /* class_init */
551 NULL, /* class_finalize */
552 NULL, /* class_data */
553 sizeof (LttvTraceContext),
554 0, /* n_preallocs */
555 (GInstanceInitFunc) trace_context_instance_init, /* instance_init */
556 NULL /* Value handling */
557 };
558
559 type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType",
560 &info, 0);
561 }
562 return type;
563}
564
565
566static void
567tracefile_context_instance_init (GTypeInstance *instance, gpointer g_class)
568{
569 /* Be careful of anything which would not work well with shallow copies */
570}
571
572
573static void
574tracefile_context_finalize (LttvTracefileContext *self)
575{
576 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE)))
577 ->finalize(G_OBJECT(self));
578}
579
580
581static void
582tracefile_context_class_init (LttvTracefileContextClass *klass)
583{
584 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
585
586 gobject_class->finalize = (void (*)(GObject *self))tracefile_context_finalize;
587}
588
589
590GType
591lttv_tracefile_context_get_type(void)
592{
593 static GType type = 0;
594 if (type == 0) {
595 static const GTypeInfo info = {
596 sizeof (LttvTracefileContextClass),
597 NULL, /* base_init */
598 NULL, /* base_finalize */
599 (GClassInitFunc) tracefile_context_class_init, /* class_init */
600 NULL, /* class_finalize */
601 NULL, /* class_data */
602 sizeof (LttvTracefileContext),
603 0, /* n_preallocs */
604 (GInstanceInitFunc) tracefile_context_instance_init, /* instance_init */
605 NULL /* Value handling */
606 };
607
608 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType",
609 &info, 0);
610 }
611 return type;
612}
613
614
615
616static gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
617 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
618 return TRUE;
619}
620
621
622void lttv_process_traceset_begin(LttvTracesetContext *self,
623 LttvHooks *before_traceset,
624 LttvHooks *before_trace,
625 LttvHooks *before_tracefile,
626 LttvHooks *event,
627 LttvHooksById *event_by_id)
628{
629
630 /* simply add hooks in context. _before hooks are called by add_hooks. */
631 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
632 lttv_traceset_context_add_hooks(self,
633 before_traceset,
634 before_trace,
635 before_tracefile,
636 event,
637 event_by_id);
638
639}
640
641/* Note : a _middle must be preceded from a _seek or another middle */
642guint lttv_process_traceset_middle(LttvTracesetContext *self,
643 LttTime end,
644 guint nb_events,
645 const LttvTracesetContextPosition *end_position)
646{
647 GTree *pqueue = self->pqueue;
648
649 guint id;
650
651 LttvTracefileContext *tfc;
652
653 LttEvent *e;
654
655 unsigned count = 0;
656
657 gboolean last_ret = FALSE; /* return value of the last hook list called */
658
659 /* Get the next event from the pqueue, call its hooks,
660 reinsert in the pqueue the following event from the same tracefile
661 unless the tracefile is finished or the event is later than the
662 end time. */
663
664 while(TRUE) {
665 tfc = NULL;
666 g_tree_foreach(pqueue, get_first, &tfc);
667 /* End of traceset : tfc is NULL */
668 if(unlikely(tfc == NULL))
669 {
670 return count;
671 }
672
673 /* Have we reached :
674 * - the maximum number of events specified?
675 * - the end position ?
676 * - the end time ?
677 * then the read is finished. We leave the queue in the same state and
678 * break the loop.
679 */
680
681 if(unlikely(last_ret == TRUE ||
682 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
683 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
684 end_position) == 0)||
685 ltt_time_compare(end, tfc->timestamp) <= 0))
686 {
687 return count;
688 }
689
690 /* Get the tracefile with an event for the smallest time found. If two
691 or more tracefiles have events for the same time, hope that lookup
692 and remove are consistent. */
693
694 g_tree_remove(pqueue, tfc);
695 count++;
696
697 e = ltt_tracefile_get_event(tfc->tf);
698 id = ltt_event_eventtype_id(e);
699 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
700 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
701
702 if(likely(!ltt_tracefile_read(tfc->tf))) {
703 tfc->timestamp = ltt_event_time(e);
704 g_tree_insert(pqueue, tfc, tfc);
705 }
706 }
707}
708
709
710void lttv_process_traceset_end(LttvTracesetContext *self,
711 LttvHooks *after_traceset,
712 LttvHooks *after_trace,
713 LttvHooks *after_tracefile,
714 LttvHooks *event,
715 LttvHooksById *event_by_id)
716{
717 /* Remove hooks from context. _after hooks are called by remove_hooks. */
718 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
719 lttv_traceset_context_remove_hooks(self,
720 after_traceset,
721 after_trace,
722 after_tracefile,
723 event,
724 event_by_id);
725}
726
727/* Subtile modification :
728 * if tracefile has no event at or after the time requested, it is not put in
729 * the queue, as the next read would fail. */
730void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
731{
732 guint i, nb_tracefile;
733
734 gint ret;
735
736 LttvTracefileContext *tfc;
737
738 GTree *pqueue = self->ts_context->pqueue;
739
740 nb_tracefile = self->tracefiles->len;
741
742 for(i = 0 ; i < nb_tracefile ; i++) {
743 tfc = g_array_index(self->tracefiles, LttvTracefileContext*, i);
744 ret = ltt_tracefile_seek_time(tfc->tf, start);
745 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
746 g_tree_remove(pqueue, tfc);
747
748 if(ret == 0) { /* not ERANGE especially */
749 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
750 g_tree_insert(pqueue, tfc, tfc);
751 }
752 }
753}
754
755
756void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
757{
758 guint i, nb_trace;
759
760 LttvTraceContext *tc;
761
762 nb_trace = lttv_traceset_number(self->ts);
763 for(i = 0 ; i < nb_trace ; i++) {
764 tc = self->traces[i];
765 lttv_process_trace_seek_time(tc, start);
766 }
767}
768
769
770gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
771 const LttvTracesetContextPosition *pos)
772{
773 guint i;
774 LttvTraceContext *tc;
775 LttvTracefileContext *tfc;
776
777 g_tree_destroy(self->pqueue);
778 self->pqueue = g_tree_new(compare_tracefile);
779
780 for(i=0;i<pos->ep->len; i++) {
781 LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i);
782 LttvTracefileContext *tfc =
783 g_array_index(pos->tfc, LttvTracefileContext*, i);
784 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
785 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
786 g_tree_insert(self->pqueue, tfc, tfc);
787 }
788 return TRUE;
789}
790
791
792
793static LttField *
794find_field(LttEventType *et, const GQuark field)
795{
796 LttType *t;
797
798 LttField *f;
799
800 guint i, nb;
801
802 GQuark name;
803
804 /* Field is unset */
805 if(field == 0) return NULL;
806
807 f = ltt_eventtype_field(et);
808 t = ltt_eventtype_type(et);
809 g_assert(ltt_type_class(t) == LTT_STRUCT);
810 nb = ltt_type_member_number(t);
811 for(i = 0 ; i < nb ; i++) {
812 ltt_type_member_type(t, i, &name);
813 if(name == field) break;
814 }
815 g_assert(i < nb);
816 return ltt_field_member(f, i);
817}
818
819LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
820 guint facility_id)
821{
822 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
823}
824
825/* Get the first facility corresponding to the name. As the types must be
826 * compatible, it is relevant to use the field name and sizes of the first
827 * facility to create data structures and assume the data will be compatible
828 * thorough the trace */
829LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
830{
831 g_assert(th->fac_list->len > 0);
832 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
833}
834
835
836/* Returns 0 on success, -1 if fails. */
837gint
838lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
839 GQuark field1, GQuark field2, GQuark field3, LttvHook h, LttvTraceHook *th)
840{
841 LttFacility *f;
842
843 LttEventType *et, *first_et;
844
845 GArray *facilities;
846
847 guint i, fac_id, ev_id;
848
849 LttvTraceHookByFacility *thf, *first_thf;
850
851 facilities = ltt_trace_facility_get_by_name(t, facility);
852
853 if(unlikely(facilities == NULL)) goto facility_error;
854
855 th->fac_index = g_array_sized_new(FALSE, TRUE,
856 sizeof(LttvTraceHookByFacility),
857 NUM_FACILITIES);
858 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
859
860 th->fac_list = g_array_sized_new(FALSE, TRUE,
861 sizeof(LttvTraceHookByFacility*),
862 facilities->len);
863 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
864
865 fac_id = g_array_index(facilities, guint, 0);
866 f = ltt_trace_get_facility_by_num(t, fac_id);
867
868 et = ltt_facility_eventtype_get_by_name(f, event);
869 if(unlikely(et == NULL)) goto event_error;
870
871 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
872 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0)
873 = thf;
874
875 ev_id = ltt_eventtype_id(et);
876
877 thf->h = h;
878 thf->id = GET_HOOK_ID(fac_id, ev_id);
879 thf->f1 = find_field(et, field1);
880 thf->f2 = find_field(et, field2);
881 thf->f3 = find_field(et, field3);
882
883 first_thf = thf;
884
885 /* Check for type compatibility too */
886 for(i=1;i<facilities->len;i++) {
887 fac_id = g_array_index(facilities, guint, i);
888 f = ltt_trace_get_facility_by_num(t, fac_id);
889
890 et = ltt_facility_eventtype_get_by_name(f, ltt_eventtype_name(et));
891 if(unlikely(et == NULL)) goto event_error;
892
893 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
894 g_array_index(th->fac_list, LttvTraceHookByFacility*, i)
895 = thf;
896 ev_id = ltt_eventtype_id(et);
897 thf->h = h;
898 thf->id = GET_HOOK_ID(fac_id, ev_id);
899 thf->f1 = find_field(et, field1);
900 if(check_fields_compatibility(first_et, et,
901 first_thf->f1, thf->f1))
902 goto type_error;
903
904 thf->f2 = find_field(et, field2);
905 if(check_fields_compatibility(first_et, et,
906 first_thf->f2, thf->f2))
907 goto type_error;
908
909 thf->f3 = find_field(et, field3);
910 if(check_fields_compatibility(first_et, et,
911 first_thf->f3, thf->f3))
912 goto type_error;
913 }
914
915 return 0;
916
917type_error:
918 goto free;
919event_error:
920 g_error("Event type %s does not exist",
921 g_quark_to_string(ltt_eventtype_name(et)));
922 goto free;
923facility_error:
924 g_error("No %s facility", g_quark_to_string(facility));
925 goto free;
926free:
927 g_array_free(th->fac_index, TRUE);
928 g_array_free(th->fac_list, TRUE);
929 th->fac_index = NULL;
930 th->fac_list = NULL;
931 return -1;
932}
933
934void lttv_trace_hook_destroy(LttvTraceHook *th)
935{
936 g_array_free(th->fac_index, TRUE);
937 g_array_free(th->fac_list, TRUE);
938}
939
940
941LttvTracesetContextPosition *lttv_traceset_context_position_new()
942{
943 LttvTracesetContextPosition *pos = g_new(LttvTracesetContextPosition,1);
944 pos->ep = g_array_sized_new(FALSE, TRUE, sizeof(LttEventPosition*),
945 10);
946 pos->tfc = g_array_sized_new(FALSE, TRUE, sizeof(LttvTracefileContext*),
947 10);
948 pos->timestamp = ltt_time_infinite;
949 return pos;
950}
951
952gboolean traverse_get_tfc(gpointer key, gpointer value, gpointer data)
953{
954 LttvTracefileContext *tfc = (LttvTracefileContext *)value;
955 LttvTracesetContextPosition *pos = (LttvTracesetContextPosition *)data;
956
957 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
958 LttEventPosition *ep = ltt_event_position_new();
959
960 ltt_event_position(event, ep);
961
962 g_array_append_val(pos->ep, ep);
963 g_array_append_val(pos->tfc, tfc);
964
965 if(ltt_time_compare(tfc->timestamp, pos->timestamp) < 0)
966 pos->timestamp = tfc->timestamp;
967
968 return 0;
969}
970
971/* Subtile modification :
972 * only save the tracefiles that are loaded in the pqueue */
973void lttv_traceset_context_position_save(const LttvTracesetContext *self,
974 LttvTracesetContextPosition *pos)
975{
976 g_tree_foreach(self->pqueue, traverse_get_tfc, pos);
977}
978
979void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
980{
981 int i;
982 for(i=0;i<pos->ep->len;i++)
983 g_free(g_array_index(pos->ep, LttEventPosition*, i));
984 g_array_free(pos->ep, TRUE);
985 g_array_free(pos->tfc, TRUE);
986 g_free(pos);
987}
988
989void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
990 const LttvTracesetContextPosition *src)
991{
992 int i;
993
994 g_array_set_size(dest->ep, src->ep->len);
995 g_array_set_size(dest->tfc, src->tfc->len);
996
997 for(i=0;i<src->ep->len;i++) {
998 g_array_index(dest->ep, LttEventPosition*, i) = ltt_event_position_new();
999 ltt_event_position_copy(
1000 g_array_index(dest->ep, LttEventPosition*, i),
1001 g_array_index(src->ep, LttEventPosition*, i));
1002 }
1003 for(i=0;i<src->tfc->len;i++) {
1004 g_array_index(dest->tfc, LttvTracefileContext*, i) =
1005 g_array_index(src->tfc, LttvTracefileContext*, i);
1006 }
1007 dest->timestamp = src->timestamp;
1008}
1009
1010gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1011 const LttvTracesetContextPosition *pos)
1012{
1013 int i;
1014 int ret;
1015
1016 for(i=0;i<pos->ep->len;i++) {
1017 LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i);
1018 LttvTracefileContext *tfc =
1019 g_array_index(pos->tfc, LttvTracefileContext*, i);
1020
1021 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
1022
1023 ret = ltt_event_position_compare((LttEventPosition*)event,
1024 ep);
1025 if(ret != 0) return ret;
1026
1027 }
1028 return 0;
1029}
1030
1031
1032gint lttv_traceset_context_pos_pos_compare(
1033 const LttvTracesetContextPosition *pos1,
1034 const LttvTracesetContextPosition *pos2)
1035{
1036 int i, j;
1037 int ret;
1038
1039 for(i=0;i<pos1->ep->len;i++) {
1040 LttEventPosition *ep1 = g_array_index(pos1->ep, LttEventPosition*, i);
1041 LttTracefile *tf1 = ltt_event_position_tracefile(ep1);
1042
1043 for(j=0;j<pos2->ep->len;j++) {
1044 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1045 LttTracefile *tf2 = ltt_event_position_tracefile(ep2);
1046
1047 if(tf1 == tf2) {
1048 ret = ltt_event_position_compare(ep1, ep2);
1049 if(ret != 0) return ret;
1050 }
1051 }
1052 }
1053 return 0;
1054
1055}
1056
1057
1058LttTime lttv_traceset_context_position_get_time(
1059 const LttvTracesetContextPosition *pos)
1060{
1061 return pos->timestamp;
1062}
1063
1064
1065LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1066{
1067 GTree *pqueue = self->pqueue;
1068 LttvTracefileContext *tfc = NULL;
1069
1070 g_tree_foreach(pqueue, get_first, &tfc);
1071
1072 return tfc;
1073}
This page took 0.026103 seconds and 4 git commands to generate.