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