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