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