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