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