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