move everything out of trunk
[lttv.git] / lttng-xenomai / LinuxTraceToolkitViewer-0.8.61-xenoltt / 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/lttv.h>
25 #include <lttv/tracecontext.h>
26 #include <ltt/event.h>
27 #include <ltt/facility.h>
28 #include <ltt/trace.h>
29 #include <ltt/type.h>
30 #include <lttv/filter.h>
31 #include <errno.h>
32
33 #define min(a,b) (((a)<(b))?(a):(b))
34
35
36 gint compare_tracefile(gconstpointer a, gconstpointer b)
37 {
38 gint comparison = 0;
39
40 const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
41 const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
42
43 if(likely(trace_a != trace_b)) {
44 comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
45 if(unlikely(comparison == 0)) {
46 if(trace_a->index < trace_b->index) comparison = -1;
47 else if(trace_a->index > trace_b->index) comparison = 1;
48 else if(trace_a->t_context->index < trace_b->t_context->index)
49 comparison = -1;
50 else if(trace_a->t_context->index > trace_b->t_context->index)
51 comparison = 1;
52 }
53 }
54 return comparison;
55 }
56
57 typedef struct _LttvTracefileContextPosition {
58 LttEventPosition *event;
59 LttvTracefileContext *tfc;
60 gboolean used; /* Tells if the tfc is at end of traceset position */
61 } LttvTracefileContextPosition;
62
63
64 struct _LttvTracesetContextPosition {
65 GArray *tfcp; /* Array of LttvTracefileContextPosition */
66 LttTime timestamp; /* Current time at the saved position */
67 /* If ltt_time_infinite : no position is
68 * set, else, a position is set (may be end
69 * of trace, with ep->len == 0) */
70 };
71
72 void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
73 {
74 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
75 }
76
77
78 void lttv_context_fini(LttvTracesetContext *self)
79 {
80 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
81 }
82
83
84 LttvTracesetContext *
85 lttv_context_new_traceset_context(LttvTracesetContext *self)
86 {
87 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
88 }
89
90
91
92
93 LttvTraceContext *
94 lttv_context_new_trace_context(LttvTracesetContext *self)
95 {
96 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
97 }
98
99
100 LttvTracefileContext *
101 lttv_context_new_tracefile_context(LttvTracesetContext *self)
102 {
103 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
104 }
105
106 /****************************************************************************
107 * lttv_traceset_context_compute_time_span
108 *
109 * Keep the time span is sync with on the fly addition and removal of traces
110 * in a trace set. It must be called each time a trace is added/removed from
111 * the traceset. It could be more efficient to call it only once a bunch
112 * of traces are loaded, but the calculation is not long, so it's not
113 * critical.
114 *
115 * Author : Xang Xiu Yang
116 ***************************************************************************/
117 static void lttv_traceset_context_compute_time_span(
118 LttvTracesetContext *self,
119 TimeInterval *time_span)
120 {
121 LttvTraceset * traceset = self->ts;
122 int numTraces = lttv_traceset_number(traceset);
123 int i;
124 LttTime s, e;
125 LttvTraceContext *tc;
126 LttTrace * trace;
127
128 time_span->start_time.tv_sec = 0;
129 time_span->start_time.tv_nsec = 0;
130 time_span->end_time.tv_sec = 0;
131 time_span->end_time.tv_nsec = 0;
132
133 for(i=0; i<numTraces;i++){
134 tc = self->traces[i];
135 trace = tc->t;
136
137 ltt_trace_time_span_get(trace, &s, &e);
138 tc->time_span.start_time = s;
139 tc->time_span.end_time = e;
140
141 if(i==0){
142 time_span->start_time = s;
143 time_span->end_time = e;
144 }else{
145 if(s.tv_sec < time_span->start_time.tv_sec
146 || (s.tv_sec == time_span->start_time.tv_sec
147 && s.tv_nsec < time_span->start_time.tv_nsec))
148 time_span->start_time = s;
149 if(e.tv_sec > time_span->end_time.tv_sec
150 || (e.tv_sec == time_span->end_time.tv_sec
151 && e.tv_nsec > time_span->end_time.tv_nsec))
152 time_span->end_time = e;
153 }
154 }
155 }
156
157 static void init_tracefile_context(LttTracefile *tracefile,
158 LttvTraceContext *tc)
159 {
160 LttvTracefileContext *tfc;
161 LttvTracesetContext *tsc = tc->ts_context;
162
163 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(tsc)->new_tracefile_context(tsc);
164
165 tfc->index = tc->tracefiles->len;
166 tc->tracefiles = g_array_append_val(tc->tracefiles, tfc);
167
168 tfc->tf = tracefile;
169
170 tfc->t_context = tc;
171 tfc->event = lttv_hooks_new();
172 tfc->event_by_id = lttv_hooks_by_id_new();
173 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
174 tfc->target_pid = -1;
175 }
176
177
178 static void
179 init(LttvTracesetContext *self, LttvTraceset *ts)
180 {
181 guint i, nb_trace;
182
183 LttvTraceContext *tc;
184
185 GData **tracefiles_groups;
186
187 struct compute_tracefile_group_args args;
188
189 nb_trace = lttv_traceset_number(ts);
190 self->ts = ts;
191 self->traces = g_new(LttvTraceContext *, nb_trace);
192 self->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
193 self->ts_a = lttv_traceset_attribute(ts);
194 for(i = 0 ; i < nb_trace ; i++) {
195 tc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
196 self->traces[i] = tc;
197
198 tc->ts_context = self;
199 tc->index = i;
200 tc->vt = lttv_traceset_get(ts, i);
201 tc->t = lttv_trace(tc->vt);
202 tc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
203 tc->t_a = lttv_trace_attribute(tc->vt);
204 tc->tracefiles = g_array_sized_new(FALSE, TRUE,
205 sizeof(LttvTracefileContext*), 10);
206
207 tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t);
208 if(tracefiles_groups != NULL) {
209 args.func = (ForEachTraceFileFunc)init_tracefile_context;
210 args.func_args = tc;
211
212 g_datalist_foreach(tracefiles_groups,
213 (GDataForeachFunc)compute_tracefile_group,
214 &args);
215 }
216
217 #if 0
218 nb_control = ltt_trace_control_tracefile_number(tc->t);
219 nb_per_cpu = ltt_trace_per_cpu_tracefile_number(tc->t);
220 nb_tracefile = nb_control + nb_per_cpu;
221 tc->tracefiles = g_new(LttvTracefileContext *, nb_tracefile);
222
223 for(j = 0 ; j < nb_tracefile ; j++) {
224 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
225 tc->tracefiles[j] = tfc;
226 tfc->index = j;
227
228 if(j < nb_control) {
229 tfc->control = TRUE;
230 tfc->tf = ltt_trace_control_tracefile_get(tc->t, j);
231 }
232 else {
233 tfc->control = FALSE;
234 tfc->tf = ltt_trace_per_cpu_tracefile_get(tc->t, j - nb_control);
235 }
236
237 tfc->t_context = tc;
238 tfc->e = ltt_event_new();
239 tfc->event = lttv_hooks_new();
240 tfc->event_by_id = lttv_hooks_by_id_new();
241 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
242 }
243 #endif //0
244
245 }
246 self->sync_position = lttv_traceset_context_position_new(self);
247 self->pqueue = g_tree_new(compare_tracefile);
248 lttv_process_traceset_seek_time(self, ltt_time_zero);
249 lttv_traceset_context_compute_time_span(self, &self->time_span);
250
251 }
252
253
254 void fini(LttvTracesetContext *self)
255 {
256 guint i, j, nb_trace, nb_tracefile;
257
258 LttvTraceContext *tc;
259
260 LttvTracefileContext **tfc;
261
262 LttvTraceset *ts = self->ts;
263
264 g_tree_destroy(self->pqueue);
265 g_object_unref(self->a);
266 lttv_traceset_context_position_destroy(self->sync_position);
267
268 nb_trace = lttv_traceset_number(ts);
269
270 for(i = 0 ; i < nb_trace ; i++) {
271 tc = self->traces[i];
272
273 g_object_unref(tc->a);
274
275 nb_tracefile = tc->tracefiles->len;
276
277 for(j = 0 ; j < nb_tracefile ; j++) {
278 tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, j);
279 lttv_hooks_destroy((*tfc)->event);
280 lttv_hooks_by_id_destroy((*tfc)->event_by_id);
281 g_object_unref((*tfc)->a);
282 g_object_unref(*tfc);
283 }
284 g_array_free(tc->tracefiles, TRUE);
285 g_object_unref(tc);
286 }
287 g_free(self->traces);
288 }
289
290
291 void lttv_traceset_context_add_hooks(LttvTracesetContext *self,
292 LttvHooks *before_traceset,
293 LttvHooks *before_trace,
294 LttvHooks *before_tracefile,
295 LttvHooks *event,
296 LttvHooksById *event_by_id)
297 {
298 LttvTraceset *ts = self->ts;
299
300 guint i, nb_trace;
301
302 LttvTraceContext *tc;
303
304 lttv_hooks_call(before_traceset, self);
305
306 nb_trace = lttv_traceset_number(ts);
307
308 for(i = 0 ; i < nb_trace ; i++) {
309 tc = self->traces[i];
310 lttv_trace_context_add_hooks(tc,
311 before_trace,
312 before_tracefile,
313 event,
314 event_by_id);
315 }
316 }
317
318
319 void lttv_traceset_context_remove_hooks(LttvTracesetContext *self,
320 LttvHooks *after_traceset,
321 LttvHooks *after_trace,
322 LttvHooks *after_tracefile,
323 LttvHooks *event,
324 LttvHooksById *event_by_id)
325 {
326
327 LttvTraceset *ts = self->ts;
328
329 guint i, nb_trace;
330
331 LttvTraceContext *tc;
332
333 nb_trace = lttv_traceset_number(ts);
334
335 for(i = 0 ; i < nb_trace ; i++) {
336 tc = self->traces[i];
337 lttv_trace_context_remove_hooks(tc,
338 after_trace,
339 after_tracefile,
340 event,
341 event_by_id);
342 }
343
344 lttv_hooks_call(after_traceset, self);
345
346
347 }
348
349 void lttv_trace_context_add_hooks(LttvTraceContext *self,
350 LttvHooks *before_trace,
351 LttvHooks *before_tracefile,
352 LttvHooks *event,
353 LttvHooksById *event_by_id)
354 {
355 guint i, nb_tracefile;
356
357 LttvTracefileContext **tfc;
358
359 lttv_hooks_call(before_trace, self);
360
361 nb_tracefile = self->tracefiles->len;
362
363 for(i = 0 ; i < nb_tracefile ; i++) {
364 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
365 lttv_tracefile_context_add_hooks(*tfc,
366 before_tracefile,
367 event,
368 event_by_id);
369 }
370 }
371
372
373
374 void lttv_trace_context_remove_hooks(LttvTraceContext *self,
375 LttvHooks *after_trace,
376 LttvHooks *after_tracefile,
377 LttvHooks *event,
378 LttvHooksById *event_by_id)
379 {
380 guint i, nb_tracefile;
381
382 LttvTracefileContext **tfc;
383
384 nb_tracefile = self->tracefiles->len;
385
386 for(i = 0 ; i < nb_tracefile ; i++) {
387 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
388 lttv_tracefile_context_remove_hooks(*tfc,
389 after_tracefile,
390 event,
391 event_by_id);
392 }
393
394 lttv_hooks_call(after_trace, self);
395 }
396
397 void lttv_tracefile_context_add_hooks(LttvTracefileContext *self,
398 LttvHooks *before_tracefile,
399 LttvHooks *event,
400 LttvHooksById *event_by_id)
401 {
402 guint i, index;
403
404 LttvHooks *hook;
405
406 lttv_hooks_call(before_tracefile, self);
407 lttv_hooks_add_list(self->event, event);
408 if(event_by_id != NULL) {
409 for(i = 0; i < event_by_id->array->len; i++) {
410 index = g_array_index(event_by_id->array, guint, i);
411 hook = lttv_hooks_by_id_find(self->event_by_id, index);
412 lttv_hooks_add_list(hook, lttv_hooks_by_id_get(event_by_id, index));
413 }
414 }
415 }
416
417 void lttv_tracefile_context_remove_hooks(LttvTracefileContext *self,
418 LttvHooks *after_tracefile,
419 LttvHooks *event,
420 LttvHooksById *event_by_id)
421 {
422 guint i, index;
423
424 LttvHooks *hook;
425
426 lttv_hooks_remove_list(self->event, event);
427 if(event_by_id != NULL) {
428 for(i = 0; i < event_by_id->array->len; i++) {
429 index = g_array_index(event_by_id->array, guint, i);
430 hook = lttv_hooks_by_id_get(self->event_by_id, index);
431 if(hook != NULL)
432 lttv_hooks_remove_list(hook, lttv_hooks_by_id_get(event_by_id, index));
433 }
434 }
435
436 lttv_hooks_call(after_tracefile, self);
437 }
438
439
440
441 void lttv_tracefile_context_add_hooks_by_id(LttvTracefileContext *tfc,
442 unsigned i,
443 LttvHooks *event_by_id)
444 {
445 LttvHooks * h;
446 h = lttv_hooks_by_id_find(tfc->event_by_id, i);
447 lttv_hooks_add_list(h, event_by_id);
448 }
449
450 void lttv_tracefile_context_remove_hooks_by_id(LttvTracefileContext *tfc,
451 unsigned i)
452 {
453 lttv_hooks_by_id_remove(tfc->event_by_id, i);
454 }
455
456 static LttvTracesetContext *
457 new_traceset_context(LttvTracesetContext *self)
458 {
459 return g_object_new(LTTV_TRACESET_CONTEXT_TYPE, NULL);
460 }
461
462
463 static LttvTraceContext *
464 new_trace_context(LttvTracesetContext *self)
465 {
466 return g_object_new(LTTV_TRACE_CONTEXT_TYPE, NULL);
467 }
468
469
470 static LttvTracefileContext *
471 new_tracefile_context(LttvTracesetContext *self)
472 {
473 return g_object_new(LTTV_TRACEFILE_CONTEXT_TYPE, NULL);
474 }
475
476
477 static void
478 traceset_context_instance_init (GTypeInstance *instance, gpointer g_class)
479 {
480 /* Be careful of anything which would not work well with shallow copies */
481 }
482
483
484 static void
485 traceset_context_finalize (LttvTracesetContext *self)
486 {
487 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACESET_CONTEXT_TYPE)))
488 ->finalize(G_OBJECT(self));
489 }
490
491
492 static void
493 traceset_context_class_init (LttvTracesetContextClass *klass)
494 {
495 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
496
497 gobject_class->finalize = (void (*)(GObject *self))traceset_context_finalize;
498 klass->init = init;
499 klass->fini = fini;
500 klass->new_traceset_context = new_traceset_context;
501 klass->new_trace_context = new_trace_context;
502 klass->new_tracefile_context = new_tracefile_context;
503 }
504
505
506 GType
507 lttv_traceset_context_get_type(void)
508 {
509 static GType type = 0;
510 if (type == 0) {
511 static const GTypeInfo info = {
512 sizeof (LttvTracesetContextClass),
513 NULL, /* base_init */
514 NULL, /* base_finalize */
515 (GClassInitFunc) traceset_context_class_init, /* class_init */
516 NULL, /* class_finalize */
517 NULL, /* class_data */
518 sizeof (LttvTracesetContext),
519 0, /* n_preallocs */
520 (GInstanceInitFunc) traceset_context_instance_init, /* instance_init */
521 NULL /* Value handling */
522 };
523
524 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracesetContextType",
525 &info, 0);
526 }
527 return type;
528 }
529
530
531 static void
532 trace_context_instance_init (GTypeInstance *instance, gpointer g_class)
533 {
534 /* Be careful of anything which would not work well with shallow copies */
535 }
536
537
538 static void
539 trace_context_finalize (LttvTraceContext *self)
540 {
541 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACE_CONTEXT_TYPE)))->
542 finalize(G_OBJECT(self));
543 }
544
545
546 static void
547 trace_context_class_init (LttvTraceContextClass *klass)
548 {
549 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
550
551 gobject_class->finalize = (void (*)(GObject *self)) trace_context_finalize;
552 }
553
554
555 GType
556 lttv_trace_context_get_type(void)
557 {
558 static GType type = 0;
559 if (type == 0) {
560 static const GTypeInfo info = {
561 sizeof (LttvTraceContextClass),
562 NULL, /* base_init */
563 NULL, /* base_finalize */
564 (GClassInitFunc) trace_context_class_init, /* class_init */
565 NULL, /* class_finalize */
566 NULL, /* class_data */
567 sizeof (LttvTraceContext),
568 0, /* n_preallocs */
569 (GInstanceInitFunc) trace_context_instance_init, /* instance_init */
570 NULL /* Value handling */
571 };
572
573 type = g_type_register_static (G_TYPE_OBJECT, "LttvTraceContextType",
574 &info, 0);
575 }
576 return type;
577 }
578
579
580 static void
581 tracefile_context_instance_init (GTypeInstance *instance, gpointer g_class)
582 {
583 /* Be careful of anything which would not work well with shallow copies */
584 }
585
586
587 static void
588 tracefile_context_finalize (LttvTracefileContext *self)
589 {
590 G_OBJECT_CLASS(g_type_class_peek(g_type_parent(LTTV_TRACEFILE_CONTEXT_TYPE)))
591 ->finalize(G_OBJECT(self));
592 }
593
594
595 static void
596 tracefile_context_class_init (LttvTracefileContextClass *klass)
597 {
598 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
599
600 gobject_class->finalize = (void (*)(GObject *self))tracefile_context_finalize;
601 }
602
603
604 GType
605 lttv_tracefile_context_get_type(void)
606 {
607 static GType type = 0;
608 if (type == 0) {
609 static const GTypeInfo info = {
610 sizeof (LttvTracefileContextClass),
611 NULL, /* base_init */
612 NULL, /* base_finalize */
613 (GClassInitFunc) tracefile_context_class_init, /* class_init */
614 NULL, /* class_finalize */
615 NULL, /* class_data */
616 sizeof (LttvTracefileContext),
617 0, /* n_preallocs */
618 (GInstanceInitFunc) tracefile_context_instance_init, /* instance_init */
619 NULL /* Value handling */
620 };
621
622 type = g_type_register_static (G_TYPE_OBJECT, "LttvTracefileContextType",
623 &info, 0);
624 }
625 return type;
626 }
627
628
629
630 static gboolean get_first(gpointer key, gpointer value, gpointer user_data) {
631 g_assert(key == value);
632 *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value;
633 return TRUE;
634 }
635
636 #ifdef DEBUG
637 // Test to see if pqueue is traversed in the right order.
638 static LttTime test_time;
639
640 static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) {
641
642 LttvTracefileContext *tfc = (LttvTracefileContext *)key;
643
644 g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u",
645 g_quark_to_string(ltt_tracefile_name(tfc->tf)),
646 tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec,
647 tfc->index, tfc->t_context->index);
648
649 if(user_data != NULL) {
650 if(((LttvTracefileContext *)user_data) == (LttvTracefileContext *)value) {
651 g_assert(compare_tracefile(user_data, value) == 0);
652 } else
653 g_assert(compare_tracefile(user_data, value) != 0);
654 }
655 g_assert(ltt_time_compare(test_time, tfc->timestamp) <= 0);
656 test_time.tv_sec = tfc->timestamp.tv_sec;
657 test_time.tv_nsec = tfc->timestamp.tv_nsec;
658
659
660 //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value);
661 return FALSE;
662 }
663 #endif //DEBUG
664
665
666
667 void lttv_process_traceset_begin(LttvTracesetContext *self,
668 LttvHooks *before_traceset,
669 LttvHooks *before_trace,
670 LttvHooks *before_tracefile,
671 LttvHooks *event,
672 LttvHooksById *event_by_id)
673 {
674
675 /* simply add hooks in context. _before hooks are called by add_hooks. */
676 /* It calls all before_traceset, before_trace, and before_tracefile hooks. */
677 lttv_traceset_context_add_hooks(self,
678 before_traceset,
679 before_trace,
680 before_tracefile,
681 event,
682 event_by_id);
683
684 }
685
686 //enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY };
687
688 /* Note : a _middle must be preceded from a _seek or another middle */
689 guint lttv_process_traceset_middle(LttvTracesetContext *self,
690 LttTime end,
691 guint nb_events,
692 const LttvTracesetContextPosition *end_position)
693 {
694 GTree *pqueue = self->pqueue;
695
696 guint fac_id, ev_id, id;
697
698 LttvTracefileContext *tfc;
699
700 LttEvent *e;
701
702 unsigned count = 0;
703
704 guint read_ret;
705
706 //enum read_state last_read_state = LAST_NONE;
707
708 gint last_ret = 0; /* return value of the last hook list called */
709
710 /* Get the next event from the pqueue, call its hooks,
711 reinsert in the pqueue the following event from the same tracefile
712 unless the tracefile is finished or the event is later than the
713 end time. */
714
715 while(TRUE) {
716 tfc = NULL;
717 g_tree_foreach(pqueue, get_first, &tfc);
718 /* End of traceset : tfc is NULL */
719 if(unlikely(tfc == NULL))
720 {
721 return count;
722 }
723
724 /* Have we reached :
725 * - the maximum number of events specified?
726 * - the end position ?
727 * - the end time ?
728 * then the read is finished. We leave the queue in the same state and
729 * break the loop.
730 */
731
732 if(unlikely(last_ret == TRUE ||
733 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
734 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
735 end_position) == 0)||
736 ltt_time_compare(end, tfc->timestamp) <= 0))
737 {
738 return count;
739 }
740
741 /* Get the tracefile with an event for the smallest time found. If two
742 or more tracefiles have events for the same time, hope that lookup
743 and remove are consistent. */
744
745 #ifdef DEBUG
746 test_time.tv_sec = 0;
747 test_time.tv_nsec = 0;
748 g_debug("test tree before remove");
749 g_tree_foreach(pqueue, test_tree, tfc);
750 #endif //DEBUG
751 g_tree_remove(pqueue, tfc);
752
753 #ifdef DEBUG
754 test_time.tv_sec = 0;
755 test_time.tv_nsec = 0;
756 g_debug("test tree after remove");
757 g_tree_foreach(pqueue, test_tree, tfc);
758 #endif //DEBUG
759
760
761 e = ltt_tracefile_get_event(tfc->tf);
762
763 //if(last_read_state != LAST_EMPTY) {
764 /* Only call hooks if the last read has given an event or if we are at the
765 * first pass (not if last read returned end of tracefile) */
766 count++;
767
768 fac_id = ltt_event_facility_id(e);
769 ev_id = ltt_event_eventtype_id(e);
770 id = GET_HOOK_ID(fac_id, ev_id);
771 tfc->target_pid = -1; /* unset target PID */
772 /* Hooks :
773 * return values : 0 : continue read, 1 : go to next position and stop read,
774 * 2 : stay at the current position and stop read */
775 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
776 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
777
778 #if 0
779 /* This is buggy : it won't work well with state computation */
780 if(unlikely(last_ret == 2)) {
781 /* This is a case where we want to stay at this position and stop read. */
782 g_tree_insert(pqueue, tfc, tfc);
783 return count - 1;
784 }
785 #endif //0
786 read_ret = ltt_tracefile_read(tfc->tf);
787
788
789 if(likely(!read_ret)) {
790 //g_debug("An event is ready");
791 tfc->timestamp = ltt_event_time(e);
792 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
793 g_tree_insert(pqueue, tfc, tfc);
794 #ifdef DEBUG
795 test_time.tv_sec = 0;
796 test_time.tv_nsec = 0;
797 g_debug("test tree after event ready");
798 g_tree_foreach(pqueue, test_tree, NULL);
799 #endif //DEBUG
800
801 //last_read_state = LAST_OK;
802 } else {
803 tfc->timestamp = ltt_time_infinite;
804
805 if(read_ret == ERANGE) {
806 // last_read_state = LAST_EMPTY;
807 g_debug("End of trace");
808 } else
809 g_error("Error happened in lttv_process_traceset_middle");
810 }
811 }
812 }
813
814
815 void lttv_process_traceset_end(LttvTracesetContext *self,
816 LttvHooks *after_traceset,
817 LttvHooks *after_trace,
818 LttvHooks *after_tracefile,
819 LttvHooks *event,
820 LttvHooksById *event_by_id)
821 {
822 /* Remove hooks from context. _after hooks are called by remove_hooks. */
823 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
824 lttv_traceset_context_remove_hooks(self,
825 after_traceset,
826 after_trace,
827 after_tracefile,
828 event,
829 event_by_id);
830 }
831
832 /* Subtile modification :
833 * if tracefile has no event at or after the time requested, it is not put in
834 * the queue, as the next read would fail.
835 *
836 * Don't forget to empty the traceset pqueue before calling this.
837 */
838 void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
839 {
840 guint i, nb_tracefile;
841
842 gint ret;
843
844 LttvTracefileContext **tfc;
845
846 nb_tracefile = self->tracefiles->len;
847
848 GTree *pqueue = self->ts_context->pqueue;
849
850 for(i = 0 ; i < nb_tracefile ; i++) {
851 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
852
853 g_tree_remove(pqueue, *tfc);
854
855 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
856 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
857
858 if(ret == 0) { /* not ERANGE especially */
859 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
860 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
861 g_tree_insert(pqueue, (*tfc), (*tfc));
862 } else {
863 (*tfc)->timestamp = ltt_time_infinite;
864 }
865 }
866 #ifdef DEBUG
867 test_time.tv_sec = 0;
868 test_time.tv_nsec = 0;
869 g_debug("test tree after seek_time");
870 g_tree_foreach(pqueue, test_tree, NULL);
871 #endif //DEBUG
872
873
874
875 }
876
877
878 void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
879 {
880 guint i, nb_trace;
881
882 LttvTraceContext *tc;
883
884 //g_tree_destroy(self->pqueue);
885 //self->pqueue = g_tree_new(compare_tracefile);
886
887 nb_trace = lttv_traceset_number(self->ts);
888 for(i = 0 ; i < nb_trace ; i++) {
889 tc = self->traces[i];
890 lttv_process_trace_seek_time(tc, start);
891 }
892 }
893
894
895 gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
896 const LttvTracesetContextPosition *pos)
897 {
898 guint i;
899 /* If a position is set, seek the traceset to this position */
900 if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
901
902 /* Test to see if the traces has been added to the trace set :
903 * It should NEVER happen. Clear all positions if a new trace comes in. */
904 /* FIXME I know this test is not optimal : should keep a number of
905 * tracefiles variable in the traceset.. eventually */
906 guint num_traces = lttv_traceset_number(self->ts);
907 guint tf_count = 0;
908 for(i=0; i<num_traces;i++) {
909 GArray * tracefiles = self->traces[i]->tracefiles;
910 guint j;
911 guint num_tracefiles = tracefiles->len;
912 for(j=0;j<num_tracefiles;j++)
913 tf_count++;
914 }
915 g_assert(tf_count == pos->tfcp->len);
916
917
918 //g_tree_destroy(self->pqueue);
919 //self->pqueue = g_tree_new(compare_tracefile);
920
921 for(i=0;i<pos->tfcp->len; i++) {
922 LttvTracefileContextPosition *tfcp =
923 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
924
925 g_tree_remove(self->pqueue, tfcp->tfc);
926
927 if(tfcp->used == TRUE) {
928 if(ltt_tracefile_seek_position(tfcp->tfc->tf, tfcp->event) != 0)
929 return 1;
930 tfcp->tfc->timestamp =
931 ltt_event_time(ltt_tracefile_get_event(tfcp->tfc->tf));
932 g_assert(ltt_time_compare(tfcp->tfc->timestamp,
933 ltt_time_infinite) != 0);
934 g_tree_insert(self->pqueue, tfcp->tfc, tfcp->tfc);
935
936 } else {
937 tfcp->tfc->timestamp = ltt_time_infinite;
938 }
939 }
940 }
941 #ifdef DEBUG
942 test_time.tv_sec = 0;
943 test_time.tv_nsec = 0;
944 g_debug("test tree after seek_position");
945 g_tree_foreach(self->pqueue, test_tree, NULL);
946 #endif //DEBUG
947
948
949
950 return 0;
951 }
952
953
954
955 static LttField *
956 find_field(LttEventType *et, const GQuark field)
957 {
958 GQuark name;
959
960 if(field == 0) return NULL;
961
962 return ltt_eventtype_field_by_name(et, field);
963 }
964
965 LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
966 guint facility_id)
967 {
968 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
969 }
970
971 /* Get the first facility corresponding to the name. As the types must be
972 * compatible, it is relevant to use the field name and sizes of the first
973 * facility to create data structures and assume the data will be compatible
974 * thorough the trace */
975 LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
976 {
977 g_assert(th->fac_list->len > 0);
978 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
979 }
980
981
982 /* Returns 0 on success, -1 if fails. */
983 gint
984 lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
985 GQuark field1, GQuark field2, GQuark field3, LttvHook h, gpointer hook_data,
986 LttvTraceHook *th)
987 {
988 LttFacility *f;
989
990 LttEventType *et, *first_et;
991
992 GArray *facilities;
993
994 guint i, fac_id, ev_id;
995
996 LttvTraceHookByFacility *thf, *first_thf;
997
998 facilities = ltt_trace_facility_get_by_name(t, facility);
999
1000 if(unlikely(facilities == NULL)) goto facility_error;
1001
1002 th->fac_index = g_array_sized_new(FALSE, TRUE,
1003 sizeof(LttvTraceHookByFacility),
1004 NUM_FACILITIES);
1005 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
1006
1007 th->fac_list = g_array_sized_new(FALSE, TRUE,
1008 sizeof(LttvTraceHookByFacility*),
1009 facilities->len);
1010 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
1011
1012 fac_id = g_array_index(facilities, guint, 0);
1013 f = ltt_trace_get_facility_by_num(t, fac_id);
1014
1015 et = ltt_facility_eventtype_get_by_name(f, event);
1016 if(unlikely(et == NULL)) goto event_error;
1017
1018 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1019 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf;
1020
1021 ev_id = ltt_eventtype_id(et);
1022
1023 thf->h = h;
1024 thf->id = GET_HOOK_ID(fac_id, ev_id);
1025 thf->f1 = find_field(et, field1);
1026 thf->f2 = find_field(et, field2);
1027 thf->f3 = find_field(et, field3);
1028 thf->hook_data = hook_data;
1029
1030 first_thf = thf;
1031 first_et = et;
1032
1033 /* Check for type compatibility too */
1034 for(i=1;i<facilities->len;i++) {
1035 fac_id = g_array_index(facilities, guint, i);
1036 f = ltt_trace_get_facility_by_num(t, fac_id);
1037
1038 et = ltt_facility_eventtype_get_by_name(f, event);
1039 if(unlikely(et == NULL)) goto event_error;
1040
1041 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1042 g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf;
1043 ev_id = ltt_eventtype_id(et);
1044 thf->h = h;
1045 thf->id = GET_HOOK_ID(fac_id, ev_id);
1046 thf->f1 = find_field(et, field1);
1047 if(check_fields_compatibility(first_et, et,
1048 first_thf->f1, thf->f1))
1049 goto type_error;
1050
1051 thf->f2 = find_field(et, field2);
1052 if(check_fields_compatibility(first_et, et,
1053 first_thf->f2, thf->f2))
1054 goto type_error;
1055
1056 thf->f3 = find_field(et, field3);
1057 if(check_fields_compatibility(first_et, et,
1058 first_thf->f3, thf->f3))
1059 goto type_error;
1060 thf->hook_data = hook_data;
1061 }
1062
1063 return 0;
1064
1065 type_error:
1066 goto free;
1067 event_error:
1068 g_error("Event type does not exist for event %s",
1069 g_quark_to_string(event));
1070 goto free;
1071 facility_error:
1072 //Ignore this type of error : some facilities are not required.
1073 //g_error("No %s facility", g_quark_to_string(facility));
1074 return -1;
1075 free:
1076 g_array_free(th->fac_index, TRUE);
1077 g_array_free(th->fac_list, TRUE);
1078 th->fac_index = NULL;
1079 th->fac_list = NULL;
1080 return -1;
1081 }
1082
1083 void lttv_trace_hook_destroy(LttvTraceHook *th)
1084 {
1085 g_array_free(th->fac_index, TRUE);
1086 g_array_free(th->fac_list, TRUE);
1087 }
1088
1089
1090
1091
1092 LttvTracesetContextPosition *lttv_traceset_context_position_new(
1093 const LttvTracesetContext *self)
1094 {
1095 guint num_traces = lttv_traceset_number(self->ts);
1096 guint tf_count = 0;
1097 guint i;
1098
1099 for(i=0; i<num_traces;i++) {
1100 GArray * tracefiles = self->traces[i]->tracefiles;
1101 guint j;
1102 guint num_tracefiles = tracefiles->len;
1103 for(j=0;j<num_tracefiles;j++)
1104 tf_count++;
1105 }
1106 LttvTracesetContextPosition *pos =
1107 g_new(LttvTracesetContextPosition, 1);
1108 pos->tfcp = g_array_sized_new(FALSE, TRUE,
1109 sizeof(LttvTracefileContextPosition),
1110 tf_count);
1111 g_array_set_size(pos->tfcp, tf_count);
1112 for(i=0;i<pos->tfcp->len;i++) {
1113 LttvTracefileContextPosition *tfcp =
1114 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1115 tfcp->event = ltt_event_position_new();
1116 }
1117
1118 pos->timestamp = ltt_time_infinite;
1119 return pos;
1120 }
1121
1122 /* Save all positions, the ones with infinite time will have NULL
1123 * ep. */
1124 /* note : a position must be destroyed when a trace is added/removed from a
1125 * traceset */
1126 void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1127 LttvTracesetContextPosition *pos)
1128 {
1129 guint i;
1130 guint num_traces = lttv_traceset_number(self->ts);
1131 guint tf_count = 0;
1132
1133 pos->timestamp = ltt_time_infinite;
1134
1135 for(i=0; i<num_traces;i++) {
1136 GArray * tracefiles = self->traces[i]->tracefiles;
1137 guint j;
1138 guint num_tracefiles = tracefiles->len;
1139
1140 for(j=0;j<num_tracefiles;j++) {
1141 g_assert(tf_count < pos->tfcp->len);
1142 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1143 LttvTracefileContext*, j);
1144 LttvTracefileContextPosition *tfcp =
1145 &g_array_index(pos->tfcp, LttvTracefileContextPosition, tf_count);
1146
1147 tfcp->tfc = *tfc;
1148
1149 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
1150 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1151 ltt_event_position(event, tfcp->event);
1152 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1153 pos->timestamp = (*tfc)->timestamp;
1154 tfcp->used = TRUE;
1155 } else {
1156 tfcp->used = FALSE;
1157 }
1158
1159 //g_array_append_val(pos->tfc, *tfc);
1160 //g_array_append_val(pos->ep, ep);
1161 tf_count++;
1162 }
1163
1164 }
1165 }
1166
1167 void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1168 {
1169 int i;
1170
1171 for(i=0;i<pos->tfcp->len;i++) {
1172 LttvTracefileContextPosition *tfcp =
1173 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1174 g_free(tfcp->event);
1175 tfcp->event = NULL;
1176 tfcp->used = FALSE;
1177 }
1178 g_array_free(pos->tfcp, TRUE);
1179 g_free(pos);
1180 }
1181
1182 void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1183 const LttvTracesetContextPosition *src)
1184 {
1185 int i;
1186 LttvTracefileContextPosition *src_tfcp, *dest_tfcp;
1187
1188 g_assert(src->tfcp->len == src->tfcp->len);
1189
1190 for(i=0;i<src->tfcp->len;i++) {
1191 src_tfcp =
1192 &g_array_index(src->tfcp, LttvTracefileContextPosition, i);
1193 dest_tfcp =
1194 &g_array_index(dest->tfcp, LttvTracefileContextPosition, i);
1195
1196 dest_tfcp->used = src_tfcp->used;
1197 dest_tfcp->tfc = src_tfcp->tfc;
1198
1199 if(src_tfcp->used) {
1200 ltt_event_position_copy(
1201 dest_tfcp->event,
1202 src_tfcp->event);
1203 }
1204 }
1205 dest->timestamp = src->timestamp;
1206 }
1207
1208 gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1209 const LttvTracesetContextPosition *pos)
1210 {
1211 int i;
1212 int ret = 0;
1213
1214 if(pos->tfcp->len == 0) {
1215 if(lttv_traceset_number(self->ts) == 0) return 0;
1216 else return 1;
1217 }
1218 if(lttv_traceset_number(self->ts) == 0)
1219 return -1;
1220
1221 for(i=0;i<pos->tfcp->len;i++) {
1222 LttvTracefileContextPosition *tfcp =
1223 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1224
1225 if(tfcp->used == FALSE) {
1226 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) < 0) {
1227 ret = -1;
1228 }
1229 } else {
1230 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) == 0) {
1231 ret = 1;
1232 } else {
1233 LttEvent *event = ltt_tracefile_get_event(tfcp->tfc->tf);
1234
1235 ret = ltt_event_position_compare((LttEventPosition*)event,
1236 tfcp->event);
1237 }
1238 }
1239 if(ret != 0) return ret;
1240
1241 }
1242 return 0;
1243 }
1244
1245
1246 gint lttv_traceset_context_pos_pos_compare(
1247 const LttvTracesetContextPosition *pos1,
1248 const LttvTracesetContextPosition *pos2)
1249 {
1250 int i, j;
1251 int ret = 0;
1252
1253 if(ltt_time_compare(pos1->timestamp, ltt_time_infinite) == 0) {
1254 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
1255 return 0;
1256 else
1257 return 1;
1258 }
1259 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
1260 return -1;
1261
1262 for(i=0;i<pos1->tfcp->len;i++) {
1263 LttvTracefileContextPosition *tfcp1 =
1264 &g_array_index(pos1->tfcp, LttvTracefileContextPosition, i);
1265
1266 if(tfcp1->used == TRUE) {
1267 for(j=0;j<pos2->tfcp->len;j++) {
1268 LttvTracefileContextPosition *tfcp2 =
1269 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1270
1271 if(tfcp1->tfc == tfcp2->tfc) {
1272 if(tfcp2->used == TRUE)
1273 ret = ltt_event_position_compare(tfcp1->event, tfcp2->event);
1274 else
1275 ret = -1;
1276
1277 if(ret != 0) return ret;
1278 }
1279 }
1280
1281 } else {
1282 for(j=0;j<pos2->tfcp->len;j++) {
1283 LttvTracefileContextPosition *tfcp2 =
1284 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1285
1286 if(tfcp1->tfc == tfcp2->tfc)
1287 if(tfcp2->used == TRUE) ret = 1;
1288 if(ret != 0) return ret;
1289 }
1290 }
1291 }
1292 return 0;
1293 }
1294
1295
1296 LttTime lttv_traceset_context_position_get_time(
1297 const LttvTracesetContextPosition *pos)
1298 {
1299 return pos->timestamp;
1300 }
1301
1302
1303 LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1304 {
1305 GTree *pqueue = self->pqueue;
1306 LttvTracefileContext *tfc = NULL;
1307
1308 g_tree_foreach(pqueue, get_first, &tfc);
1309
1310 return tfc;
1311 }
1312
1313 /* lttv_process_traceset_synchronize_tracefiles
1314 *
1315 * Use the sync_position field of the trace set context to synchronize each
1316 * tracefile with the previously saved position.
1317 *
1318 * If no previous position has been saved, it simply does nothing.
1319 */
1320 void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1321 {
1322 g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
1323 }
1324
1325
1326
1327
1328 void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1329 {
1330 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1331 }
1332
1333 struct seek_back_data {
1334 guint first_event; /* Index of the first event in the array : we will always
1335 overwrite at this position : this is a circular array.
1336 */
1337 guint events_found;
1338 guint n; /* number of events requested */
1339 GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
1340 LttvFilter *filter;
1341 check_handler *check;
1342 gboolean *stop_flag;
1343 guint raw_event_count;
1344 };
1345
1346 static gint seek_back_event_hook(void *hook_data, void* call_data)
1347 {
1348 struct seek_back_data *sd = (struct seek_back_data*)hook_data;
1349 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1350 LttvTracesetContext *tsc = tfc->t_context->ts_context;
1351 LttvTracesetContextPosition *pos;
1352
1353 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag)) return TRUE;
1354 sd->raw_event_count++;
1355
1356 if(sd->filter != NULL && sd->filter->head != NULL) {
1357 if(!lttv_filter_tree_parse(sd->filter->head,
1358 ltt_tracefile_get_event(tfc->tf),
1359 tfc->tf,
1360 tfc->t_context->t,
1361 tfc))
1362 return FALSE;
1363 }
1364
1365 pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array,
1366 sd->first_event);
1367
1368 lttv_traceset_context_position_save(tsc, pos);
1369
1370 if(sd->first_event >= sd->array->len - 1) sd->first_event = 0;
1371 else sd->first_event++;
1372
1373 sd->events_found = min(sd->n, sd->events_found + 1);
1374
1375 return FALSE;
1376 }
1377
1378 /* Seek back n events back from the current position.
1379 *
1380 * Parameters :
1381 * @self The trace set context
1382 * @n number of events to jump over
1383 * @first_offset The initial offset value used.
1384 * never put first_offset at ltt_time_zero.
1385 * @time_seeker Function pointer of the function to use to seek time :
1386 * either lttv_process_traceset_seek_time
1387 * or lttv_state_traceset_seek_time_closest
1388 * @filter The filter to call.
1389 *
1390 * Return value : the number of events found (might be lower than the number
1391 * requested if beginning of traceset is reached).
1392 *
1393 * The first search will go back first_offset and try to find the last n events
1394 * matching the filter. If there are not enough, it will try to go back from the
1395 * new trace point from first_offset*2, and so on, until beginning of trace or n
1396 * events are found.
1397 *
1398 * Note : this function does not take in account the LttvFilter : use the
1399 * similar function found in state.c instead.
1400 *
1401 * Note2 : the caller must make sure that the LttvTracesetContext does not
1402 * contain any hook, as process_traceset_middle is used in this routine.
1403 */
1404 guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
1405 guint n, LttTime first_offset,
1406 seek_time_fct time_seeker,
1407 LttvFilter *filter,
1408 check_handler *check,
1409 gboolean *stop_flag)
1410 {
1411 if(lttv_traceset_number(self->ts) == 0) return 0;
1412 g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
1413
1414 guint i;
1415 LttvTracesetContextPosition *next_iter_end_pos =
1416 lttv_traceset_context_position_new(self);
1417 LttvTracesetContextPosition *end_pos =
1418 lttv_traceset_context_position_new(self);
1419 LttvTracesetContextPosition *saved_pos =
1420 lttv_traceset_context_position_new(self);
1421 LttTime time;
1422 LttTime asked_time;
1423 LttTime time_offset;
1424 struct seek_back_data sd;
1425 LttvHooks *hooks = lttv_hooks_new();
1426
1427 sd.first_event = 0;
1428 sd.events_found = 0;
1429 sd.array = g_ptr_array_sized_new(n);
1430 sd.filter = filter;
1431 sd.n = n;
1432 sd.check = check;
1433 sd.stop_flag = stop_flag;
1434 sd.raw_event_count = 0;
1435 g_ptr_array_set_size(sd.array, n);
1436 for(i=0;i<n;i++) {
1437 g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new(self);
1438 }
1439
1440 lttv_traceset_context_position_save(self, next_iter_end_pos);
1441 lttv_traceset_context_position_save(self, saved_pos);
1442 /* Get the current time from which we will offset */
1443 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1444 /* the position saved might be end of traceset... */
1445 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1446 time = self->time_span.end_time;
1447 }
1448 asked_time = time;
1449 time_offset = first_offset;
1450
1451 lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT);
1452
1453 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1454
1455 while(1) {
1456 /* stop criteria : - n events found
1457 * - asked_time < beginning of trace */
1458 if(ltt_time_compare(asked_time, self->time_span.start_time) < 0) break;
1459
1460 lttv_traceset_context_position_copy(end_pos, next_iter_end_pos);
1461
1462 /* We must seek the traceset back to time - time_offset */
1463 /* this time becomes the new reference time */
1464 time = ltt_time_sub(time, time_offset);
1465 asked_time = time;
1466
1467 time_seeker(self, time);
1468 lttv_traceset_context_position_save(self, next_iter_end_pos);
1469 /* Resync the time in case of a seek_closest */
1470 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1471 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1472 time = self->time_span.end_time;
1473 }
1474
1475 /* Process the traceset, calling a hook which adds events
1476 * to the array, overwriting the tail. It changes first_event and
1477 * events_found too. */
1478 /* We would like to have a clean context here : no other hook than our's */
1479
1480 lttv_process_traceset_middle(self, ltt_time_infinite,
1481 G_MAXUINT, end_pos);
1482
1483 if(sd.events_found < n) {
1484 if(sd.first_event > 0) {
1485 /* Save the first position */
1486 LttvTracesetContextPosition *pos =
1487 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0);
1488 lttv_traceset_context_position_copy(saved_pos, pos);
1489 }
1490 g_assert(n-sd.events_found <= sd.array->len);
1491 /* Change array size to n - events_found */
1492 for(i=n-sd.events_found;i<sd.array->len;i++) {
1493 LttvTracesetContextPosition *pos =
1494 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1495 lttv_traceset_context_position_destroy(pos);
1496 }
1497 g_ptr_array_set_size(sd.array, n-sd.events_found);
1498 sd.first_event = 0;
1499
1500 } else break; /* Second end criterion : n events found */
1501
1502 time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL);
1503 }
1504
1505 lttv_traceset_context_position_destroy(end_pos);
1506 lttv_traceset_context_position_destroy(next_iter_end_pos);
1507
1508 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1509
1510 if(sd.events_found >= n) {
1511 /* Seek the traceset to the first event in the circular array */
1512 LttvTracesetContextPosition *pos =
1513 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array,
1514 sd.first_event);
1515 g_assert(lttv_process_traceset_seek_position(self, pos) == 0);
1516 } else {
1517 /* Will seek to the last saved position : in the worst case, it will be the
1518 * original position (if events_found is 0) */
1519 g_assert(lttv_process_traceset_seek_position(self, saved_pos) == 0);
1520 }
1521
1522 for(i=0;i<sd.array->len;i++) {
1523 LttvTracesetContextPosition *pos =
1524 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1525 lttv_traceset_context_position_destroy(pos);
1526 }
1527 g_ptr_array_free(sd.array, TRUE);
1528
1529 lttv_hooks_destroy(hooks);
1530
1531 lttv_traceset_context_position_destroy(saved_pos);
1532
1533 return sd.events_found;
1534 }
1535
1536
1537 struct seek_forward_data {
1538 guint event_count; /* event counter */
1539 guint n; /* requested number of events to jump over */
1540 LttvFilter *filter;
1541 check_handler *check;
1542 gboolean *stop_flag;
1543 guint raw_event_count; /* event counter */
1544 };
1545
1546 static gint seek_forward_event_hook(void *hook_data, void* call_data)
1547 {
1548 struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
1549 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1550
1551 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag)) return TRUE;
1552 sd->raw_event_count++;
1553
1554 if(sd->filter == NULL || lttv_filter_tree_parse(sd->filter->head,
1555 ltt_tracefile_get_event(tfc->tf),
1556 tfc->tf,
1557 tfc->t_context->t,
1558 tfc)) {
1559 sd->event_count++;
1560 if(sd->event_count >= sd->n)
1561 return TRUE;
1562 }
1563 return FALSE;
1564 }
1565
1566 /* Seek back n events forward from the current position (1 to n)
1567 * 0 is ok too, but it will actually do nothing.
1568 *
1569 * Parameters :
1570 * @self the trace set context
1571 * @n number of events to jump over
1572 * @filter filter to call.
1573 *
1574 * returns : the number of events jumped over (may be less than requested if end
1575 * of traceset reached) */
1576 guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
1577 guint n, LttvFilter *filter,
1578 check_handler *check,
1579 gboolean *stop_flag)
1580 {
1581 struct seek_forward_data sd;
1582 sd.event_count = 0;
1583 sd.n = n;
1584 sd.filter = filter;
1585 sd.check = check;
1586 sd.stop_flag = stop_flag;
1587 sd.raw_event_count = 0;
1588
1589 if(sd.event_count >= sd.n) return sd.event_count;
1590
1591 LttvHooks *hooks = lttv_hooks_new();
1592
1593 lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
1594
1595 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1596
1597 /* it will end on the end of traceset, or the fact that the
1598 * hook returns TRUE.
1599 */
1600 lttv_process_traceset_middle(self, ltt_time_infinite,
1601 G_MAXUINT, NULL);
1602
1603 /* Here, our position is either the end of traceset, or the exact position
1604 * after n events : leave it like this. This might be placed on an event that
1605 * will be filtered out, we don't care : all we know is that the following
1606 * event filtered in will be the right one. */
1607
1608 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1609
1610 lttv_hooks_destroy(hooks);
1611
1612 return sd.event_count;
1613 }
1614
1615
This page took 0.10031 seconds and 4 git commands to generate.