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