X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Flttv%2Flttv%2Ftracecontext.c;h=5d24e11bc75f66e9c88d694b6867ae696bf9ca82;hb=04f2543ebde7de5ec5102e37dbcb4d280c3a87ed;hp=28c279670efe89e53272cabc77bb5a378934500f;hpb=9d239bd92ef3198e80333c703f3ab8ff8cdaeaf7;p=lttv.git diff --git a/ltt/branches/poly/lttv/lttv/tracecontext.c b/ltt/branches/poly/lttv/lttv/tracecontext.c index 28c27967..5d24e11b 100644 --- a/ltt/branches/poly/lttv/lttv/tracecontext.c +++ b/ltt/branches/poly/lttv/lttv/tracecontext.c @@ -21,14 +21,16 @@ #endif #include +#include #include #include #include #include #include +#include #include - +#define min(a,b) (((a)<(b))?(a):(b)) gint compare_tracefile(gconstpointer a, gconstpointer b) @@ -52,11 +54,19 @@ gint compare_tracefile(gconstpointer a, gconstpointer b) return comparison; } +typedef struct _LttvTracefileContextPosition { + LttEventPosition *event; + LttvTracefileContext *tfc; + gboolean used; /* Tells if the tfc is at end of traceset position */ +} LttvTracefileContextPosition; + + struct _LttvTracesetContextPosition { - GArray *ep; /* Array of LttEventPosition */ - GArray *tfc; /* Array of corresponding - TracefileContext* */ - LttTime timestamp; /* Current time at the saved position */ + GArray *tfcp; /* Array of LttvTracefileContextPosition */ + LttTime timestamp; /* Current time at the saved position */ + /* If ltt_time_infinite : no position is + * set, else, a position is set (may be end + * of trace, with ep->len == 0) */ }; void lttv_context_init(LttvTracesetContext *self, LttvTraceset *ts) @@ -125,6 +135,8 @@ static void lttv_traceset_context_compute_time_span( trace = tc->t; ltt_trace_time_span_get(trace, &s, &e); + tc->time_span.start_time = s; + tc->time_span.end_time = e; if(i==0){ time_span->start_time = s; @@ -159,13 +171,14 @@ static void init_tracefile_context(LttTracefile *tracefile, tfc->event = lttv_hooks_new(); tfc->event_by_id = lttv_hooks_by_id_new(); tfc->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL); + tfc->target_pid = -1; } static void init(LttvTracesetContext *self, LttvTraceset *ts) { - guint i, j, nb_trace, nb_control, nb_per_cpu, nb_tracefile; + guint i, nb_trace; LttvTraceContext *tc; @@ -192,13 +205,14 @@ init(LttvTracesetContext *self, LttvTraceset *ts) sizeof(LttvTracefileContext*), 10); tracefiles_groups = ltt_trace_get_tracefiles_groups(tc->t); + if(tracefiles_groups != NULL) { + args.func = (ForEachTraceFileFunc)init_tracefile_context; + args.func_args = tc; - args.func = (ForEachTraceFileFunc)init_tracefile_context; - args.func_args = tc; - - g_datalist_foreach(tracefiles_groups, - (GDataForeachFunc)compute_tracefile_group, - &args); + g_datalist_foreach(tracefiles_groups, + (GDataForeachFunc)compute_tracefile_group, + &args); + } #if 0 nb_control = ltt_trace_control_tracefile_number(tc->t); @@ -229,6 +243,7 @@ init(LttvTracesetContext *self, LttvTraceset *ts) #endif //0 } + self->sync_position = lttv_traceset_context_position_new(self); self->pqueue = g_tree_new(compare_tracefile); lttv_process_traceset_seek_time(self, ltt_time_zero); lttv_traceset_context_compute_time_span(self, &self->time_span); @@ -242,14 +257,13 @@ void fini(LttvTracesetContext *self) LttvTraceContext *tc; - LttvTracefileContext *tfc; + LttvTracefileContext **tfc; LttvTraceset *ts = self->ts; - //FIXME : segfault - g_tree_destroy(self->pqueue); g_object_unref(self->a); + lttv_traceset_context_position_destroy(self->sync_position); nb_trace = lttv_traceset_number(ts); @@ -261,11 +275,11 @@ void fini(LttvTracesetContext *self) nb_tracefile = tc->tracefiles->len; for(j = 0 ; j < nb_tracefile ; j++) { - tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, j); - lttv_hooks_destroy(tfc->event); - lttv_hooks_by_id_destroy(tfc->event_by_id); - g_object_unref(tfc->a); - g_object_unref(tfc); + tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, j); + lttv_hooks_destroy((*tfc)->event); + lttv_hooks_by_id_destroy((*tfc)->event_by_id); + g_object_unref((*tfc)->a); + g_object_unref(*tfc); } g_array_free(tc->tracefiles, TRUE); g_object_unref(tc); @@ -340,15 +354,15 @@ void lttv_trace_context_add_hooks(LttvTraceContext *self, { guint i, nb_tracefile; - LttvTracefileContext *tfc; + LttvTracefileContext **tfc; lttv_hooks_call(before_trace, self); nb_tracefile = self->tracefiles->len; for(i = 0 ; i < nb_tracefile ; i++) { - tfc = g_array_index(self->tracefiles, LttvTracefileContext*, i); - lttv_tracefile_context_add_hooks(tfc, + tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i); + lttv_tracefile_context_add_hooks(*tfc, before_tracefile, event, event_by_id); @@ -365,13 +379,13 @@ void lttv_trace_context_remove_hooks(LttvTraceContext *self, { guint i, nb_tracefile; - LttvTracefileContext *tfc; + LttvTracefileContext **tfc; nb_tracefile = self->tracefiles->len; for(i = 0 ; i < nb_tracefile ; i++) { - tfc = g_array_index(self->tracefiles, LttvTracefileContext*, i); - lttv_tracefile_context_remove_hooks(tfc, + tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i); + lttv_tracefile_context_remove_hooks(*tfc, after_tracefile, event, event_by_id); @@ -614,10 +628,41 @@ lttv_tracefile_context_get_type(void) static gboolean get_first(gpointer key, gpointer value, gpointer user_data) { + g_assert(key == value); *((LttvTracefileContext **)user_data) = (LttvTracefileContext *)value; return TRUE; } +#ifdef DEBUG +// Test to see if pqueue is traversed in the right order. +static LttTime test_time; + +static gboolean test_tree(gpointer key, gpointer value, gpointer user_data) { + + LttvTracefileContext *tfc = (LttvTracefileContext *)key; + + g_debug("Tracefile name %s, time %lu.%lu, tfi %u, ti %u", + g_quark_to_string(ltt_tracefile_name(tfc->tf)), + tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec, + tfc->index, tfc->t_context->index); + + if(user_data != NULL) { + if(((LttvTracefileContext *)user_data) == (LttvTracefileContext *)value) { + g_assert(compare_tracefile(user_data, value) == 0); + } else + g_assert(compare_tracefile(user_data, value) != 0); + } + g_assert(ltt_time_compare(test_time, tfc->timestamp) <= 0); + test_time.tv_sec = tfc->timestamp.tv_sec; + test_time.tv_nsec = tfc->timestamp.tv_nsec; + + + //g_assert(((LttvTracefileContext *)user_data) != (LttvTracefileContext *)value); + return FALSE; +} +#endif //DEBUG + + void lttv_process_traceset_begin(LttvTracesetContext *self, LttvHooks *before_traceset, @@ -638,6 +683,8 @@ void lttv_process_traceset_begin(LttvTracesetContext *self, } +//enum read_state { LAST_NONE, LAST_OK, LAST_EMPTY }; + /* Note : a _middle must be preceded from a _seek or another middle */ guint lttv_process_traceset_middle(LttvTracesetContext *self, LttTime end, @@ -646,7 +693,7 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self, { GTree *pqueue = self->pqueue; - guint id; + guint fac_id, ev_id, id; LttvTracefileContext *tfc; @@ -654,7 +701,11 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self, unsigned count = 0; - gboolean last_ret = FALSE; /* return value of the last hook list called */ + guint read_ret; + + //enum read_state last_read_state = LAST_NONE; + + gint last_ret = 0; /* return value of the last hook list called */ /* Get the next event from the pqueue, call its hooks, reinsert in the pqueue the following event from the same tracefile @@ -679,29 +730,83 @@ guint lttv_process_traceset_middle(LttvTracesetContext *self, */ if(unlikely(last_ret == TRUE || - count >= nb_events || + ((count >= nb_events) && (nb_events != G_MAXULONG)) || (end_position!=NULL&<tv_traceset_context_ctx_pos_compare(self, end_position) == 0)|| ltt_time_compare(end, tfc->timestamp) <= 0)) { return count; } - + /* Get the tracefile with an event for the smallest time found. If two or more tracefiles have events for the same time, hope that lookup and remove are consistent. */ - + +#ifdef DEBUG + test_time.tv_sec = 0; + test_time.tv_nsec = 0; + g_debug("test tree before remove"); + g_tree_foreach(pqueue, test_tree, tfc); +#endif //DEBUG g_tree_remove(pqueue, tfc); + +#ifdef DEBUG + test_time.tv_sec = 0; + test_time.tv_nsec = 0; + g_debug("test tree after remove"); + g_tree_foreach(pqueue, test_tree, tfc); +#endif //DEBUG + + + e = ltt_tracefile_get_event(tfc->tf); + + //if(last_read_state != LAST_EMPTY) { + /* Only call hooks if the last read has given an event or if we are at the + * first pass (not if last read returned end of tracefile) */ count++; - e = ltt_tracefile_get_event(tfc->tf); - id = ltt_event_eventtype_id(e); + fac_id = ltt_event_facility_id(e); + ev_id = ltt_event_eventtype_id(e); + id = GET_HOOK_ID(fac_id, ev_id); + tfc->target_pid = -1; /* unset target PID */ + /* Hooks : + * return values : 0 : continue read, 1 : go to next position and stop read, + * 2 : stay at the current position and stop read */ last_ret = lttv_hooks_call_merge(tfc->event, tfc, lttv_hooks_by_id_get(tfc->event_by_id, id), tfc); - if(likely(!ltt_tracefile_read(tfc->tf))) { +#if 0 + /* This is buggy : it won't work well with state computation */ + if(unlikely(last_ret == 2)) { + /* This is a case where we want to stay at this position and stop read. */ + g_tree_insert(pqueue, tfc, tfc); + return count - 1; + } +#endif //0 + read_ret = ltt_tracefile_read(tfc->tf); + + + if(likely(!read_ret)) { + //g_debug("An event is ready"); tfc->timestamp = ltt_event_time(e); + g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0); g_tree_insert(pqueue, tfc, tfc); +#ifdef DEBUG + test_time.tv_sec = 0; + test_time.tv_nsec = 0; + g_debug("test tree after event ready"); + g_tree_foreach(pqueue, test_tree, NULL); +#endif //DEBUG + + //last_read_state = LAST_OK; + } else { + tfc->timestamp = ltt_time_infinite; + + if(read_ret == ERANGE) { + // last_read_state = LAST_EMPTY; + g_debug("End of trace"); + } else + g_error("Error happened in lttv_process_traceset_middle"); } } } @@ -726,30 +831,47 @@ void lttv_process_traceset_end(LttvTracesetContext *self, /* Subtile modification : * if tracefile has no event at or after the time requested, it is not put in - * the queue, as the next read would fail. */ + * the queue, as the next read would fail. + * + * Don't forget to empty the traceset pqueue before calling this. + */ void lttv_process_trace_seek_time(LttvTraceContext *self, LttTime start) { guint i, nb_tracefile; gint ret; - LttvTracefileContext *tfc; - - GTree *pqueue = self->ts_context->pqueue; + LttvTracefileContext **tfc; nb_tracefile = self->tracefiles->len; + GTree *pqueue = self->ts_context->pqueue; + for(i = 0 ; i < nb_tracefile ; i++) { - tfc = g_array_index(self->tracefiles, LttvTracefileContext*, i); - ret = ltt_tracefile_seek_time(tfc->tf, start); + tfc = &g_array_index(self->tracefiles, LttvTracefileContext*, i); + + g_tree_remove(pqueue, *tfc); + + ret = ltt_tracefile_seek_time((*tfc)->tf, start); if(ret == EPERM) g_error("error in lttv_process_trace_seek_time seek"); - g_tree_remove(pqueue, tfc); if(ret == 0) { /* not ERANGE especially */ - tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf)); - g_tree_insert(pqueue, tfc, tfc); + (*tfc)->timestamp = ltt_event_time(ltt_tracefile_get_event((*tfc)->tf)); + g_assert(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0); + g_tree_insert(pqueue, (*tfc), (*tfc)); + } else { + (*tfc)->timestamp = ltt_time_infinite; } } +#ifdef DEBUG + test_time.tv_sec = 0; + test_time.tv_nsec = 0; + g_debug("test tree after seek_time"); + g_tree_foreach(pqueue, test_tree, NULL); +#endif //DEBUG + + + } @@ -759,6 +881,9 @@ void lttv_process_traceset_seek_time(LttvTracesetContext *self, LttTime start) LttvTraceContext *tc; + //g_tree_destroy(self->pqueue); + //self->pqueue = g_tree_new(compare_tracefile); + nb_trace = lttv_traceset_number(self->ts); for(i = 0 ; i < nb_trace ; i++) { tc = self->traces[i]; @@ -771,21 +896,58 @@ gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self, const LttvTracesetContextPosition *pos) { guint i; - LttvTraceContext *tc; - LttvTracefileContext *tfc; + /* If a position is set, seek the traceset to this position */ + if(ltt_time_compare(pos->timestamp, ltt_time_infinite) != 0) { + + /* Test to see if the traces has been added to the trace set : + * It should NEVER happen. Clear all positions if a new trace comes in. */ + /* FIXME I know this test is not optimal : should keep a number of + * tracefiles variable in the traceset.. eventually */ + guint num_traces = lttv_traceset_number(self->ts); + guint tf_count = 0; + for(i=0; itraces[i]->tracefiles; + guint j; + guint num_tracefiles = tracefiles->len; + for(j=0;jtfcp->len); + - g_tree_destroy(self->pqueue); - self->pqueue = g_tree_new(compare_tracefile); - - for(i=0;iep->len; i++) { - LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i); - LttvTracefileContext *tfc = - g_array_index(pos->tfc, LttvTracefileContext*, i); - g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0); - tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf)); - g_tree_insert(self->pqueue, tfc, tfc); + //g_tree_destroy(self->pqueue); + //self->pqueue = g_tree_new(compare_tracefile); + + for(i=0;itfcp->len; i++) { + LttvTracefileContextPosition *tfcp = + &g_array_index(pos->tfcp, LttvTracefileContextPosition, i); + + g_tree_remove(self->pqueue, tfcp->tfc); + + if(tfcp->used == TRUE) { + if(ltt_tracefile_seek_position(tfcp->tfc->tf, tfcp->event) != 0) + return 1; + tfcp->tfc->timestamp = + ltt_event_time(ltt_tracefile_get_event(tfcp->tfc->tf)); + g_assert(ltt_time_compare(tfcp->tfc->timestamp, + ltt_time_infinite) != 0); + g_tree_insert(self->pqueue, tfcp->tfc, tfcp->tfc); + + } else { + tfcp->tfc->timestamp = ltt_time_infinite; + } + } } - return TRUE; +#ifdef DEBUG + test_time.tv_sec = 0; + test_time.tv_nsec = 0; + g_debug("test tree after seek_position"); + g_tree_foreach(self->pqueue, test_tree, NULL); +#endif //DEBUG + + + + return 0; } @@ -793,27 +955,11 @@ gboolean lttv_process_traceset_seek_position(LttvTracesetContext *self, static LttField * find_field(LttEventType *et, const GQuark field) { - LttType *t; - - LttField *f; - - guint i, nb; - GQuark name; - /* Field is unset */ if(field == 0) return NULL; - f = ltt_eventtype_field(et); - t = ltt_eventtype_type(et); - g_assert(ltt_type_class(t) == LTT_STRUCT); - nb = ltt_type_member_number(t); - for(i = 0 ; i < nb ; i++) { - ltt_type_member_type(t, i, &name); - if(name == field) break; - } - g_assert(i < nb); - return ltt_field_member(f, i); + return ltt_eventtype_field_by_name(et, field); } LttvTraceHookByFacility *lttv_trace_hook_get_fac(LttvTraceHook *th, @@ -836,7 +982,8 @@ LttvTraceHookByFacility *lttv_trace_hook_get_first(LttvTraceHook *th) /* Returns 0 on success, -1 if fails. */ gint lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event, - GQuark field1, GQuark field2, GQuark field3, LttvHook h, LttvTraceHook *th) + GQuark field1, GQuark field2, GQuark field3, LttvHook h, gpointer hook_data, + LttvTraceHook *th) { LttFacility *f; @@ -844,12 +991,12 @@ lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event, GArray *facilities; - guint i, fac_id; + guint i, fac_id, ev_id; LttvTraceHookByFacility *thf, *first_thf; facilities = ltt_trace_facility_get_by_name(t, facility); - + if(unlikely(facilities == NULL)) goto facility_error; th->fac_index = g_array_sized_new(FALSE, TRUE, @@ -869,30 +1016,33 @@ lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event, if(unlikely(et == NULL)) goto event_error; thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id); - g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) - = thf; + g_array_index(th->fac_list, LttvTraceHookByFacility*, 0) = thf; + ev_id = ltt_eventtype_id(et); + thf->h = h; - thf->id = ltt_eventtype_id(et); + thf->id = GET_HOOK_ID(fac_id, ev_id); thf->f1 = find_field(et, field1); thf->f2 = find_field(et, field2); thf->f3 = find_field(et, field3); + thf->hook_data = hook_data; first_thf = thf; + first_et = et; /* Check for type compatibility too */ for(i=1;ilen;i++) { fac_id = g_array_index(facilities, guint, i); f = ltt_trace_get_facility_by_num(t, fac_id); - et = ltt_facility_eventtype_get_by_name(f, ltt_eventtype_name(et)); + et = ltt_facility_eventtype_get_by_name(f, event); if(unlikely(et == NULL)) goto event_error; thf = &g_array_index(th->fac_index, LttvTraceHookByFacility, fac_id); - g_array_index(th->fac_list, LttvTraceHookByFacility*, i) - = thf; + g_array_index(th->fac_list, LttvTraceHookByFacility*, i) = thf; + ev_id = ltt_eventtype_id(et); thf->h = h; - thf->id = ltt_eventtype_id(et); + thf->id = GET_HOOK_ID(fac_id, ev_id); thf->f1 = find_field(et, field1); if(check_fields_compatibility(first_et, et, first_thf->f1, thf->f1)) @@ -907,6 +1057,7 @@ lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event, if(check_fields_compatibility(first_et, et, first_thf->f3, thf->f3)) goto type_error; + thf->hook_data = hook_data; } return 0; @@ -914,12 +1065,13 @@ lttv_trace_find_hook(LttTrace *t, GQuark facility, GQuark event, type_error: goto free; event_error: - g_error("Event type %s does not exist", - g_quark_to_string(ltt_eventtype_name(et))); + g_error("Event type does not exist for event %s", + g_quark_to_string(event)); goto free; facility_error: - g_error("No %s facility", g_quark_to_string(facility)); - goto free; + //Ignore this type of error : some facilities are not required. + //g_error("No %s facility", g_quark_to_string(facility)); + return -1; free: g_array_free(th->fac_index, TRUE); g_array_free(th->fac_list, TRUE); @@ -935,51 +1087,95 @@ void lttv_trace_hook_destroy(LttvTraceHook *th) } -LttvTracesetContextPosition *lttv_traceset_context_position_new() -{ - LttvTracesetContextPosition *pos = g_new(LttvTracesetContextPosition,1); - pos->ep = g_array_sized_new(FALSE, TRUE, sizeof(LttEventPosition*), - 10); - pos->tfc = g_array_sized_new(FALSE, TRUE, sizeof(LttvTracefileContext*), - 10); - pos->timestamp = ltt_time_infinite; - return pos; -} -gboolean traverse_get_tfc(gpointer key, gpointer value, gpointer data) -{ - LttvTracefileContext *tfc = (LttvTracefileContext *)value; - LttvTracesetContextPosition *pos = (LttvTracesetContextPosition *)data; - LttEvent *event = ltt_tracefile_get_event(tfc->tf); - LttEventPosition *ep = ltt_event_position_new(); +LttvTracesetContextPosition *lttv_traceset_context_position_new( + const LttvTracesetContext *self) +{ + guint num_traces = lttv_traceset_number(self->ts); + guint tf_count = 0; + guint i; - ltt_event_position(event, ep); - - g_array_append_val(pos->ep, ep); - g_array_append_val(pos->tfc, tfc); + for(i=0; itraces[i]->tracefiles; + guint j; + guint num_tracefiles = tracefiles->len; + for(j=0;jtfcp = g_array_sized_new(FALSE, TRUE, + sizeof(LttvTracefileContextPosition), + tf_count); + g_array_set_size(pos->tfcp, tf_count); + for(i=0;itfcp->len;i++) { + LttvTracefileContextPosition *tfcp = + &g_array_index(pos->tfcp, LttvTracefileContextPosition, i); + tfcp->event = ltt_event_position_new(); + } - if(ltt_time_compare(tfc->timestamp, pos->timestamp) < 0) - pos->timestamp = tfc->timestamp; - - return 0; + pos->timestamp = ltt_time_infinite; + return pos; } -/* Subtile modification : - * only save the tracefiles that are loaded in the pqueue */ +/* Save all positions, the ones with infinite time will have NULL + * ep. */ +/* note : a position must be destroyed when a trace is added/removed from a + * traceset */ void lttv_traceset_context_position_save(const LttvTracesetContext *self, LttvTracesetContextPosition *pos) { - g_tree_foreach(self->pqueue, traverse_get_tfc, pos); + guint i; + guint num_traces = lttv_traceset_number(self->ts); + guint tf_count = 0; + + pos->timestamp = ltt_time_infinite; + + for(i=0; itraces[i]->tracefiles; + guint j; + guint num_tracefiles = tracefiles->len; + + for(j=0;jtfcp->len); + LttvTracefileContext **tfc = &g_array_index(tracefiles, + LttvTracefileContext*, j); + LttvTracefileContextPosition *tfcp = + &g_array_index(pos->tfcp, LttvTracefileContextPosition, tf_count); + + tfcp->tfc = *tfc; + + if(ltt_time_compare((*tfc)->timestamp, ltt_time_infinite) != 0) { + LttEvent *event = ltt_tracefile_get_event((*tfc)->tf); + ltt_event_position(event, tfcp->event); + if(ltt_time_compare((*tfc)->timestamp, pos->timestamp) < 0) + pos->timestamp = (*tfc)->timestamp; + tfcp->used = TRUE; + } else { + tfcp->used = FALSE; + } + + //g_array_append_val(pos->tfc, *tfc); + //g_array_append_val(pos->ep, ep); + tf_count++; + } + + } } void lttv_traceset_context_position_destroy(LttvTracesetContextPosition *pos) { int i; - for(i=0;iep->len;i++) - g_free(g_array_index(pos->ep, LttEventPosition*, i)); - g_array_free(pos->ep, TRUE); - g_array_free(pos->tfc, TRUE); + + for(i=0;itfcp->len;i++) { + LttvTracefileContextPosition *tfcp = + &g_array_index(pos->tfcp, LttvTracefileContextPosition, i); + g_free(tfcp->event); + tfcp->event = NULL; + tfcp->used = FALSE; + } + g_array_free(pos->tfcp, TRUE); g_free(pos); } @@ -987,19 +1183,24 @@ void lttv_traceset_context_position_copy(LttvTracesetContextPosition *dest, const LttvTracesetContextPosition *src) { int i; + LttvTracefileContextPosition *src_tfcp, *dest_tfcp; - g_array_set_size(dest->ep, src->ep->len); - g_array_set_size(dest->tfc, src->tfc->len); + g_assert(src->tfcp->len == src->tfcp->len); - for(i=0;iep->len;i++) { - g_array_index(dest->ep, LttEventPosition*, i) = ltt_event_position_new(); - ltt_event_position_copy( - g_array_index(dest->ep, LttEventPosition*, i), - g_array_index(src->ep, LttEventPosition*, i)); - } - for(i=0;itfc->len;i++) { - g_array_index(dest->tfc, LttvTracefileContext*, i) = - g_array_index(src->tfc, LttvTracefileContext*, i); + for(i=0;itfcp->len;i++) { + src_tfcp = + &g_array_index(src->tfcp, LttvTracefileContextPosition, i); + dest_tfcp = + &g_array_index(dest->tfcp, LttvTracefileContextPosition, i); + + dest_tfcp->used = src_tfcp->used; + dest_tfcp->tfc = src_tfcp->tfc; + + if(src_tfcp->used) { + ltt_event_position_copy( + dest_tfcp->event, + src_tfcp->event); + } } dest->timestamp = src->timestamp; } @@ -1008,17 +1209,33 @@ gint lttv_traceset_context_ctx_pos_compare(const LttvTracesetContext *self, const LttvTracesetContextPosition *pos) { int i; - int ret; - - for(i=0;iep->len;i++) { - LttEventPosition *ep = g_array_index(pos->ep, LttEventPosition*, i); - LttvTracefileContext *tfc = - g_array_index(pos->tfc, LttvTracefileContext*, i); - - LttEvent *event = ltt_tracefile_get_event(tfc->tf); - - ret = ltt_event_position_compare((LttEventPosition*)event, - ep); + int ret = 0; + + if(pos->tfcp->len == 0) { + if(lttv_traceset_number(self->ts) == 0) return 0; + else return 1; + } + if(lttv_traceset_number(self->ts) == 0) + return -1; + + for(i=0;itfcp->len;i++) { + LttvTracefileContextPosition *tfcp = + &g_array_index(pos->tfcp, LttvTracefileContextPosition, i); + + if(tfcp->used == FALSE) { + if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) < 0) { + ret = -1; + } + } else { + if(ltt_time_compare(tfcp->tfc->timestamp, ltt_time_infinite) == 0) { + ret = 1; + } else { + LttEvent *event = ltt_tracefile_get_event(tfcp->tfc->tf); + + ret = ltt_event_position_compare((LttEventPosition*)event, + tfcp->event); + } + } if(ret != 0) return ret; } @@ -1031,24 +1248,48 @@ gint lttv_traceset_context_pos_pos_compare( const LttvTracesetContextPosition *pos2) { int i, j; - int ret; + int ret = 0; + + if(ltt_time_compare(pos1->timestamp, ltt_time_infinite) == 0) { + if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0) + return 0; + else + return 1; + } + if(ltt_time_compare(pos2->timestamp, ltt_time_infinite) == 0) + return -1; - for(i=0;iep->len;i++) { - LttEventPosition *ep1 = g_array_index(pos1->ep, LttEventPosition*, i); - LttTracefile *tf1 = ltt_event_position_tracefile(ep1); + for(i=0;itfcp->len;i++) { + LttvTracefileContextPosition *tfcp1 = + &g_array_index(pos1->tfcp, LttvTracefileContextPosition, i); - for(j=0;jep->len;j++) { - LttEventPosition *ep2 = g_array_index(pos2->ep, LttEventPosition*, j); - LttTracefile *tf2 = ltt_event_position_tracefile(ep2); + if(tfcp1->used == TRUE) { + for(j=0;jtfcp->len;j++) { + LttvTracefileContextPosition *tfcp2 = + &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j); + + if(tfcp1->tfc == tfcp2->tfc) { + if(tfcp2->used == TRUE) + ret = ltt_event_position_compare(tfcp1->event, tfcp2->event); + else + ret = -1; + + if(ret != 0) return ret; + } + } + + } else { + for(j=0;jtfcp->len;j++) { + LttvTracefileContextPosition *tfcp2 = + &g_array_index(pos2->tfcp, LttvTracefileContextPosition, j); - if(tf1 == tf2) { - ret = ltt_event_position_compare(ep1, ep2); + if(tfcp1->tfc == tfcp2->tfc) + if(tfcp2->used == TRUE) ret = 1; if(ret != 0) return ret; } } } return 0; - } @@ -1068,3 +1309,307 @@ LttvTracefileContext *lttv_traceset_context_get_current_tfc(LttvTracesetContext return tfc; } + +/* lttv_process_traceset_synchronize_tracefiles + * + * Use the sync_position field of the trace set context to synchronize each + * tracefile with the previously saved position. + * + * If no previous position has been saved, it simply does nothing. + */ +void lttv_process_traceset_synchronize_tracefiles(LttvTracesetContext *tsc) +{ + g_assert(lttv_process_traceset_seek_position(tsc, tsc->sync_position) == 0); +} + + + + +void lttv_process_traceset_get_sync_data(LttvTracesetContext *tsc) +{ + lttv_traceset_context_position_save(tsc, tsc->sync_position); +} + +struct seek_back_data { + guint first_event; /* Index of the first event in the array : we will always + overwrite at this position : this is a circular array. + */ + guint events_found; + guint n; /* number of events requested */ + GPtrArray *array; /* array of LttvTracesetContextPositions pointers */ + LttvFilter *filter; + check_handler *check; + gboolean *stop_flag; + guint raw_event_count; +}; + +static gint seek_back_event_hook(void *hook_data, void* call_data) +{ + struct seek_back_data *sd = (struct seek_back_data*)hook_data; + LttvTracefileContext *tfc = (LttvTracefileContext*)call_data; + LttvTracesetContext *tsc = tfc->t_context->ts_context; + LttvTracesetContextPosition *pos; + + if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag)) return TRUE; + sd->raw_event_count++; + + if(sd->filter != NULL && sd->filter->head != NULL) { + if(!lttv_filter_tree_parse(sd->filter->head, + ltt_tracefile_get_event(tfc->tf), + tfc->tf, + tfc->t_context->t, + tfc)) + return FALSE; + } + + pos = (LttvTracesetContextPosition*)g_ptr_array_index (sd->array, + sd->first_event); + + lttv_traceset_context_position_save(tsc, pos); + + if(sd->first_event >= sd->array->len - 1) sd->first_event = 0; + else sd->first_event++; + + sd->events_found = min(sd->n, sd->events_found + 1); + + return FALSE; +} + +/* Seek back n events back from the current position. + * + * Parameters : + * @self The trace set context + * @n number of events to jump over + * @first_offset The initial offset value used. + * never put first_offset at ltt_time_zero. + * @time_seeker Function pointer of the function to use to seek time : + * either lttv_process_traceset_seek_time + * or lttv_state_traceset_seek_time_closest + * @filter The filter to call. + * + * Return value : the number of events found (might be lower than the number + * requested if beginning of traceset is reached). + * + * The first search will go back first_offset and try to find the last n events + * matching the filter. If there are not enough, it will try to go back from the + * new trace point from first_offset*2, and so on, until beginning of trace or n + * events are found. + * + * Note : this function does not take in account the LttvFilter : use the + * similar function found in state.c instead. + * + * Note2 : the caller must make sure that the LttvTracesetContext does not + * contain any hook, as process_traceset_middle is used in this routine. + */ +guint lttv_process_traceset_seek_n_backward(LttvTracesetContext *self, + guint n, LttTime first_offset, + seek_time_fct time_seeker, + LttvFilter *filter, + check_handler *check, + gboolean *stop_flag) +{ + if(lttv_traceset_number(self->ts) == 0) return 0; + g_assert(ltt_time_compare(first_offset, ltt_time_zero) != 0); + + guint i; + LttvTracesetContextPosition *next_iter_end_pos = + lttv_traceset_context_position_new(self); + LttvTracesetContextPosition *end_pos = + lttv_traceset_context_position_new(self); + LttvTracesetContextPosition *saved_pos = + lttv_traceset_context_position_new(self); + LttTime time; + LttTime asked_time; + LttTime time_offset; + struct seek_back_data sd; + LttvHooks *hooks = lttv_hooks_new(); + + sd.first_event = 0; + sd.events_found = 0; + sd.array = g_ptr_array_sized_new(n); + sd.filter = filter; + sd.n = n; + sd.check = check; + sd.stop_flag = stop_flag; + sd.raw_event_count = 0; + g_ptr_array_set_size(sd.array, n); + for(i=0;itime_span.end_time) > 0) { + time = self->time_span.end_time; + } + asked_time = time; + time_offset = first_offset; + + lttv_hooks_add(hooks, seek_back_event_hook, &sd, LTTV_PRIO_DEFAULT); + + lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL); + + while(1) { + /* stop criteria : - n events found + * - asked_time < beginning of trace */ + if(ltt_time_compare(asked_time, self->time_span.start_time) < 0) break; + + lttv_traceset_context_position_copy(end_pos, next_iter_end_pos); + + /* We must seek the traceset back to time - time_offset */ + /* this time becomes the new reference time */ + time = ltt_time_sub(time, time_offset); + asked_time = time; + + time_seeker(self, time); + lttv_traceset_context_position_save(self, next_iter_end_pos); + /* Resync the time in case of a seek_closest */ + time = lttv_traceset_context_position_get_time(next_iter_end_pos); + if(ltt_time_compare(time, self->time_span.end_time) > 0) { + time = self->time_span.end_time; + } + + /* Process the traceset, calling a hook which adds events + * to the array, overwriting the tail. It changes first_event and + * events_found too. */ + /* We would like to have a clean context here : no other hook than our's */ + + lttv_process_traceset_middle(self, ltt_time_infinite, + G_MAXUINT, end_pos); + + if(sd.events_found < n) { + if(sd.first_event > 0) { + /* Save the first position */ + LttvTracesetContextPosition *pos = + (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, 0); + lttv_traceset_context_position_copy(saved_pos, pos); + } + g_assert(n-sd.events_found <= sd.array->len); + /* Change array size to n - events_found */ + for(i=n-sd.events_found;ilen;i++) { + LttvTracesetContextPosition *pos = + (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i); + lttv_traceset_context_position_destroy(pos); + } + g_ptr_array_set_size(sd.array, n-sd.events_found); + sd.first_event = 0; + + } else break; /* Second end criterion : n events found */ + + time_offset = ltt_time_mul(time_offset, BACKWARD_SEEK_MUL); + } + + lttv_traceset_context_position_destroy(end_pos); + lttv_traceset_context_position_destroy(next_iter_end_pos); + + lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL); + + if(sd.events_found >= n) { + /* Seek the traceset to the first event in the circular array */ + LttvTracesetContextPosition *pos = + (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, + sd.first_event); + g_assert(lttv_process_traceset_seek_position(self, pos) == 0); + } else { + /* Will seek to the last saved position : in the worst case, it will be the + * original position (if events_found is 0) */ + g_assert(lttv_process_traceset_seek_position(self, saved_pos) == 0); + } + + for(i=0;ilen;i++) { + LttvTracesetContextPosition *pos = + (LttvTracesetContextPosition*)g_ptr_array_index (sd.array, i); + lttv_traceset_context_position_destroy(pos); + } + g_ptr_array_free(sd.array, TRUE); + + lttv_hooks_destroy(hooks); + + lttv_traceset_context_position_destroy(saved_pos); + + return sd.events_found; +} + + +struct seek_forward_data { + guint event_count; /* event counter */ + guint n; /* requested number of events to jump over */ + LttvFilter *filter; + check_handler *check; + gboolean *stop_flag; + guint raw_event_count; /* event counter */ +}; + +static gint seek_forward_event_hook(void *hook_data, void* call_data) +{ + struct seek_forward_data *sd = (struct seek_forward_data*)hook_data; + LttvTracefileContext *tfc = (LttvTracefileContext*)call_data; + + if(sd->check && sd->check(sd->raw_event_count, sd->stop_flag)) return TRUE; + sd->raw_event_count++; + + if(sd->filter == NULL || lttv_filter_tree_parse(sd->filter->head, + ltt_tracefile_get_event(tfc->tf), + tfc->tf, + tfc->t_context->t, + tfc)) { + sd->event_count++; + if(sd->event_count >= sd->n) + return TRUE; + } + return FALSE; +} + +/* Seek back n events forward from the current position (1 to n) + * 0 is ok too, but it will actually do nothing. + * + * Parameters : + * @self the trace set context + * @n number of events to jump over + * @filter filter to call. + * + * returns : the number of events jumped over (may be less than requested if end + * of traceset reached) */ +guint lttv_process_traceset_seek_n_forward(LttvTracesetContext *self, + guint n, LttvFilter *filter, + check_handler *check, + gboolean *stop_flag) +{ + struct seek_forward_data sd; + sd.event_count = 0; + sd.n = n; + sd.filter = filter; + sd.check = check; + sd.stop_flag = stop_flag; + sd.raw_event_count = 0; + + if(sd.event_count >= sd.n) return sd.event_count; + + LttvHooks *hooks = lttv_hooks_new(); + + lttv_hooks_add(hooks, seek_forward_event_hook, &sd, LTTV_PRIO_DEFAULT); + + lttv_process_traceset_begin(self, NULL, NULL, NULL, hooks, NULL); + + /* it will end on the end of traceset, or the fact that the + * hook returns TRUE. + */ + lttv_process_traceset_middle(self, ltt_time_infinite, + G_MAXUINT, NULL); + + /* Here, our position is either the end of traceset, or the exact position + * after n events : leave it like this. This might be placed on an event that + * will be filtered out, we don't care : all we know is that the following + * event filtered in will be the right one. */ + + lttv_process_traceset_end(self, NULL, NULL, NULL, hooks, NULL); + + lttv_hooks_destroy(hooks); + + return sd.event_count; +} + +