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