fix unexisting trace error path
[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;
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 if(tracefiles_groups != NULL) {
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
204 #if 0
205 nb_control = ltt_trace_control_tracefile_number(tc->t);
206 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
207 nb_tracefile = nb_control + nb_per_cpu;
208 tc->tracefiles = g_new(LttvTracefileContext *, nb_tracefile);
209
210 for(j = 0 ; j < nb_tracefile ; j++) {
211 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
212 tc->tracefiles[j] = tfc;
213 tfc->index = j;
214
215 if(j < nb_control) {
216 tfc->control = TRUE;
217 tfc->tf = ltt_trace_control_tracefile_get(tc->t, j);
218 }
219 else {
220 tfc->control = FALSE;
221 tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
222 }
223
224 tfc->t_context = tc;
225 tfc->e = ltt_event_new();
226 tfc->event = lttv_hooks_new();
227 tfc->event_by_id = lttv_hooks_by_id_new();
228 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
229 }
230 #endif //0
231
232 }
233 self->pqueue = g_tree_new(compare_tracefile);
234 lttv_process_traceset_seek_time(self, ltt_time_zero);
235 lttv_traceset_context_compute_time_span(self, &self->time_span);
236
237 }
238
239
240 void fini(LttvTracesetContext *self)
241 {
242 guint i, j, nb_trace, nb_tracefile;
243
244 LttvTraceContext *tc;
245
246 LttvTracefileContext **tfc;
247
248 LttvTraceset *ts = self->ts;
249
250 //FIXME : segfault
251
252 g_tree_destroy(self->pqueue);
253 g_object_unref(self->a);
254
255 nb_trace = lttv_traceset_number(ts);
256
257 for(i = 0 ; i < nb_trace ; i++) {
258 tc = self->traces[i];
259
260 g_object_unref(tc->a);
261
262 nb_tracefile = tc->tracefiles->len;
263
264 for(j = 0 ; j < nb_tracefile ; j++) {
265 tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, j);
266 lttv_hooks_destroy((*tfc)->event);
267 lttv_hooks_by_id_destroy((*tfc)->event_by_id);
268 g_object_unref((*tfc)->a);
269 g_object_unref(*tfc);
270 }
271 g_array_free(tc->tracefiles, TRUE);
272 g_object_unref(tc);
273 }
274 g_free(self->traces);
275 }
276
277
278 void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
279 LttvHooks *before_traceset,
280 LttvHooks *before_trace,
281 LttvHooks *before_tracefile,
282 LttvHooks *event,
283 LttvHooksById *event_by_id)
284 {
285 LttvTraceset *ts = self->ts;
286
287 guint i, nb_trace;
288
289 LttvTraceContext *tc;
290
291 lttv_hooks_call(before_traceset, self);
292
293 nb_trace = lttv_traceset_number(ts);
294
295 for(i = 0 ; i < nb_trace ; i++) {
296 tc = self->traces[i];
297 lttv_trace_context_add_hooks(tc,
298 before_trace,
299 before_tracefile,
300 event,
301 event_by_id);
302 }
303 }
304
305
306 void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
307 LttvHooks *after_traceset,
308 LttvHooks *after_trace,
309 LttvHooks *after_tracefile,
310 LttvHooks *event,
311 LttvHooksById *event_by_id)
312 {
313
314 LttvTraceset *ts = self->ts;
315
316 guint i, nb_trace;
317
318 LttvTraceContext *tc;
319
320 nb_trace = lttv_traceset_number(ts);
321
322 for(i = 0 ; i < nb_trace ; i++) {
323 tc = self->traces[i];
324 lttv_trace_context_remove_hooks(tc,
325 after_trace,
326 after_tracefile,
327 event,
328 event_by_id);
329 }
330
331 lttv_hooks_call(after_traceset, self);
332
333
334 }
335
336 void lttv_trace_context_add_hooks(LttvTraceContext *self,
337 LttvHooks *before_trace,
338 LttvHooks *before_tracefile,
339 LttvHooks *event,
340 LttvHooksById *event_by_id)
341 {
342 guint i, nb_tracefile;
343
344 LttvTracefileContext **tfc;
345
346 lttv_hooks_call(before_trace, self);
347
348 nb_tracefile = self->tracefiles->len;
349
350 for(i = 0 ; i < nb_tracefile ; i++) {
351 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
352 lttv_tracefile_context_add_hooks(*tfc,
353 before_tracefile,
354 event,
355 event_by_id);
356 }
357 }
358
359
360
361 void lttv_trace_context_remove_hooks(LttvTraceContext *self,
362 LttvHooks *after_trace,
363 LttvHooks *after_tracefile,
364 LttvHooks *event,
365 LttvHooksById *event_by_id)
366 {
367 guint i, nb_tracefile;
368
369 LttvTracefileContext **tfc;
370
371 nb_tracefile = self->tracefiles->len;
372
373 for(i = 0 ; i < nb_tracefile ; i++) {
374 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
375 lttv_tracefile_context_remove_hooks(*tfc,
376 after_tracefile,
377 event,
378 event_by_id);
379 }
380
381 lttv_hooks_call(after_trace, self);
382 }
383
384 void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
385 LttvHooks *before_tracefile,
386 LttvHooks *event,
387 LttvHooksById *event_by_id)
388 {
389 guint i, index;
390
391 LttvHooks *hook;
392
393 lttv_hooks_call(before_tracefile, self);
394 lttv_hooks_add_list(self->event, event);
395 if(event_by_id != NULL) {
396 for(i = 0; i < event_by_id->array->len; i++) {
397 index = g_array_index(event_by_id->array, guint, i);
398 hook = lttv_hooks_by_id_find(self->event_by_id, index);
399 lttv_hooks_add_list(hook, lttv_hooks_by_id_get(event_by_id, index));
400 }
401 }
402 }
403
404 void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
405 LttvHooks *after_tracefile,
406 LttvHooks *event,
407 LttvHooksById *event_by_id)
408 {
409 guint i, index;
410
411 LttvHooks *hook;
412
413 lttv_hooks_remove_list(self->event, event);
414 if(event_by_id != NULL) {
415 for(i = 0; i < event_by_id->array->len; i++) {
416 index = g_array_index(event_by_id->array, guint, i);
417 hook = lttv_hooks_by_id_get(self->event_by_id, index);
418 if(hook != NULL)
419 lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, index));
420 }
421 }
422
423 lttv_hooks_call(after_tracefile, self);
424 }
425
426
427
428 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext *tfc,
429 unsigned i,
430 LttvHooks *event_by_id)
431 {
432 LttvHooks * h;
433 h = lttv_hooks_by_id_find(tfc->event_by_id, i);
434 lttv_hooks_add_list(h, event_by_id);
435 }
436
437 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext *tfc,
438 unsigned i)
439 {
440 lttv_hooks_by_id_remove(tfc->event_by_id, i);
441 }
442
443 static LttvTracesetContext *
444 new_traceset_context(LttvTracesetContext *self)
445 {
446 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
447 }
448
449
450 static LttvTraceContext *
451 new_trace_context(LttvTracesetContext *self)
452 {
453 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
454 }
455
456
457 static LttvTracefileContext *
458 new_tracefile_context(LttvTracesetContext *self)
459 {
460 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
461 }
462
463
464 static void
465 traceset_context_instance_init (GTypeInstance *instance, gpointer g_class)
466 {
467 /* Be careful of anything which would not work well with shallow copies */
468 }
469
470
471 static void
472 traceset_context_finalize (LttvTracesetContext *self)
473 {
474 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE)))
475 ->finalize(G_OBJECT(self));
476 }
477
478
479 static void
480 traceset_context_class_init (LttvTracesetContextClass *klass)
481 {
482 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
483
484 gobject_class->finalize = (void (*)(GObject *self))traceset_context_finalize;
485 klass->init = init;
486 klass->fini = fini;
487 klass->new_traceset_context = new_traceset_context;
488 klass->new_trace_context = new_trace_context;
489 klass->new_tracefile_context = new_tracefile_context;
490 }
491
492
493 GType
494 lttv_traceset_context_get_type(void)
495 {
496 static GType type = 0;
497 if (type == 0) {
498 static const GTypeInfo info = {
499 sizeof (LttvTracesetContextClass),
500 NULL, /* base_init */
501 NULL, /* base_finalize */
502 (GClassInitFunc) traceset_context_class_init, /* class_init */
503 NULL, /* class_finalize */
504 NULL, /* class_data */
505 sizeof (LttvTracesetContext),
506 0, /* n_preallocs */
507 (GInstanceInitFunc) traceset_context_instance_init, /* instance_init */
508 NULL /* Value handling */
509 };
510
511 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType",
512 &info, 0);
513 }
514 return type;
515 }
516
517
518 static void
519 trace_context_instance_init (GTypeInstance *instance, gpointer g_class)
520 {
521 /* Be careful of anything which would not work well with shallow copies */
522 }
523
524
525 static void
526 trace_context_finalize (LttvTraceContext *self)
527 {
528 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))->
529 finalize(G_OBJECT(self));
530 }
531
532
533 static void
534 trace_context_class_init (LttvTraceContextClass *klass)
535 {
536 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
537
538 gobject_class->finalize = (void (*)(GObject *self)) trace_context_finalize;
539 }
540
541
542 GType
543 lttv_trace_context_get_type(void)
544 {
545 static GType type = 0;
546 if (type == 0) {
547 static const GTypeInfo info = {
548 sizeof (LttvTraceContextClass),
549 NULL, /* base_init */
550 NULL, /* base_finalize */
551 (GClassInitFunc) trace_context_class_init, /* class_init */
552 NULL, /* class_finalize */
553 NULL, /* class_data */
554 sizeof (LttvTraceContext),
555 0, /* n_preallocs */
556 (GInstanceInitFunc) trace_context_instance_init, /* instance_init */
557 NULL /* Value handling */
558 };
559
560 type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType",
561 &info, 0);
562 }
563 return type;
564 }
565
566
567 static void
568 tracefile_context_instance_init (GTypeInstance *instance, gpointer g_class)
569 {
570 /* Be careful of anything which would not work well with shallow copies */
571 }
572
573
574 static void
575 tracefile_context_finalize (LttvTracefileContext *self)
576 {
577 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE)))
578 ->finalize(G_OBJECT(self));
579 }
580
581
582 static void
583 tracefile_context_class_init (LttvTracefileContextClass *klass)
584 {
585 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
586
587 gobject_class->finalize = (void (*)(GObject *self))tracefile_context_finalize;
588 }
589
590
591 GType
592 lttv_tracefile_context_get_type(void)
593 {
594 static GType type = 0;
595 if (type == 0) {
596 static const GTypeInfo info = {
597 sizeof (LttvTracefileContextClass),
598 NULL, /* base_init */
599 NULL, /* base_finalize */
600 (GClassInitFunc) tracefile_context_class_init, /* class_init */
601 NULL, /* class_finalize */
602 NULL, /* class_data */
603 sizeof (LttvTracefileContext),
604 0, /* n_preallocs */
605 (GInstanceInitFunc) tracefile_context_instance_init, /* instance_init */
606 NULL /* Value handling */
607 };
608
609 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType",
610 &info, 0);
611 }
612 return type;
613 }
614
615
616
617 static gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
618 g_assert(key == value);
619 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
620 return TRUE;
621 }
622
623 static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) {
624
625 LttvTracefileContext *tfc = (LttvTracefileContext *)key;
626
627 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
628 g_quark_to_string(ltt_tracefile_name(tfc->tf)),
629 tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec,
630 tfc->index, tfc->t_context->index);
631
632 if(((LttvTracefileContext *)user_data) == (LttvTracefileContext *)value) {
633 g_assert(compare_tracefile(user_data, value) == 0);
634 } else
635 g_assert(compare_tracefile(user_data, value) != 0);
636
637 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
638 return FALSE;
639 }
640
641
642
643 void lttv_process_traceset_begin(LttvTracesetContext *self,
644 LttvHooks *before_traceset,
645 LttvHooks *before_trace,
646 LttvHooks *before_tracefile,
647 LttvHooks *event,
648 LttvHooksById *event_by_id)
649 {
650
651 /* simply add hooks in context. _before hooks are called by add_hooks. */
652 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
653 lttv_traceset_context_add_hooks(self,
654 before_traceset,
655 before_trace,
656 before_tracefile,
657 event,
658 event_by_id);
659
660 }
661
662 /* Note : a _middle must be preceded from a _seek or another middle */
663 guint lttv_process_traceset_middle(LttvTracesetContext *self,
664 LttTime end,
665 guint nb_events,
666 const LttvTracesetContextPosition *end_position)
667 {
668 GTree *pqueue = self->pqueue;
669
670 guint fac_id, ev_id, id;
671
672 LttvTracefileContext *tfc;
673
674 LttEvent *e;
675
676 unsigned count = 0;
677
678 guint read_ret = FALSE;
679
680 gboolean last_ret = FALSE; /* return value of the last hook list called */
681
682 /* Get the next event from the pqueue, call its hooks,
683 reinsert in the pqueue the following event from the same tracefile
684 unless the tracefile is finished or the event is later than the
685 end time. */
686
687 while(TRUE) {
688 tfc = NULL;
689 g_tree_foreach(pqueue, get_first, &tfc);
690 /* End of traceset : tfc is NULL */
691 if(unlikely(tfc == NULL))
692 {
693 return count;
694 }
695
696 /* Have we reached :
697 * - the maximum number of events specified?
698 * - the end position ?
699 * - the end time ?
700 * then the read is finished. We leave the queue in the same state and
701 * break the loop.
702 */
703
704 if(unlikely(last_ret == TRUE ||
705 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
706 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
707 end_position) == 0)||
708 ltt_time_compare(end, tfc->timestamp) <= 0))
709 {
710 return count;
711 }
712
713 /* Get the tracefile with an event for the smallest time found. If two
714 or more tracefiles have events for the same time, hope that lookup
715 and remove are consistent. */
716
717 #ifdef DEBUG
718 g_debug("test tree before remove");
719 g_tree_foreach(pqueue, test_tree, tfc);
720 #endif //DEBUG
721 g_tree_remove(pqueue, tfc);
722
723 #ifdef DEBUG
724 g_debug("test tree after remove");
725 g_tree_foreach(pqueue, test_tree, tfc);
726 #endif //DEBUG
727
728 count++;
729
730 e = ltt_tracefile_get_event(tfc->tf);
731 fac_id = ltt_event_facility_id(e);
732 ev_id = ltt_event_eventtype_id(e);
733 id = GET_HOOK_ID(fac_id, ev_id);
734 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
735 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
736
737 read_ret = ltt_tracefile_read(tfc->tf);
738
739 if(likely(!read_ret)) {
740 g_debug("An event is ready");
741 tfc->timestamp = ltt_event_time(e);
742
743 g_tree_insert(pqueue, tfc, tfc);
744 } else {
745 tfc->timestamp = ltt_time_infinite;
746
747 if(read_ret == ERANGE)
748 g_debug("End of trace");
749 else
750 g_error("Error happened in lttv_process_traceset_middle");
751 }
752 }
753 }
754
755
756 void lttv_process_traceset_end(LttvTracesetContext *self,
757 LttvHooks *after_traceset,
758 LttvHooks *after_trace,
759 LttvHooks *after_tracefile,
760 LttvHooks *event,
761 LttvHooksById *event_by_id)
762 {
763 /* Remove hooks from context. _after hooks are called by remove_hooks. */
764 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
765 lttv_traceset_context_remove_hooks(self,
766 after_traceset,
767 after_trace,
768 after_tracefile,
769 event,
770 event_by_id);
771 }
772
773 /* Subtile modification :
774 * if tracefile has no event at or after the time requested, it is not put in
775 * the queue, as the next read would fail. */
776 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
777 {
778 guint i, nb_tracefile;
779
780 gint ret;
781
782 LttvTracefileContext **tfc;
783
784 GTree *pqueue = self->ts_context->pqueue;
785
786 nb_tracefile = self->tracefiles->len;
787
788 for(i = 0 ; i < nb_tracefile ; i++) {
789 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
790
791 g_tree_remove(pqueue, *tfc);
792
793 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
794 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
795
796 if(ret == 0) { /* not ERANGE especially */
797 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
798 g_tree_insert(pqueue, (*tfc), (*tfc));
799 } else {
800 (*tfc)->timestamp = ltt_time_infinite;
801 }
802 }
803 }
804
805
806 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
807 {
808 guint i, nb_trace;
809
810 LttvTraceContext *tc;
811
812 nb_trace = lttv_traceset_number(self->ts);
813 for(i = 0 ; i < nb_trace ; i++) {
814 tc = self->traces[i];
815 lttv_process_trace_seek_time(tc, start);
816 }
817 }
818
819
820 gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
821 const LttvTracesetContextPosition *pos)
822 {
823 guint i;
824 LttvTraceContext *tc;
825 LttvTracefileContext *tfc;
826
827 g_tree_destroy(self->pqueue);
828 self->pqueue = g_tree_new(compare_tracefile);
829
830 for(i=0;i<pos->ep->len; i++) {
831 LttEventPosition **ep = &g_array_index(pos->ep, LttEventPosition*, i);
832 LttvTracefileContext **tfc =
833 &g_array_index(pos->tfc, LttvTracefileContext*, i);
834 if(*ep != NULL) {
835 g_assert(ltt_tracefile_seek_position((*tfc)->tf, *ep) == 0);
836 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
837 g_tree_insert(self->pqueue, (*tfc), (*tfc));
838 } else {
839 (*tfc)->timestamp = ltt_time_infinite;
840 }
841 }
842 return TRUE;
843 }
844
845
846
847 static LttField *
848 find_field(LttEventType *et, const GQuark field)
849 {
850 LttType *t;
851
852 LttField *f;
853
854 guint i, nb;
855
856 GQuark name;
857
858 /* Field is unset */
859 if(field == 0) return NULL;
860
861 f = ltt_eventtype_field(et);
862 t = ltt_eventtype_type(et);
863 g_assert(ltt_type_class(t) == LTT_STRUCT);
864 nb = ltt_type_member_number(t);
865 for(i = 0 ; i < nb ; i++) {
866 ltt_type_member_type(t, i, &name);
867 if(name == field) break;
868 }
869 g_assert(i < nb);
870 return ltt_field_member(f, i);
871 }
872
873 LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
874 guint facility_id)
875 {
876 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
877 }
878
879 /* Get the first facility corresponding to the name. As the types must be
880 * compatible, it is relevant to use the field name and sizes of the first
881 * facility to create data structures and assume the data will be compatible
882 * thorough the trace */
883 LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
884 {
885 g_assert(th->fac_list->len > 0);
886 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
887 }
888
889
890 /* Returns 0 on success, -1 if fails. */
891 gint
892 lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
893 GQuark field1, GQuark field2, GQuark field3, LttvHook h, LttvTraceHook *th)
894 {
895 LttFacility *f;
896
897 LttEventType *et, *first_et;
898
899 GArray *facilities;
900
901 guint i, fac_id, ev_id;
902
903 LttvTraceHookByFacility *thf, *first_thf;
904
905 facilities = ltt_trace_facility_get_by_name(t, facility);
906
907 if(unlikely(facilities == NULL)) goto facility_error;
908
909 th->fac_index = g_array_sized_new(FALSE, TRUE,
910 sizeof(LttvTraceHookByFacility),
911 NUM_FACILITIES);
912 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
913
914 th->fac_list = g_array_sized_new(FALSE, TRUE,
915 sizeof(LttvTraceHookByFacility*),
916 facilities->len);
917 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
918
919 fac_id = g_array_index(facilities, guint, 0);
920 f = ltt_trace_get_facility_by_num(t, fac_id);
921
922 et = ltt_facility_eventtype_get_by_name(f, event);
923 if(unlikely(et == NULL)) goto event_error;
924
925 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
926 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf;
927
928 ev_id = ltt_eventtype_id(et);
929
930 thf->h = h;
931 thf->id = GET_HOOK_ID(fac_id, ev_id);
932 thf->f1 = find_field(et, field1);
933 thf->f2 = find_field(et, field2);
934 thf->f3 = find_field(et, field3);
935
936 first_thf = thf;
937
938 /* Check for type compatibility too */
939 for(i=1;i<facilities->len;i++) {
940 fac_id = g_array_index(facilities, guint, i);
941 f = ltt_trace_get_facility_by_num(t, fac_id);
942
943 et = ltt_facility_eventtype_get_by_name(f, ltt_eventtype_name(et));
944 if(unlikely(et == NULL)) goto event_error;
945
946 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
947 g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf;
948 ev_id = ltt_eventtype_id(et);
949 thf->h = h;
950 thf->id = GET_HOOK_ID(fac_id, ev_id);
951 thf->f1 = find_field(et, field1);
952 if(check_fields_compatibility(first_et, et,
953 first_thf->f1, thf->f1))
954 goto type_error;
955
956 thf->f2 = find_field(et, field2);
957 if(check_fields_compatibility(first_et, et,
958 first_thf->f2, thf->f2))
959 goto type_error;
960
961 thf->f3 = find_field(et, field3);
962 if(check_fields_compatibility(first_et, et,
963 first_thf->f3, thf->f3))
964 goto type_error;
965 }
966
967 return 0;
968
969 type_error:
970 goto free;
971 event_error:
972 g_error("Event type %s does not exist",
973 g_quark_to_string(ltt_eventtype_name(et)));
974 goto free;
975 facility_error:
976 g_error("No %s facility", g_quark_to_string(facility));
977 goto free;
978 free:
979 g_array_free(th->fac_index, TRUE);
980 g_array_free(th->fac_list, TRUE);
981 th->fac_index = NULL;
982 th->fac_list = NULL;
983 return -1;
984 }
985
986 void lttv_trace_hook_destroy(LttvTraceHook *th)
987 {
988 g_array_free(th->fac_index, TRUE);
989 g_array_free(th->fac_list, TRUE);
990 }
991
992
993 LttvTracesetContextPosition *lttv_traceset_context_position_new()
994 {
995 LttvTracesetContextPosition *pos = g_new(LttvTracesetContextPosition,1);
996 pos->ep = g_array_sized_new(FALSE, TRUE, sizeof(LttEventPosition*),
997 10);
998 pos->tfc = g_array_sized_new(FALSE, TRUE, sizeof(LttvTracefileContext*),
999 10);
1000 pos->timestamp = ltt_time_infinite;
1001 return pos;
1002 }
1003
1004 /* Save all positions, the ones not in the pqueue will have NULL
1005 * ep. */
1006 void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1007 LttvTracesetContextPosition *pos)
1008 {
1009 guint i;
1010 guint num_traces = lttv_traceset_number(self->ts);
1011
1012 for(i=0; i<num_traces;i++) {
1013 GArray * tracefiles = self->traces[i]->tracefiles;
1014 guint j;
1015 guint num_tracefiles = tracefiles->len;
1016
1017 for(j=0;j<num_tracefiles;j++) {
1018 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1019 LttvTracefileContext*, j);
1020
1021 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1022 LttEventPosition *ep;
1023
1024 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1025 ep = ltt_event_position_new();
1026 ltt_event_position(event, ep);
1027 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1028 pos->timestamp = (*tfc)->timestamp;
1029 } else {
1030 ep = NULL;
1031 }
1032 g_array_append_val(pos->tfc, *tfc);
1033 g_array_append_val(pos->ep, ep);
1034 }
1035
1036 }
1037 }
1038
1039 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1040 {
1041 int i;
1042 LttEventPosition **ep;
1043
1044 for(i=0;i<pos->ep->len;i++) {
1045 ep = &g_array_index(pos->ep, LttEventPosition*, i);
1046 if(*ep != NULL)
1047 g_free(*ep);
1048 }
1049 g_array_free(pos->ep, TRUE);
1050 g_array_free(pos->tfc, TRUE);
1051 g_free(pos);
1052 }
1053
1054 void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1055 const LttvTracesetContextPosition *src)
1056 {
1057 int i;
1058 LttEventPosition **src_ep, **dest_ep;
1059
1060 g_array_set_size(dest->ep, src->ep->len);
1061 g_array_set_size(dest->tfc, src->tfc->len);
1062
1063 for(i=0;i<src->ep->len;i++) {
1064 src_ep = &g_array_index(src->ep, LttEventPosition*, i);
1065 dest_ep = &g_array_index(dest->ep, LttEventPosition*, i);
1066 if(*src_ep != NULL) {
1067 *dest_ep = ltt_event_position_new();
1068 ltt_event_position_copy(
1069 *dest_ep,
1070 *src_ep);
1071 } else
1072 *dest_ep = NULL;
1073 }
1074 for(i=0;i<src->tfc->len;i++) {
1075 g_array_index(dest->tfc, LttvTracefileContext*, i) =
1076 g_array_index(src->tfc, LttvTracefileContext*, i);
1077 }
1078 dest->timestamp = src->timestamp;
1079 }
1080
1081 gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1082 const LttvTracesetContextPosition *pos)
1083 {
1084 int i;
1085 int ret;
1086
1087 for(i=0;i<pos->ep->len;i++) {
1088 LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i);
1089 LttvTracefileContext *tfc =
1090 g_array_index(pos->tfc, LttvTracefileContext*, i);
1091
1092 if(ep == NULL) {
1093 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0) {
1094 ret = -1;
1095 }
1096 } else {
1097 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) == 0) {
1098 ret = 1;
1099 } else {
1100 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
1101
1102 ret = ltt_event_position_compare((LttEventPosition*)event,
1103 ep);
1104 }
1105 }
1106 if(ret != 0) return ret;
1107
1108 }
1109 return 0;
1110 }
1111
1112
1113 gint lttv_traceset_context_pos_pos_compare(
1114 const LttvTracesetContextPosition *pos1,
1115 const LttvTracesetContextPosition *pos2)
1116 {
1117 int i, j;
1118 int ret;
1119
1120 for(i=0;i<pos1->ep->len;i++) {
1121 LttEventPosition *ep1 = g_array_index(pos1->ep, LttEventPosition*, i);
1122 LttvTracefileContext *tfc1 = g_array_index(pos1->tfc,
1123 LttvTracefileContext*, i);
1124
1125 if(ep1 != NULL) {
1126 for(j=0;j<pos2->ep->len;j++) {
1127 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1128 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1129 LttvTracefileContext*, j);
1130 if(tfc1 == tfc2) {
1131 if(ep2 != NULL)
1132 ret = ltt_event_position_compare(ep1, ep2);
1133 else
1134 ret = -1;
1135
1136 if(ret != 0) return ret;
1137 }
1138 }
1139 } else {
1140 for(j=0;j<pos2->ep->len;j++) {
1141 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1142 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1143 LttvTracefileContext*, j);
1144 if(tfc1 == tfc2) {
1145 if(ep2 != NULL) ret = 1;
1146 }
1147 }
1148 }
1149 }
1150 return 0;
1151 }
1152
1153
1154 LttTime lttv_traceset_context_position_get_time(
1155 const LttvTracesetContextPosition *pos)
1156 {
1157 return pos->timestamp;
1158 }
1159
1160
1161 LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1162 {
1163 GTree *pqueue = self->pqueue;
1164 LttvTracefileContext *tfc = NULL;
1165
1166 g_tree_foreach(pqueue, get_first, &tfc);
1167
1168 return tfc;
1169 }
This page took 0.052296 seconds and 5 git commands to generate.