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