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