update compat
[lttv.git] / trunk / lttv / 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 *
8697a616 104 * Keep the time span is 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)) {
983 g_warning("No channel for marker named %s.%s found",
984 g_quark_to_string(channel_name), g_quark_to_string(event_name));
985 return 1;
986 }
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)) {
750eb11a 991 g_warning("No marker named %s.%s found",
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);
750eb11a 1029 g_warning("Field %s cannot be found in marker %s.%s",
1030 g_quark_to_string(*f), g_quark_to_string(channel_name),
1031 g_quark_to_string(event_name));
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) {
750eb11a 1043 g_warning("No marker of name %s.%s has all requested fields",
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
9ba3aaaf 1156 g_assert(src->tfcp->len == src->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{
1290 g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
1291}
1292
1293
1294
1295
1296void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1297{
1298 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1299}
1300
0bd2f89c 1301struct seek_back_data {
1302 guint first_event; /* Index of the first event in the array : we will always
1303 overwrite at this position : this is a circular array.
1304 */
1305 guint events_found;
33e44b82 1306 guint n; /* number of events requested */
0bd2f89c 1307 GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
b139ad2a 1308 LttvFilter *filter1;
1309 LttvFilter *filter2;
1310 LttvFilter *filter3;
fb3d6047 1311 gpointer data;
04f2543e 1312 check_handler *check;
1313 gboolean *stop_flag;
1314 guint raw_event_count;
0bd2f89c 1315};
1316
1317static gint seek_back_event_hook(void *hook_data, void* call_data)
1318{
1319 struct seek_back_data *sd = (struct seek_back_data*)hook_data;
1320 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1321 LttvTracesetContext *tsc = tfc->t_context->ts_context;
1322 LttvTracesetContextPosition *pos;
33e44b82 1323
fb3d6047 1324 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
1325 return TRUE;
04f2543e 1326 sd->raw_event_count++;
1327
b139ad2a 1328 if(sd->filter1 != NULL && sd->filter1->head != NULL &&
1329 !lttv_filter_tree_parse(sd->filter1->head,
33e44b82 1330 ltt_tracefile_get_event(tfc->tf),
1331 tfc->tf,
1332 tfc->t_context->t,
b6ef18af 1333 tfc,NULL,NULL)) {
b139ad2a 1334 return FALSE;
0bd2f89c 1335 }
b139ad2a 1336 if(sd->filter2 != NULL && sd->filter2->head != NULL &&
1337 !lttv_filter_tree_parse(sd->filter2->head,
1338 ltt_tracefile_get_event(tfc->tf),
1339 tfc->tf,
1340 tfc->t_context->t,
b6ef18af 1341 tfc,NULL,NULL)) {
b139ad2a 1342 return FALSE;
1343 }
1344 if(sd->filter3 != NULL && sd->filter3->head != NULL &&
1345 !lttv_filter_tree_parse(sd->filter3->head,
1346 ltt_tracefile_get_event(tfc->tf),
1347 tfc->tf,
1348 tfc->t_context->t,
b6ef18af 1349 tfc,NULL,NULL)) {
b139ad2a 1350 return FALSE;
1351 }
1352
33e44b82 1353 pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array,
1354 sd->first_event);
0bd2f89c 1355
1356 lttv_traceset_context_position_save(tsc, pos);
1357
1358 if(sd->first_event >= sd->array->len - 1) sd->first_event = 0;
1359 else sd->first_event++;
1360
33e44b82 1361 sd->events_found = min(sd->n, sd->events_found + 1);
0bd2f89c 1362
1363 return FALSE;
1364}
1365
0bd2f89c 1366/* Seek back n events back from the current position.
1367 *
1368 * Parameters :
1369 * @self The trace set context
1370 * @n number of events to jump over
9ba3aaaf 1371 * @first_offset The initial offset value used.
33e44b82 1372 * never put first_offset at ltt_time_zero.
1373 * @time_seeker Function pointer of the function to use to seek time :
1374 * either lttv_process_traceset_seek_time
1375 * or lttv_state_traceset_seek_time_closest
1376 * @filter The filter to call.
0bd2f89c 1377 *
1378 * Return value : the number of events found (might be lower than the number
1379 * requested if beginning of traceset is reached).
1380 *
1381 * The first search will go back first_offset and try to find the last n events
1382 * matching the filter. If there are not enough, it will try to go back from the
1383 * new trace point from first_offset*2, and so on, until beginning of trace or n
1384 * events are found.
1385 *
1386 * Note : this function does not take in account the LttvFilter : use the
1387 * similar function found in state.c instead.
1388 *
1389 * Note2 : the caller must make sure that the LttvTracesetContext does not
1390 * contain any hook, as process_traceset_middle is used in this routine.
1391 */
1392guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
33e44b82 1393 guint n, LttTime first_offset,
1394 seek_time_fct time_seeker,
04f2543e 1395 check_handler *check,
b139ad2a 1396 gboolean *stop_flag,
1397 LttvFilter *filter1,
1398 LttvFilter *filter2,
fb3d6047 1399 LttvFilter *filter3,
1400 gpointer data)
0bd2f89c 1401{
33e44b82 1402 if(lttv_traceset_number(self->ts) == 0) return 0;
1403 g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
1404
0bd2f89c 1405 guint i;
1406 LttvTracesetContextPosition *next_iter_end_pos =
9ba3aaaf 1407 lttv_traceset_context_position_new(self);
1408 LttvTracesetContextPosition *end_pos =
1409 lttv_traceset_context_position_new(self);
1410 LttvTracesetContextPosition *saved_pos =
1411 lttv_traceset_context_position_new(self);
0bd2f89c 1412 LttTime time;
9d227699 1413 LttTime asked_time;
0bd2f89c 1414 LttTime time_offset;
1415 struct seek_back_data sd;
1416 LttvHooks *hooks = lttv_hooks_new();
1417
1418 sd.first_event = 0;
1419 sd.events_found = 0;
1420 sd.array = g_ptr_array_sized_new(n);
b139ad2a 1421 sd.filter1 = filter1;
1422 sd.filter2 = filter2;
1423 sd.filter3 = filter3;
fb3d6047 1424 sd.data = data;
33e44b82 1425 sd.n = n;
04f2543e 1426 sd.check = check;
1427 sd.stop_flag = stop_flag;
1428 sd.raw_event_count = 0;
0bd2f89c 1429 g_ptr_array_set_size(sd.array, n);
1430 for(i=0;i<n;i++) {
9ba3aaaf 1431 g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new(self);
0bd2f89c 1432 }
33e44b82 1433
0bd2f89c 1434 lttv_traceset_context_position_save(self, next_iter_end_pos);
33e44b82 1435 lttv_traceset_context_position_save(self, saved_pos);
0bd2f89c 1436 /* Get the current time from which we will offset */
1437 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1438 /* the position saved might be end of traceset... */
1439 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1440 time = self->time_span.end_time;
1441 }
9d227699 1442 asked_time = time;
0bd2f89c 1443 time_offset = first_offset;
1444
1445 lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT);
1446
1447 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1448
1449 while(1) {
1450 /* stop criteria : - n events found
9d227699 1451 * - asked_time < beginning of trace */
1452 if(ltt_time_compare(asked_time, self->time_span.start_time) < 0) break;
0bd2f89c 1453
1454 lttv_traceset_context_position_copy(end_pos, next_iter_end_pos);
1455
1456 /* We must seek the traceset back to time - time_offset */
1457 /* this time becomes the new reference time */
1458 time = ltt_time_sub(time, time_offset);
9d227699 1459 asked_time = time;
0bd2f89c 1460
33e44b82 1461 time_seeker(self, time);
0bd2f89c 1462 lttv_traceset_context_position_save(self, next_iter_end_pos);
33e44b82 1463 /* Resync the time in case of a seek_closest */
1464 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1465 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1466 time = self->time_span.end_time;
1467 }
0bd2f89c 1468
1469 /* Process the traceset, calling a hook which adds events
1470 * to the array, overwriting the tail. It changes first_event and
1471 * events_found too. */
1472 /* We would like to have a clean context here : no other hook than our's */
1473
1474 lttv_process_traceset_middle(self, ltt_time_infinite,
1475 G_MAXUINT, end_pos);
1476
33e44b82 1477 if(sd.events_found < n) {
1478 if(sd.first_event > 0) {
1479 /* Save the first position */
1480 LttvTracesetContextPosition *pos =
1481 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0);
1482 lttv_traceset_context_position_copy(saved_pos, pos);
1483 }
1484 g_assert(n-sd.events_found <= sd.array->len);
1485 /* Change array size to n - events_found */
1486 for(i=n-sd.events_found;i<sd.array->len;i++) {
1487 LttvTracesetContextPosition *pos =
1488 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1489 lttv_traceset_context_position_destroy(pos);
1490 }
1491 g_ptr_array_set_size(sd.array, n-sd.events_found);
1492 sd.first_event = 0;
1493
1494 } else break; /* Second end criterion : n events found */
1495
0bd2f89c 1496 time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL);
1497 }
1498
1499 lttv_traceset_context_position_destroy(end_pos);
1500 lttv_traceset_context_position_destroy(next_iter_end_pos);
1501
1502 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1503
33e44b82 1504 if(sd.events_found >= n) {
0bd2f89c 1505 /* Seek the traceset to the first event in the circular array */
1506 LttvTracesetContextPosition *pos =
1507 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array,
1508 sd.first_event);
1509 g_assert(lttv_process_traceset_seek_position(self, pos) == 0);
33e44b82 1510 } else {
1511 /* Will seek to the last saved position : in the worst case, it will be the
1512 * original position (if events_found is 0) */
1513 g_assert(lttv_process_traceset_seek_position(self, saved_pos) == 0);
0bd2f89c 1514 }
1515
33e44b82 1516 for(i=0;i<sd.array->len;i++) {
0bd2f89c 1517 LttvTracesetContextPosition *pos =
1518 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1519 lttv_traceset_context_position_destroy(pos);
1520 }
1521 g_ptr_array_free(sd.array, TRUE);
1522
1523 lttv_hooks_destroy(hooks);
1524
33e44b82 1525 lttv_traceset_context_position_destroy(saved_pos);
1526
0bd2f89c 1527 return sd.events_found;
1528}
1529
1530
1531struct seek_forward_data {
1532 guint event_count; /* event counter */
1533 guint n; /* requested number of events to jump over */
b139ad2a 1534 LttvFilter *filter1;
1535 LttvFilter *filter2;
1536 LttvFilter *filter3;
fb3d6047 1537 gpointer data;
04f2543e 1538 check_handler *check;
1539 gboolean *stop_flag;
1540 guint raw_event_count; /* event counter */
0bd2f89c 1541};
1542
1543static gint seek_forward_event_hook(void *hook_data, void* call_data)
1544{
1545 struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
33e44b82 1546 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
0bd2f89c 1547
fb3d6047 1548 if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag, sd->data))
1549 return TRUE;
04f2543e 1550 sd->raw_event_count++;
1551
b139ad2a 1552 if(sd->filter1 != NULL && sd->filter1->head != NULL &&
1553 !lttv_filter_tree_parse(sd->filter1->head,
33e44b82 1554 ltt_tracefile_get_event(tfc->tf),
1555 tfc->tf,
1556 tfc->t_context->t,
b6ef18af 1557 tfc,NULL,NULL)) {
b139ad2a 1558 return FALSE;
1fae3dd3 1559 }
b139ad2a 1560 if(sd->filter2 != NULL && sd->filter2->head != NULL &&
1561 !lttv_filter_tree_parse(sd->filter2->head,
1562 ltt_tracefile_get_event(tfc->tf),
1563 tfc->tf,
1564 tfc->t_context->t,
b6ef18af 1565 tfc,NULL,NULL)) {
b139ad2a 1566 return FALSE;
1567 }
1568 if(sd->filter3 != NULL && sd->filter3->head != NULL &&
1569 !lttv_filter_tree_parse(sd->filter3->head,
1570 ltt_tracefile_get_event(tfc->tf),
1571 tfc->tf,
1572 tfc->t_context->t,
b6ef18af 1573 tfc,NULL,NULL)) {
b139ad2a 1574 return FALSE;
1575 }
1576
1577 sd->event_count++;
1578 if(sd->event_count >= sd->n)
1579 return TRUE;
e594b7fd 1580 return FALSE;
0bd2f89c 1581}
1582
aaecaa99 1583/* Seek back n events forward from the current position (1 to n)
1584 * 0 is ok too, but it will actually do nothing.
0bd2f89c 1585 *
1586 * Parameters :
33e44b82 1587 * @self the trace set context
1588 * @n number of events to jump over
1589 * @filter filter to call.
0bd2f89c 1590 *
1591 * returns : the number of events jumped over (may be less than requested if end
1592 * of traceset reached) */
1593guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
b139ad2a 1594 guint n,
04f2543e 1595 check_handler *check,
b139ad2a 1596 gboolean *stop_flag,
1597 LttvFilter *filter1,
1598 LttvFilter *filter2,
fb3d6047 1599 LttvFilter *filter3,
1600 gpointer data)
0bd2f89c 1601{
1602 struct seek_forward_data sd;
1603 sd.event_count = 0;
1604 sd.n = n;
b139ad2a 1605 sd.filter1 = filter1;
1606 sd.filter2 = filter2;
1607 sd.filter3 = filter3;
fb3d6047 1608 sd.data = data;
04f2543e 1609 sd.check = check;
1610 sd.stop_flag = stop_flag;
1611 sd.raw_event_count = 0;
aaecaa99 1612
1613 if(sd.event_count >= sd.n) return sd.event_count;
1614
0bd2f89c 1615 LttvHooks *hooks = lttv_hooks_new();
1616
1617 lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
1618
1619 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1620
1621 /* it will end on the end of traceset, or the fact that the
aaecaa99 1622 * hook returns TRUE.
0bd2f89c 1623 */
1624 lttv_process_traceset_middle(self, ltt_time_infinite,
1625 G_MAXUINT, NULL);
1626
1627 /* Here, our position is either the end of traceset, or the exact position
aaecaa99 1628 * after n events : leave it like this. This might be placed on an event that
1629 * will be filtered out, we don't care : all we know is that the following
1630 * event filtered in will be the right one. */
0bd2f89c 1631
1632 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1633
1634 lttv_hooks_destroy(hooks);
1635
1636 return sd.event_count;
1637}
1638
1639
This page took 0.215522 seconds and 4 git commands to generate.