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