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