fix seek time
[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_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
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 // self->sync_position = lttv_traceset_context_position_new();
182 for(i = 0 ; i < nb_trace ; i++) {
183 tc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
184 self->traces[i] = tc;
185
186 tc->ts_context = self;
187 tc->index = i;
188 tc->vt = lttv_traceset_get(ts, i);
189 tc->t = lttv_trace(tc->vt);
190 tc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
191 tc->t_a = lttv_trace_attribute(tc->vt);
192 tc->tracefiles = g_array_sized_new(FALSE, TRUE,
193 sizeof(LttvTracefileContext*), 10);
194
195 tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t);
196 if(tracefiles_groups != NULL) {
197 args.func = (ForEachTraceFileFunc)init_tracefile_context;
198 args.func_args = tc;
199
200 g_datalist_foreach(tracefiles_groups,
201 (GDataForeachFunc)compute_tracefile_group,
202 &args);
203 }
204
205 #if 0
206 nb_control = ltt_trace_control_tracefile_number(tc->t);
207 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
208 nb_tracefile = nb_control + nb_per_cpu;
209 tc->tracefiles = g_new(LttvTracefileContext *, nb_tracefile);
210
211 for(j = 0 ; j < nb_tracefile ; j++) {
212 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
213 tc->tracefiles[j] = tfc;
214 tfc->index = j;
215
216 if(j < nb_control) {
217 tfc->control = TRUE;
218 tfc->tf = ltt_trace_control_tracefile_get(tc->t, j);
219 }
220 else {
221 tfc->control = FALSE;
222 tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
223 }
224
225 tfc->t_context = tc;
226 tfc->e = ltt_event_new();
227 tfc->event = lttv_hooks_new();
228 tfc->event_by_id = lttv_hooks_by_id_new();
229 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
230 }
231 #endif //0
232
233 }
234 self->pqueue = g_tree_new(compare_tracefile);
235 lttv_process_traceset_seek_time(self, ltt_time_zero);
236 lttv_traceset_context_compute_time_span(self, &self->time_span);
237
238 }
239
240
241 void fini(LttvTracesetContext *self)
242 {
243 guint i, j, nb_trace, nb_tracefile;
244
245 LttvTraceContext *tc;
246
247 LttvTracefileContext **tfc;
248
249 LttvTraceset *ts = self->ts;
250
251 g_tree_destroy(self->pqueue);
252 g_object_unref(self->a);
253 // lttv_traceset_context_position_destroy(self->sync_position);
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 enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
663
664 /* Note : a _middle must be preceded from a _seek or another middle */
665 guint lttv_process_traceset_middle(LttvTracesetContext *self,
666 LttTime end,
667 guint nb_events,
668 const LttvTracesetContextPosition *end_position)
669 {
670 GTree *pqueue = self->pqueue;
671
672 guint fac_id, ev_id, id;
673
674 LttvTracefileContext *tfc;
675
676 LttEvent *e;
677
678 unsigned count = 0;
679
680 guint read_ret;
681
682 enum read_state last_read_state = LAST_NONE;
683
684 gboolean last_ret = FALSE; /* return value of the last hook list called */
685
686 /* Get the next event from the pqueue, call its hooks,
687 reinsert in the pqueue the following event from the same tracefile
688 unless the tracefile is finished or the event is later than the
689 end time. */
690
691 while(TRUE) {
692 tfc = NULL;
693 g_tree_foreach(pqueue, get_first, &tfc);
694 /* End of traceset : tfc is NULL */
695 if(unlikely(tfc == NULL))
696 {
697 return count;
698 }
699
700 /* Have we reached :
701 * - the maximum number of events specified?
702 * - the end position ?
703 * - the end time ?
704 * then the read is finished. We leave the queue in the same state and
705 * break the loop.
706 */
707
708 if(unlikely(last_ret == TRUE ||
709 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
710 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
711 end_position) == 0)||
712 ltt_time_compare(end, tfc->timestamp) <= 0))
713 {
714 return count;
715 }
716
717 /* Get the tracefile with an event for the smallest time found. If two
718 or more tracefiles have events for the same time, hope that lookup
719 and remove are consistent. */
720
721 #ifdef DEBUG
722 g_debug("test tree before remove");
723 g_tree_foreach(pqueue, test_tree, tfc);
724 #endif //DEBUG
725 g_tree_remove(pqueue, tfc);
726
727 #ifdef DEBUG
728 g_debug("test tree after remove");
729 g_tree_foreach(pqueue, test_tree, tfc);
730 #endif //DEBUG
731
732 e = ltt_tracefile_get_event(tfc->tf);
733
734 if(last_read_state != LAST_EMPTY) {
735 /* Only call hooks if the last read has given an event or if we are at the
736 * first pass (not if last read returned end of tracefile) */
737 count++;
738
739 fac_id = ltt_event_facility_id(e);
740 ev_id = ltt_event_eventtype_id(e);
741 id = GET_HOOK_ID(fac_id, ev_id);
742 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
743 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
744 }
745
746 read_ret = ltt_tracefile_read(tfc->tf);
747
748 if(likely(!read_ret)) {
749 g_debug("An event is ready");
750 tfc->timestamp = ltt_event_time(e);
751
752 g_tree_insert(pqueue, tfc, tfc);
753 last_read_state = LAST_OK;
754 } else {
755 tfc->timestamp = ltt_time_infinite;
756
757 if(read_ret == ERANGE) {
758 last_read_state = LAST_EMPTY;
759 g_debug("End of trace");
760 } else
761 g_error("Error happened in lttv_process_traceset_middle");
762 }
763 }
764 }
765
766
767 void lttv_process_traceset_end(LttvTracesetContext *self,
768 LttvHooks *after_traceset,
769 LttvHooks *after_trace,
770 LttvHooks *after_tracefile,
771 LttvHooks *event,
772 LttvHooksById *event_by_id)
773 {
774 /* Remove hooks from context. _after hooks are called by remove_hooks. */
775 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
776 lttv_traceset_context_remove_hooks(self,
777 after_traceset,
778 after_trace,
779 after_tracefile,
780 event,
781 event_by_id);
782 }
783
784 /* Subtile modification :
785 * if tracefile has no event at or after the time requested, it is not put in
786 * the queue, as the next read would fail. */
787 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
788 {
789 guint i, nb_tracefile;
790
791 gint ret;
792
793 LttvTracefileContext **tfc;
794
795 GTree *pqueue = self->ts_context->pqueue;
796
797 nb_tracefile = self->tracefiles->len;
798
799 for(i = 0 ; i < nb_tracefile ; i++) {
800 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
801
802 g_tree_remove(pqueue, *tfc);
803
804 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
805 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
806
807 if(ret == 0) { /* not ERANGE especially */
808 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
809 g_tree_insert(pqueue, (*tfc), (*tfc));
810 } else {
811 (*tfc)->timestamp = ltt_time_infinite;
812 }
813 }
814 }
815
816
817 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
818 {
819 guint i, nb_trace;
820
821 LttvTraceContext *tc;
822
823 nb_trace = lttv_traceset_number(self->ts);
824 for(i = 0 ; i < nb_trace ; i++) {
825 tc = self->traces[i];
826 lttv_process_trace_seek_time(tc, start);
827 }
828 }
829
830
831 gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
832 const LttvTracesetContextPosition *pos)
833 {
834 guint i;
835
836 g_tree_destroy(self->pqueue);
837 self->pqueue = g_tree_new(compare_tracefile);
838
839 for(i=0;i<pos->ep->len; i++) {
840 LttEventPosition **ep = &g_array_index(pos->ep, LttEventPosition*, i);
841 LttvTracefileContext **tfc =
842 &g_array_index(pos->tfc, LttvTracefileContext*, i);
843 if(*ep != NULL) {
844 if(ltt_tracefile_seek_position((*tfc)->tf, *ep) != 0)
845 return 1;
846 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
847 g_tree_insert(self->pqueue, (*tfc), (*tfc));
848 } else {
849 (*tfc)->timestamp = ltt_time_infinite;
850 }
851 }
852 return 0;
853 }
854
855
856
857 static LttField *
858 find_field(LttEventType *et, const GQuark field)
859 {
860 LttType *t;
861
862 LttField *f;
863
864 guint i, nb;
865
866 GQuark name;
867
868 /* Field is unset */
869 if(field == 0) return NULL;
870
871 f = ltt_eventtype_field(et);
872 t = ltt_eventtype_type(et);
873 g_assert(ltt_type_class(t) == LTT_STRUCT);
874 nb = ltt_type_member_number(t);
875 for(i = 0 ; i < nb ; i++) {
876 ltt_type_member_type(t, i, &name);
877 if(name == field) break;
878 }
879 g_assert(i < nb);
880 return ltt_field_member(f, i);
881 }
882
883 LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
884 guint facility_id)
885 {
886 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
887 }
888
889 /* Get the first facility corresponding to the name. As the types must be
890 * compatible, it is relevant to use the field name and sizes of the first
891 * facility to create data structures and assume the data will be compatible
892 * thorough the trace */
893 LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
894 {
895 g_assert(th->fac_list->len > 0);
896 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
897 }
898
899
900 /* Returns 0 on success, -1 if fails. */
901 gint
902 lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
903 GQuark field1, GQuark field2, GQuark field3, LttvHook h, gpointer hook_data,
904 LttvTraceHook *th)
905 {
906 LttFacility *f;
907
908 LttEventType *et, *first_et;
909
910 GArray *facilities;
911
912 guint i, fac_id, ev_id;
913
914 LttvTraceHookByFacility *thf, *first_thf;
915
916 facilities = ltt_trace_facility_get_by_name(t, facility);
917
918 if(unlikely(facilities == NULL)) goto facility_error;
919
920 th->fac_index = g_array_sized_new(FALSE, TRUE,
921 sizeof(LttvTraceHookByFacility),
922 NUM_FACILITIES);
923 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
924
925 th->fac_list = g_array_sized_new(FALSE, TRUE,
926 sizeof(LttvTraceHookByFacility*),
927 facilities->len);
928 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
929
930 fac_id = g_array_index(facilities, guint, 0);
931 f = ltt_trace_get_facility_by_num(t, fac_id);
932
933 et = ltt_facility_eventtype_get_by_name(f, event);
934 if(unlikely(et == NULL)) goto event_error;
935
936 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
937 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf;
938
939 ev_id = ltt_eventtype_id(et);
940
941 thf->h = h;
942 thf->id = GET_HOOK_ID(fac_id, ev_id);
943 thf->f1 = find_field(et, field1);
944 thf->f2 = find_field(et, field2);
945 thf->f3 = find_field(et, field3);
946 thf->hook_data = hook_data;
947
948 first_thf = thf;
949 first_et = et;
950
951 /* Check for type compatibility too */
952 for(i=1;i<facilities->len;i++) {
953 fac_id = g_array_index(facilities, guint, i);
954 f = ltt_trace_get_facility_by_num(t, fac_id);
955
956 et = ltt_facility_eventtype_get_by_name(f, ltt_eventtype_name(et));
957 if(unlikely(et == NULL)) goto event_error;
958
959 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
960 g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf;
961 ev_id = ltt_eventtype_id(et);
962 thf->h = h;
963 thf->id = GET_HOOK_ID(fac_id, ev_id);
964 thf->f1 = find_field(et, field1);
965 if(check_fields_compatibility(first_et, et,
966 first_thf->f1, thf->f1))
967 goto type_error;
968
969 thf->f2 = find_field(et, field2);
970 if(check_fields_compatibility(first_et, et,
971 first_thf->f2, thf->f2))
972 goto type_error;
973
974 thf->f3 = find_field(et, field3);
975 if(check_fields_compatibility(first_et, et,
976 first_thf->f3, thf->f3))
977 goto type_error;
978 thf->hook_data = hook_data;
979 }
980
981 return 0;
982
983 type_error:
984 goto free;
985 event_error:
986 g_error("Event type %s does not exist",
987 g_quark_to_string(ltt_eventtype_name(et)));
988 goto free;
989 facility_error:
990 g_error("No %s facility", g_quark_to_string(facility));
991 goto free;
992 free:
993 g_array_free(th->fac_index, TRUE);
994 g_array_free(th->fac_list, TRUE);
995 th->fac_index = NULL;
996 th->fac_list = NULL;
997 return -1;
998 }
999
1000 void lttv_trace_hook_destroy(LttvTraceHook *th)
1001 {
1002 g_array_free(th->fac_index, TRUE);
1003 g_array_free(th->fac_list, TRUE);
1004 }
1005
1006
1007 LttvTracesetContextPosition *lttv_traceset_context_position_new()
1008 {
1009 LttvTracesetContextPosition *pos = g_new(LttvTracesetContextPosition,1);
1010 pos->ep = g_array_sized_new(FALSE, TRUE, sizeof(LttEventPosition*),
1011 10);
1012 pos->tfc = g_array_sized_new(FALSE, TRUE, sizeof(LttvTracefileContext*),
1013 10);
1014 pos->timestamp = ltt_time_infinite;
1015 return pos;
1016 }
1017
1018 /* Save all positions, the ones not in the pqueue will have NULL
1019 * ep. */
1020 void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1021 LttvTracesetContextPosition *pos)
1022 {
1023 guint i;
1024 guint num_traces = lttv_traceset_number(self->ts);
1025
1026 for(i=0; i<num_traces;i++) {
1027 GArray * tracefiles = self->traces[i]->tracefiles;
1028 guint j;
1029 guint num_tracefiles = tracefiles->len;
1030
1031 for(j=0;j<num_tracefiles;j++) {
1032 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1033 LttvTracefileContext*, j);
1034
1035 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1036 LttEventPosition *ep;
1037
1038 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1039 ep = ltt_event_position_new();
1040 ltt_event_position(event, ep);
1041 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1042 pos->timestamp = (*tfc)->timestamp;
1043 } else {
1044 ep = NULL;
1045 }
1046 g_array_append_val(pos->tfc, *tfc);
1047 g_array_append_val(pos->ep, ep);
1048 }
1049
1050 }
1051 }
1052
1053 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1054 {
1055 int i;
1056 LttEventPosition **ep;
1057
1058 for(i=0;i<pos->ep->len;i++) {
1059 ep = &g_array_index(pos->ep, LttEventPosition*, i);
1060 if(*ep != NULL)
1061 g_free(*ep);
1062 }
1063 g_array_free(pos->ep, TRUE);
1064 g_array_free(pos->tfc, TRUE);
1065 g_free(pos);
1066 }
1067
1068 void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1069 const LttvTracesetContextPosition *src)
1070 {
1071 int i;
1072 LttEventPosition **src_ep, **dest_ep;
1073
1074 g_array_set_size(dest->ep, src->ep->len);
1075 g_array_set_size(dest->tfc, src->tfc->len);
1076
1077 for(i=0;i<src->ep->len;i++) {
1078 src_ep = &g_array_index(src->ep, LttEventPosition*, i);
1079 dest_ep = &g_array_index(dest->ep, LttEventPosition*, i);
1080 if(*src_ep != NULL) {
1081 *dest_ep = ltt_event_position_new();
1082 ltt_event_position_copy(
1083 *dest_ep,
1084 *src_ep);
1085 } else
1086 *dest_ep = NULL;
1087 }
1088 for(i=0;i<src->tfc->len;i++) {
1089 g_array_index(dest->tfc, LttvTracefileContext*, i) =
1090 g_array_index(src->tfc, LttvTracefileContext*, i);
1091 }
1092 dest->timestamp = src->timestamp;
1093 }
1094
1095 gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1096 const LttvTracesetContextPosition *pos)
1097 {
1098 int i;
1099 int ret = 0;
1100
1101 if(pos->ep->len == 0) {
1102 if(lttv_traceset_number(self->ts) == 0) return 0;
1103 else return 1;
1104 }
1105 if(lttv_traceset_number(self->ts) == 0)
1106 return -1;
1107
1108 for(i=0;i<pos->ep->len;i++) {
1109 LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i);
1110 LttvTracefileContext *tfc =
1111 g_array_index(pos->tfc, LttvTracefileContext*, i);
1112
1113 if(ep == NULL) {
1114 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0) {
1115 ret = -1;
1116 }
1117 } else {
1118 if(ltt_time_compare(tfc->timestamp, ltt_time_infinite) == 0) {
1119 ret = 1;
1120 } else {
1121 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
1122
1123 ret = ltt_event_position_compare((LttEventPosition*)event,
1124 ep);
1125 }
1126 }
1127 if(ret != 0) return ret;
1128
1129 }
1130 return 0;
1131 }
1132
1133
1134 gint lttv_traceset_context_pos_pos_compare(
1135 const LttvTracesetContextPosition *pos1,
1136 const LttvTracesetContextPosition *pos2)
1137 {
1138 int i, j;
1139 int ret;
1140
1141 if(pos1->ep->len == 0) {
1142 if(pos2->ep->len == 0) return 0;
1143 else return 1;
1144 }
1145 if(pos2->ep->len == 0)
1146 return -1;
1147
1148 for(i=0;i<pos1->ep->len;i++) {
1149 LttEventPosition *ep1 = g_array_index(pos1->ep, LttEventPosition*, i);
1150 LttvTracefileContext *tfc1 = g_array_index(pos1->tfc,
1151 LttvTracefileContext*, i);
1152
1153 if(ep1 != NULL) {
1154 for(j=0;j<pos2->ep->len;j++) {
1155 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1156 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1157 LttvTracefileContext*, j);
1158 if(tfc1 == tfc2) {
1159 if(ep2 != NULL)
1160 ret = ltt_event_position_compare(ep1, ep2);
1161 else
1162 ret = -1;
1163
1164 if(ret != 0) return ret;
1165 }
1166 }
1167 } else {
1168 for(j=0;j<pos2->ep->len;j++) {
1169 LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j);
1170 LttvTracefileContext *tfc2 = g_array_index(pos2->tfc,
1171 LttvTracefileContext*, j);
1172 if(tfc1 == tfc2) {
1173 if(ep2 != NULL) ret = 1;
1174 }
1175 }
1176 }
1177 }
1178 return 0;
1179 }
1180
1181
1182 LttTime lttv_traceset_context_position_get_time(
1183 const LttvTracesetContextPosition *pos)
1184 {
1185 return pos->timestamp;
1186 }
1187
1188
1189 LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1190 {
1191 GTree *pqueue = self->pqueue;
1192 LttvTracefileContext *tfc = NULL;
1193
1194 g_tree_foreach(pqueue, get_first, &tfc);
1195
1196 return tfc;
1197 }
1198 #if 0
1199 /* lttv_process_traceset_synchronize_tracefiles
1200 *
1201 * Use the sync_position field of the trace set context to synchronize each
1202 * tracefile with the previously saved position.
1203 *
1204 * If no previous position has been saved, it simply does nothing.
1205 */
1206 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1207 {
1208 g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
1209 }
1210
1211
1212
1213
1214 void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1215 {
1216 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1217 }
1218
1219 #endif //0
1220
This page took 0.053953 seconds and 5 git commands to generate.