fix seek to position
[lttv.git] / ltt / branches / poly / lttv / lttv / tracecontext.c
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
34 gint 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_b->timestamp, trace_a->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
55 struct _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
62 void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
63 {
64 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
65 }
66
67
68 void lttv_context_fini(LttvTracesetContext *self)
69 {
70 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
71 }
72
73
74 LttvTracesetContext *
75 lttv_context_new_traceset_context(LttvTracesetContext *self)
76 {
77 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
78 }
79
80
81
82
83 LttvTraceContext *
84 lttv_context_new_trace_context(LttvTracesetContext *self)
85 {
86 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
87 }
88
89
90 LttvTracefileContext *
91 lttv_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 ***************************************************************************/
107 static 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
145 static 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
165 static void
166 init(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
239 void 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
277 void 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
305 void 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
335 void 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
360 void 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
383 void 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
403 void 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
427 void 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
436 void 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
442 static LttvTracesetContext *
443 new_traceset_context(LttvTracesetContext *self)
444 {
445 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
446 }
447
448
449 static LttvTraceContext *
450 new_trace_context(LttvTracesetContext *self)
451 {
452 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
453 }
454
455
456 static LttvTracefileContext *
457 new_tracefile_context(LttvTracesetContext *self)
458 {
459 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
460 }
461
462
463 static void
464 traceset_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
470 static void
471 traceset_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
478 static void
479 traceset_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
492 GType
493 lttv_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
517 static void
518 trace_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
524 static void
525 trace_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
532 static void
533 trace_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
541 GType
542 lttv_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
566 static void
567 tracefile_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
573 static void
574 tracefile_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
581 static void
582 tracefile_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
590 GType
591 lttv_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
616 static gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
617 g_assert(key == value);
618 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
619 return TRUE;
620 }
621
622 static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) {
623
624 LttvTracefileContext *tfc = (LttvTracefileContext *)key;
625
626 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
627 g_quark_to_string(ltt_tracefile_name(tfc->tf)),
628 tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec,
629 tfc->index, tfc->t_context->index);
630
631 if(((LttvTracefileContext *)user_data) == (LttvTracefileContext *)value) {
632 g_assert(compare_tracefile(user_data, value) == 0);
633 } else
634 g_assert(compare_tracefile(user_data, value) != 0);
635
636 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
637 return FALSE;
638 }
639
640
641
642 void lttv_process_traceset_begin(LttvTracesetContext *self,
643 LttvHooks *before_traceset,
644 LttvHooks *before_trace,
645 LttvHooks *before_tracefile,
646 LttvHooks *event,
647 LttvHooksById *event_by_id)
648 {
649
650 /* simply add hooks in context. _before hooks are called by add_hooks. */
651 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
652 lttv_traceset_context_add_hooks(self,
653 before_traceset,
654 before_trace,
655 before_tracefile,
656 event,
657 event_by_id);
658
659 }
660
661 /* Note : a _middle must be preceded from a _seek or another middle */
662 guint lttv_process_traceset_middle(LttvTracesetContext *self,
663 LttTime end,
664 guint nb_events,
665 const LttvTracesetContextPosition *end_position)
666 {
667 GTree *pqueue = self->pqueue;
668
669 guint fac_id, ev_id, id;
670
671 LttvTracefileContext *tfc;
672
673 LttEvent *e;
674
675 unsigned count = 0;
676
677 guint read_ret = FALSE;
678
679 gboolean last_ret = FALSE; /* return value of the last hook list called */
680
681 /* Get the next event from the pqueue, call its hooks,
682 reinsert in the pqueue the following event from the same tracefile
683 unless the tracefile is finished or the event is later than the
684 end time. */
685
686 while(TRUE) {
687 tfc = NULL;
688 g_tree_foreach(pqueue, get_first, &tfc);
689 /* End of traceset : tfc is NULL */
690 if(unlikely(tfc == NULL))
691 {
692 return count;
693 }
694
695 /* Have we reached :
696 * - the maximum number of events specified?
697 * - the end position ?
698 * - the end time ?
699 * then the read is finished. We leave the queue in the same state and
700 * break the loop.
701 */
702
703 if(unlikely(last_ret == TRUE ||
704 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
705 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
706 end_position) == 0)||
707 ltt_time_compare(end, tfc->timestamp) <= 0))
708 {
709 return count;
710 }
711
712 /* Get the tracefile with an event for the smallest time found. If two
713 or more tracefiles have events for the same time, hope that lookup
714 and remove are consistent. */
715
716 #ifdef DEBUG
717 g_debug("test tree before remove");
718 g_tree_foreach(pqueue, test_tree, tfc);
719 #endif //DEBUG
720 g_tree_remove(pqueue, tfc);
721
722 #ifdef DEBUG
723 g_debug("test tree after remove");
724 g_tree_foreach(pqueue, test_tree, tfc);
725 #endif //DEBUG
726
727 count++;
728
729 e = ltt_tracefile_get_event(tfc->tf);
730 fac_id = ltt_event_facility_id(e);
731 ev_id = ltt_event_eventtype_id(e);
732 id = GET_HOOK_ID(fac_id, ev_id);
733 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
734 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
735
736 read_ret = ltt_tracefile_read(tfc->tf);
737
738 if(likely(!read_ret)) {
739 g_debug("An event is ready");
740 tfc->timestamp = ltt_event_time(e);
741
742 g_tree_insert(pqueue, tfc, tfc);
743 } else {
744 tfc->timestamp = ltt_time_infinite;
745
746 if(read_ret == ERANGE)
747 g_debug("End of trace");
748 else
749 g_error("Error happened in lttv_process_traceset_middle");
750 }
751 }
752 }
753
754
755 void lttv_process_traceset_end(LttvTracesetContext *self,
756 LttvHooks *after_traceset,
757 LttvHooks *after_trace,
758 LttvHooks *after_tracefile,
759 LttvHooks *event,
760 LttvHooksById *event_by_id)
761 {
762 /* Remove hooks from context. _after hooks are called by remove_hooks. */
763 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
764 lttv_traceset_context_remove_hooks(self,
765 after_traceset,
766 after_trace,
767 after_tracefile,
768 event,
769 event_by_id);
770 }
771
772 /* Subtile modification :
773 * if tracefile has no event at or after the time requested, it is not put in
774 * the queue, as the next read would fail. */
775 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
776 {
777 guint i, nb_tracefile;
778
779 gint ret;
780
781 LttvTracefileContext **tfc;
782
783 GTree *pqueue = self->ts_context->pqueue;
784
785 nb_tracefile = self->tracefiles->len;
786
787 for(i = 0 ; i < nb_tracefile ; i++) {
788 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
789
790 g_tree_remove(pqueue, *tfc);
791
792 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
793 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
794
795 if(ret == 0) { /* not ERANGE especially */
796 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
797 g_tree_insert(pqueue, (*tfc), (*tfc));
798 } else {
799 (*tfc)->timestamp = ltt_time_infinite;
800 }
801 }
802 }
803
804
805 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
806 {
807 guint i, nb_trace;
808
809 LttvTraceContext *tc;
810
811 nb_trace = lttv_traceset_number(self->ts);
812 for(i = 0 ; i < nb_trace ; i++) {
813 tc = self->traces[i];
814 lttv_process_trace_seek_time(tc, start);
815 }
816 }
817
818
819 gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
820 const LttvTracesetContextPosition *pos)
821 {
822 guint i;
823 LttvTraceContext *tc;
824 LttvTracefileContext *tfc;
825
826 g_tree_destroy(self->pqueue);
827 self->pqueue = g_tree_new(compare_tracefile);
828
829 for(i=0;i<pos->ep->len; i++) {
830 LttEventPosition **ep = &g_array_index(pos->ep, LttEventPosition*, i);
831 LttvTracefileContext **tfc =
832 &g_array_index(pos->tfc, LttvTracefileContext*, i);
833 if(*ep != NULL) {
834 g_assert(ltt_tracefile_seek_position((*tfc)->tf, *ep) == 0);
835 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
836 g_tree_insert(self->pqueue, (*tfc), (*tfc));
837 } else {
838 (*tfc)->timestamp = ltt_time_infinite;
839 }
840 }
841 return TRUE;
842 }
843
844
845
846 static LttField *
847 find_field(LttEventType *et, const GQuark field)
848 {
849 LttType *t;
850
851 LttField *f;
852
853 guint i, nb;
854
855 GQuark name;
856
857 /* Field is unset */
858 if(field == 0) return NULL;
859
860 f = ltt_eventtype_field(et);
861 t = ltt_eventtype_type(et);
862 g_assert(ltt_type_class(t) == LTT_STRUCT);
863 nb = ltt_type_member_number(t);
864 for(i = 0 ; i < nb ; i++) {
865 ltt_type_member_type(t, i, &name);
866 if(name == field) break;
867 }
868 g_assert(i < nb);
869 return ltt_field_member(f, i);
870 }
871
872 LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
873 guint facility_id)
874 {
875 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
876 }
877
878 /* Get the first facility corresponding to the name. As the types must be
879 * compatible, it is relevant to use the field name and sizes of the first
880 * facility to create data structures and assume the data will be compatible
881 * thorough the trace */
882 LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
883 {
884 g_assert(th->fac_list->len > 0);
885 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
886 }
887
888
889 /* Returns 0 on success, -1 if fails. */
890 gint
891 lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
892 GQuark field1, GQuark field2, GQuark field3, LttvHook h, LttvTraceHook *th)
893 {
894 LttFacility *f;
895
896 LttEventType *et, *first_et;
897
898 GArray *facilities;
899
900 guint i, fac_id, ev_id;
901
902 LttvTraceHookByFacility *thf, *first_thf;
903
904 facilities = ltt_trace_facility_get_by_name(t, facility);
905
906 if(unlikely(facilities == NULL)) goto facility_error;
907
908 th->fac_index = g_array_sized_new(FALSE, TRUE,
909 sizeof(LttvTraceHookByFacility),
910 NUM_FACILITIES);
911 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
912
913 th->fac_list = g_array_sized_new(FALSE, TRUE,
914 sizeof(LttvTraceHookByFacility*),
915 facilities->len);
916 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
917
918 fac_id = g_array_index(facilities, guint, 0);
919 f = ltt_trace_get_facility_by_num(t, fac_id);
920
921 et = ltt_facility_eventtype_get_by_name(f, event);
922 if(unlikely(et == NULL)) goto event_error;
923
924 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
925 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf;
926
927 ev_id = ltt_eventtype_id(et);
928
929 thf->h = h;
930 thf->id = GET_HOOK_ID(fac_id, ev_id);
931 thf->f1 = find_field(et, field1);
932 thf->f2 = find_field(et, field2);
933 thf->f3 = find_field(et, field3);
934
935 first_thf = thf;
936
937 /* Check for type compatibility too */
938 for(i=1;i<facilities->len;i++) {
939 fac_id = g_array_index(facilities, guint, i);
940 f = ltt_trace_get_facility_by_num(t, fac_id);
941
942 et = ltt_facility_eventtype_get_by_name(f, ltt_eventtype_name(et));
943 if(unlikely(et == NULL)) goto event_error;
944
945 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
946 g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf;
947 ev_id = ltt_eventtype_id(et);
948 thf->h = h;
949 thf->id = GET_HOOK_ID(fac_id, ev_id);
950 thf->f1 = find_field(et, field1);
951 if(check_fields_compatibility(first_et, et,
952 first_thf->f1, thf->f1))
953 goto type_error;
954
955 thf->f2 = find_field(et, field2);
956 if(check_fields_compatibility(first_et, et,
957 first_thf->f2, thf->f2))
958 goto type_error;
959
960 thf->f3 = find_field(et, field3);
961 if(check_fields_compatibility(first_et, et,
962 first_thf->f3, thf->f3))
963 goto type_error;
964 }
965
966 return 0;
967
968 type_error:
969 goto free;
970 event_error:
971 g_error("Event type %s does not exist",
972 g_quark_to_string(ltt_eventtype_name(et)));
973 goto free;
974 facility_error:
975 g_error("No %s facility", g_quark_to_string(facility));
976 goto free;
977 free:
978 g_array_free(th->fac_index, TRUE);
979 g_array_free(th->fac_list, TRUE);
980 th->fac_index = NULL;
981 th->fac_list = NULL;
982 return -1;
983 }
984
985 void lttv_trace_hook_destroy(LttvTraceHook *th)
986 {
987 g_array_free(th->fac_index, TRUE);
988 g_array_free(th->fac_list, TRUE);
989 }
990
991
992 LttvTracesetContextPosition *lttv_traceset_context_position_new()
993 {
994 LttvTracesetContextPosition *pos = g_new(LttvTracesetContextPosition,1);
995 pos->ep = g_array_sized_new(FALSE, TRUE, sizeof(LttEventPosition*),
996 10);
997 pos->tfc = g_array_sized_new(FALSE, TRUE, sizeof(LttvTracefileContext*),
998 10);
999 pos->timestamp = ltt_time_infinite;
1000 return pos;
1001 }
1002
1003 /* Save all positions, the ones not in the pqueue will have NULL
1004 * ep. */
1005 void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1006 LttvTracesetContextPosition *pos)
1007 {
1008 guint i;
1009 guint num_traces = lttv_traceset_number(self->ts);
1010
1011 for(i=0; i<num_traces;i++) {
1012 GArray * tracefiles = self->traces[i]->tracefiles;
1013 guint j;
1014 guint num_tracefiles = tracefiles->len;
1015
1016 for(j=0;j<num_tracefiles;j++) {
1017 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1018 LttvTracefileContext*, j);
1019
1020 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1021 LttEventPosition *ep;
1022
1023 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1024 ep = ltt_event_position_new();
1025 ltt_event_position(event, ep);
1026 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1027 pos->timestamp = (*tfc)->timestamp;
1028 } else {
1029 ep = NULL;
1030 }
1031 g_array_append_val(pos->tfc, *tfc);
1032 g_array_append_val(pos->ep, ep);
1033 }
1034
1035 }
1036 }
1037
1038 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1039 {
1040 int i;
1041 LttEventPosition **ep;
1042
1043 for(i=0;i<pos->ep->len;i++) {
1044 ep = &g_array_index(pos->ep, LttEventPosition*, i);
1045 if(*ep != NULL)
1046 g_free(*ep);
1047 }
1048 g_array_free(pos->ep, TRUE);
1049 g_array_free(pos->tfc, TRUE);
1050 g_free(pos);
1051 }
1052
1053 void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1054 const LttvTracesetContextPosition *src)
1055 {
1056 int i;
1057 LttEventPosition **src_ep, **dest_ep;
1058
1059 g_array_set_size(dest->ep, src->ep->len);
1060 g_array_set_size(dest->tfc, src->tfc->len);
1061
1062 for(i=0;i<src->ep->len;i++) {
1063 src_ep = &g_array_index(src->ep, LttEventPosition*, i);
1064 dest_ep = &g_array_index(dest->ep, LttEventPosition*, i);
1065 if(*src_ep != NULL) {
1066 *dest_ep = ltt_event_position_new();
1067 ltt_event_position_copy(
1068 *dest_ep,
1069 *src_ep);
1070 } else
1071 *dest_ep = NULL;
1072 }
1073 for(i=0;i<src->tfc->len;i++) {
1074 g_array_index(dest->tfc, LttvTracefileContext*, i) =
1075 g_array_index(src->tfc, LttvTracefileContext*, i);
1076 }
1077 dest->timestamp = src->timestamp;
1078 }
1079
1080 gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1081 const LttvTracesetContextPosition *pos)
1082 {
1083 int i;
1084 int ret;
1085
1086 for(i=0;i<pos->ep->len;i++) {
1087 LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i);
1088 LttvTracefileContext *tfc =
1089 g_array_index(pos->tfc, LttvTracefileContext*, i);
1090
1091 if(ep == NULL) {
1092 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0) {
1093 ret = -1;
1094 }
1095 } else {
1096 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) == 0) {
1097 ret = 1;
1098 } else {
1099 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
1100
1101 ret = ltt_event_position_compare((LttEventPosition*)event,
1102 ep);
1103 }
1104 }
1105 if(ret != 0) return ret;
1106
1107 }
1108 return 0;
1109 }
1110
1111
1112 gint lttv_traceset_context_pos_pos_compare(
1113 const LttvTracesetContextPosition *pos1,
1114 const LttvTracesetContextPosition *pos2)
1115 {
1116 int i, j;
1117 int ret;
1118
1119 for(i=0;i<pos1->ep->len;i++) {
1120 LttEventPosition *ep1 = g_array_index(pos1->ep, LttEventPosition*, i);
1121 LttvTracefileContext *tfc1 = g_array_index(pos1->tfc,
1122 LttvTracefileContext*, i);
1123
1124 if(ep1 != NULL) {
1125 for(j=0;j<pos2->ep->len;j++) {
1126 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1127 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1128 LttvTracefileContext*, j);
1129 if(tfc1 == tfc2) {
1130 if(ep2 != NULL)
1131 ret = ltt_event_position_compare(ep1, ep2);
1132 else
1133 ret = -1;
1134
1135 if(ret != 0) return ret;
1136 }
1137 }
1138 } else {
1139 for(j=0;j<pos2->ep->len;j++) {
1140 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1141 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1142 LttvTracefileContext*, j);
1143 if(tfc1 == tfc2) {
1144 if(ep2 != NULL) ret = 1;
1145 }
1146 }
1147 }
1148 }
1149 return 0;
1150 }
1151
1152
1153 LttTime lttv_traceset_context_position_get_time(
1154 const LttvTracesetContextPosition *pos)
1155 {
1156 return pos->timestamp;
1157 }
1158
1159
1160 LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1161 {
1162 GTree *pqueue = self->pqueue;
1163 LttvTracefileContext *tfc = NULL;
1164
1165 g_tree_foreach(pqueue, get_first, &tfc);
1166
1167 return tfc;
1168 }
This page took 0.055727 seconds and 4 git commands to generate.