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