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