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