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