free bugfix
[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>
d8f124de 24#include <lttv/tracecontext.h>
ffd54a90 25#include <ltt/event.h>
b445142a 26#include <ltt/facility.h>
a5dcde2f 27#include <ltt/trace.h>
28#include <ltt/type.h>
33e44b82 29#include <lttv/filter.h>
27304273 30#include <errno.h>
dc877563 31
0bd2f89c 32#define min(a,b) (((a)<(b))?(a):(b))
8697a616 33
34
27304273 35gint compare_tracefile(gconstpointer a, gconstpointer b)
8697a616 36{
cf94ff67 37 gint comparison = 0;
8697a616 38
00e74b69 39 const LttvTracefileContext *trace_a = (const LttvTracefileContext *)a;
00e74b69 40 const LttvTracefileContext *trace_b = (const LttvTracefileContext *)b;
8697a616 41
1d1df11d 42 if(likely(trace_a != trace_b)) {
8fe3c6b6 43 comparison = ltt_time_compare(trace_a->timestamp, trace_b->timestamp);
1d1df11d 44 if(unlikely(comparison == 0)) {
a855f059 45 if(trace_a->index < trace_b->index) comparison = -1;
46 else if(trace_a->index > trace_b->index) comparison = 1;
47 else if(trace_a->t_context->index < trace_b->t_context->index)
48 comparison = -1;
49 else if(trace_a->t_context->index > trace_b->t_context->index)
50 comparison = 1;
51 }
cf94ff67 52 }
cf94ff67 53 return comparison;
8697a616 54}
55
9ba3aaaf 56typedef struct _LttvTracefileContextPosition {
57 LttEventPosition *event;
58 LttvTracefileContext *tfc;
59 gboolean used; /* Tells if the tfc is at end of traceset position */
60} LttvTracefileContextPosition;
61
62
8697a616 63struct _LttvTracesetContextPosition {
9ba3aaaf 64 GArray *tfcp; /* Array of LttvTracefileContextPosition */
18c87975 65 LttTime timestamp; /* Current time at the saved position */
66 /* If ltt_time_infinite : no position is
67 * set, else, a position is set (may be end
68 * of trace, with ep->len == 0) */
8697a616 69};
70
ffd54a90 71void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts)
dc877563 72{
ffd54a90 73 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->init(self, ts);
dc877563 74}
75
76
77void lttv_context_fini(LttvTracesetContext *self)
78{
79 LTTV_TRACESET_CONTEXT_GET_CLASS(self)->fini(self);
80}
81
82
83LttvTracesetContext *
84lttv_context_new_traceset_context(LttvTracesetContext *self)
85{
86 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_traceset_context(self);
87}
88
89
90
91
92LttvTraceContext *
93lttv_context_new_trace_context(LttvTracesetContext *self)
94{
95 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_trace_context(self);
96}
97
98
99LttvTracefileContext *
100lttv_context_new_tracefile_context(LttvTracesetContext *self)
101{
c6bc9cb9 102 return LTTV_TRACESET_CONTEXT_GET_CLASS(self)->new_tracefile_context(self);
dc877563 103}
104
f7afe191 105/****************************************************************************
106 * lttv_traceset_context_compute_time_span
107 *
8697a616 108 * Keep the time span is sync with on the fly addition and removal of traces
f7afe191 109 * in a trace set. It must be called each time a trace is added/removed from
110 * the traceset. It could be more efficient to call it only once a bunch
111 * of traces are loaded, but the calculation is not long, so it's not
112 * critical.
113 *
114 * Author : Xang Xiu Yang
f7afe191 115 ***************************************************************************/
116static void lttv_traceset_context_compute_time_span(
117 LttvTracesetContext *self,
33f7a12c 118 TimeInterval *time_span)
f7afe191 119{
120 LttvTraceset * traceset = self->ts;
121 int numTraces = lttv_traceset_number(traceset);
122 int i;
123 LttTime s, e;
124 LttvTraceContext *tc;
125 LttTrace * trace;
126
33f7a12c 127 time_span->start_time.tv_sec = 0;
128 time_span->start_time.tv_nsec = 0;
129 time_span->end_time.tv_sec = 0;
130 time_span->end_time.tv_nsec = 0;
912be9a5 131
f7afe191 132 for(i=0; i<numTraces;i++){
133 tc = self->traces[i];
134 trace = tc->t;
135
136 ltt_trace_time_span_get(trace, &s, &e);
14aecf75 137 tc->time_span.start_time = s;
138 tc->time_span.end_time = e;
f7afe191 139
140 if(i==0){
33f7a12c 141 time_span->start_time = s;
142 time_span->end_time = e;
f7afe191 143 }else{
33f7a12c 144 if(s.tv_sec < time_span->start_time.tv_sec
145 || (s.tv_sec == time_span->start_time.tv_sec
146 && s.tv_nsec < time_span->start_time.tv_nsec))
147 time_span->start_time = s;
148 if(e.tv_sec > time_span->end_time.tv_sec
149 || (e.tv_sec == time_span->end_time.tv_sec
150 && e.tv_nsec > time_span->end_time.tv_nsec))
151 time_span->end_time = e;
f7afe191 152 }
153 }
154}
155
eed2ef37 156static void init_tracefile_context(LttTracefile *tracefile,
157 LttvTraceContext *tc)
158{
159 LttvTracefileContext *tfc;
160 LttvTracesetContext *tsc = tc->ts_context;
161
162 tfc = LTTV_TRACESET_CONTEXT_GET_CLASS(tsc)->new_tracefile_context(tsc);
163
164 tfc->index = tc->tracefiles->len;
165 tc->tracefiles = g_array_append_val(tc->tracefiles, tfc);
166
167 tfc->tf = tracefile;
168
169 tfc->t_context = tc;
170 tfc->event = lttv_hooks_new();
171 tfc->event_by_id = lttv_hooks_by_id_new();
172 tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
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
698e81c2 694 guint fac_id, ev_id, id;
2a2fa4f0 695
2a2fa4f0 696 LttvTracefileContext *tfc;
697
eed2ef37 698 LttEvent *e;
699
2a2fa4f0 700 unsigned count = 0;
701
36d36c9f 702 guint read_ret;
703
bd4c3eca 704 //enum read_state last_read_state = LAST_NONE;
698e81c2 705
78b82ded 706 gint last_ret = 0; /* return value of the last hook list called */
a54f091a 707
dc877563 708 /* Get the next event from the pqueue, call its hooks,
709 reinsert in the pqueue the following event from the same tracefile
710 unless the tracefile is finished or the event is later than the
8697a616 711 end time. */
dc877563 712
ffd54a90 713 while(TRUE) {
dc877563 714 tfc = NULL;
715 g_tree_foreach(pqueue, get_first, &tfc);
33f7a12c 716 /* End of traceset : tfc is NULL */
1d1df11d 717 if(unlikely(tfc == NULL))
a43d67ba 718 {
a43d67ba 719 return count;
720 }
dc877563 721
8697a616 722 /* Have we reached :
723 * - the maximum number of events specified?
724 * - the end position ?
725 * - the end time ?
726 * then the read is finished. We leave the queue in the same state and
727 * break the loop.
728 */
729
1d1df11d 730 if(unlikely(last_ret == TRUE ||
d052ffc3 731 ((count >= nb_events) && (nb_events != G_MAXULONG)) ||
8b0bbe19 732 (end_position!=NULL&&lttv_traceset_context_ctx_pos_compare(self,
733 end_position) == 0)||
1d1df11d 734 ltt_time_compare(end, tfc->timestamp) <= 0))
a43d67ba 735 {
a43d67ba 736 return count;
737 }
36d36c9f 738
308711e5 739 /* Get the tracefile with an event for the smallest time found. If two
740 or more tracefiles have events for the same time, hope that lookup
741 and remove are consistent. */
1986f254 742
743#ifdef DEBUG
e7f5e89d 744 test_time.tv_sec = 0;
745 test_time.tv_nsec = 0;
77199e93 746 g_debug("test tree before remove");
747 g_tree_foreach(pqueue, test_tree, tfc);
1986f254 748#endif //DEBUG
f95bc830 749 g_tree_remove(pqueue, tfc);
698e81c2 750
1986f254 751#ifdef DEBUG
e7f5e89d 752 test_time.tv_sec = 0;
753 test_time.tv_nsec = 0;
77199e93 754 g_debug("test tree after remove");
698e81c2 755 g_tree_foreach(pqueue, test_tree, tfc);
1986f254 756#endif //DEBUG
77199e93 757
bd4c3eca 758
eed2ef37 759 e = ltt_tracefile_get_event(tfc->tf);
dc877563 760
bd4c3eca 761 //if(last_read_state != LAST_EMPTY) {
762 /* Only call hooks if the last read has given an event or if we are at the
763 * first pass (not if last read returned end of tracefile) */
764 count++;
765
766 fac_id = ltt_event_facility_id(e);
767 ev_id = ltt_event_eventtype_id(e);
768 id = GET_HOOK_ID(fac_id, ev_id);
1fae3dd3 769 /* Hooks :
770 * return values : 0 : continue read, 1 : go to next position and stop read,
771 * 2 : stay at the current position and stop read */
bd4c3eca 772 last_ret = lttv_hooks_call_merge(tfc->event, tfc,
773 lttv_hooks_by_id_get(tfc->event_by_id, id), tfc);
1fae3dd3 774
876b4889 775 if(unlikely(last_ret == 2)) {
1fae3dd3 776 /* This is a case where we want to stay at this position and stop read. */
777 g_tree_insert(pqueue, tfc, tfc);
778 return count - 1;
779 }
36d36c9f 780
698e81c2 781 read_ret = ltt_tracefile_read(tfc->tf);
1fae3dd3 782
783
698e81c2 784 if(likely(!read_ret)) {
3054461a 785 //g_debug("An event is ready");
eed2ef37 786 tfc->timestamp = ltt_event_time(e);
e7f5e89d 787 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
33f7a12c 788 g_tree_insert(pqueue, tfc, tfc);
e7f5e89d 789#ifdef DEBUG
790 test_time.tv_sec = 0;
791 test_time.tv_nsec = 0;
792 g_debug("test tree after event ready");
793 g_tree_foreach(pqueue, test_tree, NULL);
794#endif //DEBUG
795
bd4c3eca 796 //last_read_state = LAST_OK;
698e81c2 797 } else {
1986f254 798 tfc->timestamp = ltt_time_infinite;
799
36d36c9f 800 if(read_ret == ERANGE) {
bd4c3eca 801 // last_read_state = LAST_EMPTY;
698e81c2 802 g_debug("End of trace");
36d36c9f 803 } else
698e81c2 804 g_error("Error happened in lttv_process_traceset_middle");
dc877563 805 }
806 }
2a2fa4f0 807}
808
809
8697a616 810void lttv_process_traceset_end(LttvTracesetContext *self,
811 LttvHooks *after_traceset,
812 LttvHooks *after_trace,
813 LttvHooks *after_tracefile,
814 LttvHooks *event,
815 LttvHooksById *event_by_id)
2a2fa4f0 816{
8697a616 817 /* Remove hooks from context. _after hooks are called by remove_hooks. */
818 /* It calls all after_traceset, after_trace, and after_tracefile hooks. */
819 lttv_traceset_context_remove_hooks(self,
820 after_traceset,
821 after_trace,
822 after_tracefile,
823 event,
824 event_by_id);
825}
2a2fa4f0 826
27304273 827/* Subtile modification :
828 * if tracefile has no event at or after the time requested, it is not put in
348c6ba8 829 * the queue, as the next read would fail.
830 *
831 * Don't forget to empty the traceset pqueue before calling this.
832 */
8697a616 833void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start)
834{
835 guint i, nb_tracefile;
2a2fa4f0 836
eed2ef37 837 gint ret;
838
1986f254 839 LttvTracefileContext **tfc;
2a2fa4f0 840
eed2ef37 841 nb_tracefile = self->tracefiles->len;
dc877563 842
e7f5e89d 843 GTree *pqueue = self->ts_context->pqueue;
844
8697a616 845 for(i = 0 ; i < nb_tracefile ; i++) {
1986f254 846 tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i);
77199e93 847
d448fce2 848 g_tree_remove(pqueue, *tfc);
77199e93 849
1986f254 850 ret = ltt_tracefile_seek_time((*tfc)->tf, start);
27304273 851 if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek");
27304273 852
853 if(ret == 0) { /* not ERANGE especially */
1986f254 854 (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf));
e7f5e89d 855 g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0);
1986f254 856 g_tree_insert(pqueue, (*tfc), (*tfc));
857 } else {
858 (*tfc)->timestamp = ltt_time_infinite;
27304273 859 }
8697a616 860 }
e7f5e89d 861#ifdef DEBUG
862 test_time.tv_sec = 0;
863 test_time.tv_nsec = 0;
864 g_debug("test tree after seek_time");
865 g_tree_foreach(pqueue, test_tree, NULL);
866#endif //DEBUG
867
868
869
8697a616 870}
dc877563 871
2a2fa4f0 872
8697a616 873void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start)
874{
875 guint i, nb_trace;
2a2fa4f0 876
8697a616 877 LttvTraceContext *tc;
2a2fa4f0 878
d448fce2 879 //g_tree_destroy(self->pqueue);
880 //self->pqueue = g_tree_new(compare_tracefile);
348c6ba8 881
8697a616 882 nb_trace = lttv_traceset_number(self->ts);
883 for(i = 0 ; i < nb_trace ; i++) {
884 tc = self->traces[i];
885 lttv_process_trace_seek_time(tc, start);
886 }
dc877563 887}
b445142a 888
308711e5 889
8697a616 890gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self,
891 const LttvTracesetContextPosition *pos)
308711e5 892{
27304273 893 guint i;
d448fce2 894 /* If a position is set, seek the traceset to this position */
18c87975 895 if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) {
d448fce2 896
897 /* Test to see if the traces has been added to the trace set :
898 * It should NEVER happen. Clear all positions if a new trace comes in. */
899 /* FIXME I know this test is not optimal : should keep a number of
900 * tracefiles variable in the traceset.. eventually */
901 guint num_traces = lttv_traceset_number(self->ts);
902 guint tf_count = 0;
903 for(i=0; i<num_traces;i++) {
904 GArray * tracefiles = self->traces[i]->tracefiles;
905 guint j;
906 guint num_tracefiles = tracefiles->len;
907 for(j=0;j<num_tracefiles;j++)
908 tf_count++;
909 }
910 g_assert(tf_count == pos->tfcp->len);
911
912
913 //g_tree_destroy(self->pqueue);
914 //self->pqueue = g_tree_new(compare_tracefile);
18c87975 915
9ba3aaaf 916 for(i=0;i<pos->tfcp->len; i++) {
917 LttvTracefileContextPosition *tfcp =
918 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
d448fce2 919
920 g_tree_remove(self->pqueue, tfcp->tfc);
9ba3aaaf 921
922 if(tfcp->used == TRUE) {
923 if(ltt_tracefile_seek_position(tfcp->tfc->tf, tfcp->event) != 0)
18c87975 924 return 1;
9ba3aaaf 925 tfcp->tfc->timestamp =
926 ltt_event_time(ltt_tracefile_get_event(tfcp->tfc->tf));
927 g_assert(ltt_time_compare(tfcp->tfc->timestamp,
928 ltt_time_infinite) != 0);
929 g_tree_insert(self->pqueue, tfcp->tfc, tfcp->tfc);
930
18c87975 931 } else {
9ba3aaaf 932 tfcp->tfc->timestamp = ltt_time_infinite;
18c87975 933 }
1986f254 934 }
308711e5 935 }
e7f5e89d 936#ifdef DEBUG
937 test_time.tv_sec = 0;
938 test_time.tv_nsec = 0;
939 g_debug("test tree after seek_position");
940 g_tree_foreach(self->pqueue, test_tree, NULL);
941#endif //DEBUG
942
943
944
2c82c4dc 945 return 0;
308711e5 946}
947
948
8697a616 949
b445142a 950static LttField *
eed2ef37 951find_field(LttEventType *et, const GQuark field)
b445142a 952{
953 LttType *t;
954
955 LttField *f;
956
957 guint i, nb;
958
eed2ef37 959 GQuark name;
b445142a 960
eed2ef37 961 /* Field is unset */
962 if(field == 0) return NULL;
963
b445142a 964 f = ltt_eventtype_field(et);
965 t = ltt_eventtype_type(et);
966 g_assert(ltt_type_class(t) == LTT_STRUCT);
967 nb = ltt_type_member_number(t);
968 for(i = 0 ; i < nb ; i++) {
969 ltt_type_member_type(t, i, &name);
eed2ef37 970 if(name == field) break;
b445142a 971 }
972 g_assert(i < nb);
973 return ltt_field_member(f, i);
974}
975
eed2ef37 976LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th,
977 guint facility_id)
978{
979 return &g_array_index(th->fac_index, LttvTraceHookByFacility, facility_id);
980}
981
982/* Get the first facility corresponding to the name. As the types must be
983 * compatible, it is relevant to use the field name and sizes of the first
984 * facility to create data structures and assume the data will be compatible
985 * thorough the trace */
986LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th)
987{
988 g_assert(th->fac_list->len > 0);
989 return g_array_index(th->fac_list, LttvTraceHookByFacility*, 0);
990}
991
b445142a 992
eed2ef37 993/* Returns 0 on success, -1 if fails. */
994gint
995lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event,
2c82c4dc 996 GQuark field1, GQuark field2, GQuark field3, LttvHook h, gpointer hook_data,
997 LttvTraceHook *th)
b445142a 998{
999 LttFacility *f;
1000
eed2ef37 1001 LttEventType *et, *first_et;
1002
1003 GArray *facilities;
1004
d052ffc3 1005 guint i, fac_id, ev_id;
b445142a 1006
eed2ef37 1007 LttvTraceHookByFacility *thf, *first_thf;
b445142a 1008
eed2ef37 1009 facilities = ltt_trace_facility_get_by_name(t, facility);
021eeb41 1010
eed2ef37 1011 if(unlikely(facilities == NULL)) goto facility_error;
1012
1013 th->fac_index = g_array_sized_new(FALSE, TRUE,
1014 sizeof(LttvTraceHookByFacility),
1015 NUM_FACILITIES);
1016 th->fac_index = g_array_set_size(th->fac_index, NUM_FACILITIES);
b445142a 1017
eed2ef37 1018 th->fac_list = g_array_sized_new(FALSE, TRUE,
1019 sizeof(LttvTraceHookByFacility*),
1020 facilities->len);
1021 th->fac_list = g_array_set_size(th->fac_list, facilities->len);
1022
1023 fac_id = g_array_index(facilities, guint, 0);
1024 f = ltt_trace_get_facility_by_num(t, fac_id);
1025
cb03932a 1026 et = ltt_facility_eventtype_get_by_name(f, event);
eed2ef37 1027 if(unlikely(et == NULL)) goto event_error;
1028
1029 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1986f254 1030 g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf;
9d239bd9 1031
d052ffc3 1032 ev_id = ltt_eventtype_id(et);
1033
eed2ef37 1034 thf->h = h;
d052ffc3 1035 thf->id = GET_HOOK_ID(fac_id, ev_id);
eed2ef37 1036 thf->f1 = find_field(et, field1);
1037 thf->f2 = find_field(et, field2);
1038 thf->f3 = find_field(et, field3);
2c82c4dc 1039 thf->hook_data = hook_data;
eed2ef37 1040
1041 first_thf = thf;
826f1ab2 1042 first_et = et;
eed2ef37 1043
1044 /* Check for type compatibility too */
1045 for(i=1;i<facilities->len;i++) {
1046 fac_id = g_array_index(facilities, guint, i);
1047 f = ltt_trace_get_facility_by_num(t, fac_id);
1048
f4b88a7d 1049 et = ltt_facility_eventtype_get_by_name(f, event);
eed2ef37 1050 if(unlikely(et == NULL)) goto event_error;
1051
1052 thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id);
1986f254 1053 g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf;
d052ffc3 1054 ev_id = ltt_eventtype_id(et);
eed2ef37 1055 thf->h = h;
d052ffc3 1056 thf->id = GET_HOOK_ID(fac_id, ev_id);
eed2ef37 1057 thf->f1 = find_field(et, field1);
1058 if(check_fields_compatibility(first_et, et,
1059 first_thf->f1, thf->f1))
1060 goto type_error;
1061
1062 thf->f2 = find_field(et, field2);
1063 if(check_fields_compatibility(first_et, et,
1064 first_thf->f2, thf->f2))
1065 goto type_error;
1066
1067 thf->f3 = find_field(et, field3);
1068 if(check_fields_compatibility(first_et, et,
1069 first_thf->f3, thf->f3))
1070 goto type_error;
2c82c4dc 1071 thf->hook_data = hook_data;
eed2ef37 1072 }
1073
1074 return 0;
1075
1076type_error:
1077 goto free;
1078event_error:
f4b88a7d 1079 g_error("Event type does not exist for event %s",
1080 g_quark_to_string(event));
eed2ef37 1081 goto free;
1082facility_error:
1083 g_error("No %s facility", g_quark_to_string(facility));
1084 goto free;
1085free:
1086 g_array_free(th->fac_index, TRUE);
1087 g_array_free(th->fac_list, TRUE);
1088 th->fac_index = NULL;
1089 th->fac_list = NULL;
1090 return -1;
1091}
1092
1093void lttv_trace_hook_destroy(LttvTraceHook *th)
1094{
1095 g_array_free(th->fac_index, TRUE);
1096 g_array_free(th->fac_list, TRUE);
b445142a 1097}
1098
1099
9ba3aaaf 1100
1101
1102LttvTracesetContextPosition *lttv_traceset_context_position_new(
1103 const LttvTracesetContext *self)
5e2c04a2 1104{
9ba3aaaf 1105 guint num_traces = lttv_traceset_number(self->ts);
1106 guint tf_count = 0;
1107 guint i;
1108
1109 for(i=0; i<num_traces;i++) {
1110 GArray * tracefiles = self->traces[i]->tracefiles;
1111 guint j;
1112 guint num_tracefiles = tracefiles->len;
1113 for(j=0;j<num_tracefiles;j++)
1114 tf_count++;
1115 }
1116 LttvTracesetContextPosition *pos =
1117 g_new(LttvTracesetContextPosition, 1);
1118 pos->tfcp = g_array_sized_new(FALSE, TRUE,
1119 sizeof(LttvTracefileContextPosition),
1120 tf_count);
1121 g_array_set_size(pos->tfcp, tf_count);
1122 for(i=0;i<pos->tfcp->len;i++) {
1123 LttvTracefileContextPosition *tfcp =
1124 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1125 tfcp->event = ltt_event_position_new();
1126 }
1127
27304273 1128 pos->timestamp = ltt_time_infinite;
1129 return pos;
5e2c04a2 1130}
1131
3054461a 1132/* Save all positions, the ones with infinite time will have NULL
1986f254 1133 * ep. */
9ba3aaaf 1134/* note : a position must be destroyed when a trace is added/removed from a
1135 * traceset */
27304273 1136void lttv_traceset_context_position_save(const LttvTracesetContext *self,
1137 LttvTracesetContextPosition *pos)
1138{
1986f254 1139 guint i;
1140 guint num_traces = lttv_traceset_number(self->ts);
9ba3aaaf 1141 guint tf_count = 0;
728d0c3e 1142
0bd2f89c 1143 pos->timestamp = ltt_time_infinite;
728d0c3e 1144
1986f254 1145 for(i=0; i<num_traces;i++) {
1146 GArray * tracefiles = self->traces[i]->tracefiles;
1147 guint j;
1148 guint num_tracefiles = tracefiles->len;
1149
1150 for(j=0;j<num_tracefiles;j++) {
9ba3aaaf 1151 g_assert(tf_count < pos->tfcp->len);
1986f254 1152 LttvTracefileContext **tfc = &g_array_index(tracefiles,
1153 LttvTracefileContext*, j);
9ba3aaaf 1154 LttvTracefileContextPosition *tfcp =
1155 &g_array_index(pos->tfcp, LttvTracefileContextPosition, tf_count);
1986f254 1156
9ba3aaaf 1157 tfcp->tfc = *tfc;
1986f254 1158
1159 if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) {
9ba3aaaf 1160 LttEvent *event = ltt_tracefile_get_event((*tfc)->tf);
1161 ltt_event_position(event, tfcp->event);
1986f254 1162 if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0)
1163 pos->timestamp = (*tfc)->timestamp;
9ba3aaaf 1164 tfcp->used = TRUE;
1986f254 1165 } else {
9ba3aaaf 1166 tfcp->used = FALSE;
1986f254 1167 }
9ba3aaaf 1168
1169 //g_array_append_val(pos->tfc, *tfc);
1170 //g_array_append_val(pos->ep, ep);
1171 tf_count++;
1986f254 1172 }
1173
1174 }
8697a616 1175}
1176
1177void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos)
1178{
27304273 1179 int i;
1986f254 1180
9ba3aaaf 1181 for(i=0;i<pos->tfcp->len;i++) {
1182 LttvTracefileContextPosition *tfcp =
1183 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1184 g_free(tfcp->event);
1185 tfcp->event = NULL;
1186 tfcp->used = FALSE;
1986f254 1187 }
9ba3aaaf 1188 g_array_free(pos->tfcp, TRUE);
27304273 1189 g_free(pos);
8697a616 1190}
1191
5e2c04a2 1192void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest,
1193 const LttvTracesetContextPosition *src)
1194{
27304273 1195 int i;
9ba3aaaf 1196 LttvTracefileContextPosition *src_tfcp, *dest_tfcp;
5e2c04a2 1197
9ba3aaaf 1198 g_assert(src->tfcp->len == src->tfcp->len);
27304273 1199
9ba3aaaf 1200 for(i=0;i<src->tfcp->len;i++) {
1201 src_tfcp =
1202 &g_array_index(src->tfcp, LttvTracefileContextPosition, i);
1203 dest_tfcp =
1204 &g_array_index(dest->tfcp, LttvTracefileContextPosition, i);
1205
1206 dest_tfcp->used = src_tfcp->used;
1207 dest_tfcp->tfc = src_tfcp->tfc;
1208
1209 if(src_tfcp->used) {
1986f254 1210 ltt_event_position_copy(
9ba3aaaf 1211 dest_tfcp->event,
1212 src_tfcp->event);
1213 }
5e2c04a2 1214 }
5e2c04a2 1215 dest->timestamp = src->timestamp;
1216}
1217
8697a616 1218gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self,
1219 const LttvTracesetContextPosition *pos)
1220{
27304273 1221 int i;
826f1ab2 1222 int ret = 0;
2c82c4dc 1223
9ba3aaaf 1224 if(pos->tfcp->len == 0) {
2c82c4dc 1225 if(lttv_traceset_number(self->ts) == 0) return 0;
1226 else return 1;
1227 }
1228 if(lttv_traceset_number(self->ts) == 0)
1229 return -1;
1230
9ba3aaaf 1231 for(i=0;i<pos->tfcp->len;i++) {
1232 LttvTracefileContextPosition *tfcp =
1233 &g_array_index(pos->tfcp, LttvTracefileContextPosition, i);
1986f254 1234
9ba3aaaf 1235 if(tfcp->used == FALSE) {
1236 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) < 0) {
1986f254 1237 ret = -1;
1238 }
1239 } else {
9ba3aaaf 1240 if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) == 0) {
1986f254 1241 ret = 1;
1242 } else {
9ba3aaaf 1243 LttEvent *event = ltt_tracefile_get_event(tfcp->tfc->tf);
8697a616 1244
1986f254 1245 ret = ltt_event_position_compare((LttEventPosition*)event,
9ba3aaaf 1246 tfcp->event);
1986f254 1247 }
1248 }
27304273 1249 if(ret != 0) return ret;
8697a616 1250
8697a616 1251 }
1252 return 0;
1253}
1254
1255
1256gint lttv_traceset_context_pos_pos_compare(
1257 const LttvTracesetContextPosition *pos1,
1258 const LttvTracesetContextPosition *pos2)
1259{
27304273 1260 int i, j;
b4aeb12d 1261 int ret = 0;
8697a616 1262
565f2491 1263 if(ltt_time_compare(pos1->timestamp, ltt_time_infinite) == 0) {
1264 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
1265 return 0;
1266 else
1267 return 1;
2c82c4dc 1268 }
565f2491 1269 if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0)
2c82c4dc 1270 return -1;
1271
9ba3aaaf 1272 for(i=0;i<pos1->tfcp->len;i++) {
1273 LttvTracefileContextPosition *tfcp1 =
1274 &g_array_index(pos1->tfcp, LttvTracefileContextPosition, i);
27304273 1275
9ba3aaaf 1276 if(tfcp1->used == TRUE) {
1277 for(j=0;j<pos2->tfcp->len;j++) {
1278 LttvTracefileContextPosition *tfcp2 =
1279 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1280
1281 if(tfcp1->tfc == tfcp2->tfc) {
1282 if(tfcp2->used == TRUE)
1283 ret = ltt_event_position_compare(tfcp1->event, tfcp2->event);
1986f254 1284 else
1285 ret = -1;
1286
1287 if(ret != 0) return ret;
1288 }
1289 }
9ba3aaaf 1290
1986f254 1291 } else {
9ba3aaaf 1292 for(j=0;j<pos2->tfcp->len;j++) {
1293 LttvTracefileContextPosition *tfcp2 =
1294 &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j);
1295
1296 if(tfcp1->tfc == tfcp2->tfc)
1297 if(tfcp2->used == TRUE) ret = 1;
1298 if(ret != 0) return ret;
27304273 1299 }
8697a616 1300 }
1301 }
1302 return 0;
1303}
1304
1305
2d262115 1306LttTime lttv_traceset_context_position_get_time(
1307 const LttvTracesetContextPosition *pos)
1308{
1309 return pos->timestamp;
1310}
1311
1312
1313LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext *self)
1314{
1315 GTree *pqueue = self->pqueue;
b56b5fec 1316 LttvTracefileContext *tfc = NULL;
2d262115 1317
1318 g_tree_foreach(pqueue, get_first, &tfc);
1319
1320 return tfc;
1321}
18c87975 1322
2c82c4dc 1323/* lttv_process_traceset_synchronize_tracefiles
1324 *
1325 * Use the sync_position field of the trace set context to synchronize each
1326 * tracefile with the previously saved position.
1327 *
1328 * If no previous position has been saved, it simply does nothing.
1329 */
1330void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc)
1331{
1332 g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0);
1333}
1334
1335
1336
1337
1338void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc)
1339{
1340 lttv_traceset_context_position_save(tsc, tsc->sync_position);
1341}
1342
0bd2f89c 1343struct seek_back_data {
1344 guint first_event; /* Index of the first event in the array : we will always
1345 overwrite at this position : this is a circular array.
1346 */
1347 guint events_found;
33e44b82 1348 guint n; /* number of events requested */
0bd2f89c 1349 GPtrArray *array; /* array of LttvTracesetContextPositions pointers */
33e44b82 1350 LttvFilter *filter;
0bd2f89c 1351};
1352
1353static gint seek_back_event_hook(void *hook_data, void* call_data)
1354{
1355 struct seek_back_data *sd = (struct seek_back_data*)hook_data;
1356 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
1357 LttvTracesetContext *tsc = tfc->t_context->ts_context;
1358 LttvTracesetContextPosition *pos;
33e44b82 1359
bd4c3eca 1360 if(sd->filter != NULL && sd->filter->head != NULL) {
33e44b82 1361 if(!lttv_filter_tree_parse(sd->filter->head,
1362 ltt_tracefile_get_event(tfc->tf),
1363 tfc->tf,
1364 tfc->t_context->t,
1365 tfc))
1366 return FALSE;
0bd2f89c 1367 }
33e44b82 1368
1369 pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array,
1370 sd->first_event);
0bd2f89c 1371
1372 lttv_traceset_context_position_save(tsc, pos);
1373
1374 if(sd->first_event >= sd->array->len - 1) sd->first_event = 0;
1375 else sd->first_event++;
1376
33e44b82 1377 sd->events_found = min(sd->n, sd->events_found + 1);
0bd2f89c 1378
1379 return FALSE;
1380}
1381
0bd2f89c 1382/* Seek back n events back from the current position.
1383 *
1384 * Parameters :
1385 * @self The trace set context
1386 * @n number of events to jump over
9ba3aaaf 1387 * @first_offset The initial offset value used.
33e44b82 1388 * never put first_offset at ltt_time_zero.
1389 * @time_seeker Function pointer of the function to use to seek time :
1390 * either lttv_process_traceset_seek_time
1391 * or lttv_state_traceset_seek_time_closest
1392 * @filter The filter to call.
0bd2f89c 1393 *
1394 * Return value : the number of events found (might be lower than the number
1395 * requested if beginning of traceset is reached).
1396 *
1397 * The first search will go back first_offset and try to find the last n events
1398 * matching the filter. If there are not enough, it will try to go back from the
1399 * new trace point from first_offset*2, and so on, until beginning of trace or n
1400 * events are found.
1401 *
1402 * Note : this function does not take in account the LttvFilter : use the
1403 * similar function found in state.c instead.
1404 *
1405 * Note2 : the caller must make sure that the LttvTracesetContext does not
1406 * contain any hook, as process_traceset_middle is used in this routine.
1407 */
1408guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self,
33e44b82 1409 guint n, LttTime first_offset,
1410 seek_time_fct time_seeker,
1411 LttvFilter *filter)
0bd2f89c 1412{
33e44b82 1413 if(lttv_traceset_number(self->ts) == 0) return 0;
1414 g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0);
1415
0bd2f89c 1416 guint i;
1417 LttvTracesetContextPosition *next_iter_end_pos =
9ba3aaaf 1418 lttv_traceset_context_position_new(self);
1419 LttvTracesetContextPosition *end_pos =
1420 lttv_traceset_context_position_new(self);
1421 LttvTracesetContextPosition *saved_pos =
1422 lttv_traceset_context_position_new(self);
0bd2f89c 1423 LttTime time;
9d227699 1424 LttTime asked_time;
0bd2f89c 1425 LttTime time_offset;
1426 struct seek_back_data sd;
1427 LttvHooks *hooks = lttv_hooks_new();
1428
1429 sd.first_event = 0;
1430 sd.events_found = 0;
1431 sd.array = g_ptr_array_sized_new(n);
33e44b82 1432 sd.filter = filter;
1433 sd.n = n;
0bd2f89c 1434 g_ptr_array_set_size(sd.array, n);
1435 for(i=0;i<n;i++) {
9ba3aaaf 1436 g_ptr_array_index (sd.array, i) = lttv_traceset_context_position_new(self);
0bd2f89c 1437 }
33e44b82 1438
0bd2f89c 1439 lttv_traceset_context_position_save(self, next_iter_end_pos);
33e44b82 1440 lttv_traceset_context_position_save(self, saved_pos);
0bd2f89c 1441 /* Get the current time from which we will offset */
1442 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1443 /* the position saved might be end of traceset... */
1444 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1445 time = self->time_span.end_time;
1446 }
9d227699 1447 asked_time = time;
0bd2f89c 1448 time_offset = first_offset;
1449
1450 lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT);
1451
1452 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1453
1454 while(1) {
1455 /* stop criteria : - n events found
9d227699 1456 * - asked_time < beginning of trace */
1457 if(ltt_time_compare(asked_time, self->time_span.start_time) < 0) break;
0bd2f89c 1458
1459 lttv_traceset_context_position_copy(end_pos, next_iter_end_pos);
1460
1461 /* We must seek the traceset back to time - time_offset */
1462 /* this time becomes the new reference time */
1463 time = ltt_time_sub(time, time_offset);
9d227699 1464 asked_time = time;
0bd2f89c 1465
33e44b82 1466 time_seeker(self, time);
0bd2f89c 1467 lttv_traceset_context_position_save(self, next_iter_end_pos);
33e44b82 1468 /* Resync the time in case of a seek_closest */
1469 time = lttv_traceset_context_position_get_time(next_iter_end_pos);
1470 if(ltt_time_compare(time, self->time_span.end_time) > 0) {
1471 time = self->time_span.end_time;
1472 }
0bd2f89c 1473
1474 /* Process the traceset, calling a hook which adds events
1475 * to the array, overwriting the tail. It changes first_event and
1476 * events_found too. */
1477 /* We would like to have a clean context here : no other hook than our's */
1478
1479 lttv_process_traceset_middle(self, ltt_time_infinite,
1480 G_MAXUINT, end_pos);
1481
33e44b82 1482 if(sd.events_found < n) {
1483 if(sd.first_event > 0) {
1484 /* Save the first position */
1485 LttvTracesetContextPosition *pos =
1486 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0);
1487 lttv_traceset_context_position_copy(saved_pos, pos);
1488 }
1489 g_assert(n-sd.events_found <= sd.array->len);
1490 /* Change array size to n - events_found */
1491 for(i=n-sd.events_found;i<sd.array->len;i++) {
1492 LttvTracesetContextPosition *pos =
1493 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1494 lttv_traceset_context_position_destroy(pos);
1495 }
1496 g_ptr_array_set_size(sd.array, n-sd.events_found);
1497 sd.first_event = 0;
1498
1499 } else break; /* Second end criterion : n events found */
1500
0bd2f89c 1501 time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL);
1502 }
1503
1504 lttv_traceset_context_position_destroy(end_pos);
1505 lttv_traceset_context_position_destroy(next_iter_end_pos);
1506
1507 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1508
33e44b82 1509 if(sd.events_found >= n) {
0bd2f89c 1510 /* Seek the traceset to the first event in the circular array */
1511 LttvTracesetContextPosition *pos =
1512 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array,
1513 sd.first_event);
1514 g_assert(lttv_process_traceset_seek_position(self, pos) == 0);
33e44b82 1515 } else {
1516 /* Will seek to the last saved position : in the worst case, it will be the
1517 * original position (if events_found is 0) */
1518 g_assert(lttv_process_traceset_seek_position(self, saved_pos) == 0);
0bd2f89c 1519 }
1520
33e44b82 1521 for(i=0;i<sd.array->len;i++) {
0bd2f89c 1522 LttvTracesetContextPosition *pos =
1523 (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i);
1524 lttv_traceset_context_position_destroy(pos);
1525 }
1526 g_ptr_array_free(sd.array, TRUE);
1527
1528 lttv_hooks_destroy(hooks);
1529
33e44b82 1530 lttv_traceset_context_position_destroy(saved_pos);
1531
0bd2f89c 1532 return sd.events_found;
1533}
1534
1535
1536struct seek_forward_data {
1537 guint event_count; /* event counter */
1538 guint n; /* requested number of events to jump over */
33e44b82 1539 LttvFilter *filter;
0bd2f89c 1540};
1541
1542static gint seek_forward_event_hook(void *hook_data, void* call_data)
1543{
1544 struct seek_forward_data *sd = (struct seek_forward_data*)hook_data;
33e44b82 1545 LttvTracefileContext *tfc = (LttvTracefileContext*)call_data;
0bd2f89c 1546
33e44b82 1547 if(sd->filter != NULL) {
1548 if(!lttv_filter_tree_parse(sd->filter->head,
1549 ltt_tracefile_get_event(tfc->tf),
1550 tfc->tf,
1551 tfc->t_context->t,
1552 tfc))
1553 return FALSE;
1554 }
1555
0bd2f89c 1556
1557 if(sd->event_count >= sd->n)
1fae3dd3 1558 return 2; /* Stay at the same position */
1559 else {
1560 sd->event_count++;
0bd2f89c 1561 return FALSE;
1fae3dd3 1562 }
0bd2f89c 1563}
1564
1565/* Seek back n events forward from the current position
1566 *
1567 * Parameters :
33e44b82 1568 * @self the trace set context
1569 * @n number of events to jump over
1570 * @filter filter to call.
0bd2f89c 1571 *
1572 * returns : the number of events jumped over (may be less than requested if end
1573 * of traceset reached) */
1574guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self,
33e44b82 1575 guint n, LttvFilter *filter)
0bd2f89c 1576{
1577 struct seek_forward_data sd;
1578 sd.event_count = 0;
1579 sd.n = n;
33e44b82 1580 sd.filter = filter;
0bd2f89c 1581 LttvHooks *hooks = lttv_hooks_new();
1582
1583 lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT);
1584
1585 lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL);
1586
1587 /* it will end on the end of traceset, or the fact that the
5562ddce 1588 * hook returns 2.
0bd2f89c 1589 */
1590 lttv_process_traceset_middle(self, ltt_time_infinite,
1591 G_MAXUINT, NULL);
1592
1593 /* Here, our position is either the end of traceset, or the exact position
1594 * after n events : leave it like this. */
1595
1596 lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL);
1597
1598 lttv_hooks_destroy(hooks);
1599
1600 return sd.event_count;
1601}
1602
1603
This page took 0.115234 seconds and 4 git commands to generate.