#include <lttv/traceset.h>
#include <lttv/iattribute.h>
+#include <lttv/state.h>
+#include <lttv/event.h>
+#include <lttv/hook.h>
#include <stdio.h>
+#include <babeltrace/babeltrace.h>
#include <babeltrace/context.h>
-
+#include <babeltrace/ctf/iterator.h>
+#include <babeltrace/ctf/events.h>
+
+/* To traverse a tree recursively */
+#include <fcntl.h>
+/* For the use of realpath*/
+#include <limits.h>
+#include <stdlib.h>
+/* For strcpy*/
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
/* A trace is a sequence of events gathered in the same tracing session. The
events may be stored in several tracefiles in the same directory.
A trace set is defined when several traces are to be analyzed together,
possibly to study the interactions between events in the different traces.
*/
-struct _LttvTraceset {
- char * filename;
- GPtrArray *traces;
- struct bt_context *context;
- LttvAttribute *a;
-};
+LttvTraceset *lttv_traceset_new(void)
+{
+ LttvTraceset *ts;
+ struct bt_iter_pos begin_pos;
-struct _LttvTrace {
- LttTrace *t;
- LttvAttribute *a;
- guint ref_count;
-};
+ ts = g_new(LttvTraceset, 1);
+ ts->filename = NULL;
+ ts->common_path = NULL;
+ ts->traces = g_ptr_array_new();
+ ts->context = bt_context_create();
+ ts->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
+ /*Initialize iterator to the beginning of the traces*/
+ begin_pos.type = BT_SEEK_BEGIN;
+ ts->iter = bt_ctf_iter_create(ts->context, &begin_pos, NULL);
-LttvTraceset *lttv_traceset_new()
-{
- LttvTraceset *s;
+ ts->event_hooks = lttv_hooks_new();
- s = g_new(LttvTraceset, 1);
- s->filename = NULL;
- s->traces = g_ptr_array_new();
- s->context = bt_context_create();
- s->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
- return s;
+ ts->state_trace_handle_index = g_ptr_array_new();
+ ts->has_precomputed_states = FALSE;
+
+ ts->time_span.start_time = ltt_time_zero;
+ ts->time_span.end_time = ltt_time_zero;
+ lttv_traceset_get_time_span_real(ts);
+ return ts;
}
char * lttv_traceset_name(LttvTraceset * s)
return s->filename;
}
-LttvTrace *lttv_trace_new(LttTrace *t)
+#ifdef BABEL_CLEANUP
+LttvTrace *lttv_trace_new(LttTrace *t)
+{
+ LttvTrace *new_trace;
+
+ new_trace = g_new(LttvTrace, 1);
+ new_trace->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
+ new_trace->id = t;
+ new_trace->ref_count = 0;
+ return new_trace;
+}
+#endif
+/*
+ * get_absolute_pathname : Return the unique pathname in the system
+ *
+ * pathname is the relative path.
+ *
+ * abs_pathname is being set to the absolute path.
+ *
+ */
+void get_absolute_pathname(const gchar *pathname, gchar * abs_pathname)
+{
+ abs_pathname[0] = '\0';
+
+ if (realpath(pathname, abs_pathname) != NULL)
+ return;
+ else
+ {
+ /* error, return the original path unmodified */
+ strcpy(abs_pathname, pathname);
+ return;
+ }
+ return;
+}
+
+
+
+/*
+ * lttv_trace_create : Create a trace from a path
+ *
+ * ts is the traceset in which will be contained the trace
+ *
+ * path is the path where to find a trace. It is not recursive.
+ *
+ * This function is static since a trace should always be contained in a
+ * traceset.
+ *
+ * return the created trace or NULL on failure
+ */
+static LttvTrace *lttv_trace_create(LttvTraceset *ts, const char *path)
{
+ int id = bt_context_add_trace(lttv_traceset_get_context(ts),
+ path,
+ "ctf",
+ NULL,
+ NULL,
+ NULL);
+ if (id < 0) {
+ return NULL;
+ }
+ // Create the trace and save the trace handle id returned by babeltrace
LttvTrace *new_trace;
new_trace = g_new(LttvTrace, 1);
new_trace->a = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
- new_trace->t = t;
+ new_trace->id = id;
new_trace->ref_count = 0;
+ new_trace->short_name[0] = '\0';
+ new_trace->traceset = ts;
+ new_trace->state = g_new(LttvTraceState,1);
+ lttv_trace_state_init(new_trace->state,new_trace);
+
+ /* Add the state to the trace_handle to state index */
+ g_ptr_array_set_size(ts->state_trace_handle_index,id+1);
+ g_ptr_array_index(ts->state_trace_handle_index,id) = new_trace->state;
+
+ /* Find common path */
+ if (ts->common_path == NULL) {
+ ts->common_path = strdup(path);
+ } else {
+ /* TODO ybrosseau 2013-05-24: consider put that in a function */
+ int i,j;
+ for (i = 0;
+ ts->common_path != '\0';
+ i++) {
+ if (path[i] != ts->common_path[i]) {
+ /* The common path has changed, redo the other traces */
+ for(j = 0; j < ts->traces->len; j++) {
+ LttvTrace *t = g_ptr_array_index(ts->traces, j);
+ strncpy(t->short_name, t->full_path+i, TRACE_NAME_SIZE);
+ }
+
+ break;
+ }
+ }
+ strncpy(new_trace->short_name, path+i, TRACE_NAME_SIZE);
+ }
+ new_trace->full_path = strdup(path);
+
return new_trace;
}
+/*
+ * lttv_trace_create : Create and add a single trace to a traceset
+ *
+ * ts is the traceset in which will be contained the trace
+ *
+ * path is the path where to find a trace. It is not recursive.
+ *
+ * return a positive integer (>=0)on success or -1 on failure
+ */
+static int lttv_traceset_create_trace(LttvTraceset *ts, const char *path)
+{
+ LttvTrace *trace = lttv_trace_create(ts, path);
+ if (trace == NULL) {
+ return -1;
+ }
+ lttv_traceset_add(ts, trace);
+ return 0;
+}
LttvTraceset *lttv_traceset_copy(LttvTraceset *s_orig)
{
s = g_new(LttvTraceset, 1);
s->filename = NULL;
+ s->common_path = strdup(s_orig->common_path);
s->traces = g_ptr_array_new();
+ s->state_trace_handle_index = g_ptr_array_new();
for(i=0;i<s_orig->traces->len;i++)
{
trace = g_ptr_array_index(s_orig->traces, i);
trace->ref_count++;
+ /* WARNING: this is an alias, not a copy. */
g_ptr_array_add(s->traces, trace);
+
+ g_ptr_array_set_size(s->state_trace_handle_index,trace->id+1);
+ g_ptr_array_index(s->state_trace_handle_index,trace->id) = trace->state;
+
}
s->context = s_orig->context;
bt_context_get(s->context);
for(i=0;i<s->traces->len;i++) {
LttvTrace *trace = g_ptr_array_index(s->traces, i);
lttv_trace_unref(trace);
+ // todo mdenis 2012-03-27: uncomment when babeltrace gets fixed
+ //bt_context_remove_trace(lttv_traceset_get_context(s), trace->id);
if(lttv_trace_get_ref_number(trace) == 0)
lttv_trace_destroy(trace);
}
+ free(s->common_path);
g_ptr_array_free(s->traces, TRUE);
bt_context_put(s->context);
g_object_unref(s->a);
g_free(s);
}
+struct bt_context *lttv_traceset_get_context(LttvTraceset *s)
+{
+ return s->context;
+}
+
+LttvTraceset *lttv_trace_get_traceset(LttvTrace *trace)
+{
+ return trace->traceset;
+}
+
+LttvHooks *lttv_traceset_get_hooks(LttvTraceset *s)
+{
+ return s->event_hooks;
+}
+
void lttv_trace_destroy(LttvTrace *t)
{
+ free(t->full_path);
g_object_unref(t->a);
g_free(t);
}
-
void lttv_traceset_add(LttvTraceset *s, LttvTrace *t)
{
t->ref_count++;
g_ptr_array_add(s->traces, t);
}
+int lttv_traceset_get_trace_index_from_event(LttvEvent *event)
+{
+ LttvTraceset *ts = event->state->trace->traceset;
+
+ return lttv_traceset_get_trace_index_from_handle_id(ts, bt_ctf_event_get_handle_id(event->bt_event));
+}
+
+int lttv_traceset_get_trace_index_from_handle_id(LttvTraceset *ts, int handle_id)
+{
+ int i;
+
+ /* TODO ybrosseau 2013-05-22: use a map to speedup the lookup */
+
+ for(i = 0; i < ts->traces->len; i++) {
+ LttvTrace *t = g_ptr_array_index(ts->traces, i);
+ if (t && t->id == handle_id) {
+ return i;
+ }
+ }
+
+ /* Handle id not found */
+ return -1;
+
+}
+
+int lttv_traceset_add_path(LttvTraceset *ts, char *trace_path)
+{
+ int ret = -1;
+ DIR *curdir = NULL;
+ gboolean metaFileFound = FALSE;
+
+ /* Open top level directory */
+ curdir = opendir(trace_path);
+ if (curdir == NULL) {
+ g_warning("Cannot open directory %s (%s)", trace_path, strerror(errno));
+ return ret;
+ }
+
+ // Check if a metadata file exists in the current directory
+ int metafd = openat(dirfd(curdir), "metadata", O_RDONLY);
+ if (metafd < 0) {
+
+ } else {
+ ret = close(metafd);
+ if (ret < 0) {
+ g_warning("Unable to close metadata "
+ "file descriptor : %s.", trace_path);
+ goto error;
+ }
+
+ ret = lttv_traceset_create_trace(ts, trace_path);
+ if (ret < 0) {
+ g_warning("Opening trace \"%s\" "
+ "for reading.", trace_path);
+ goto error;
+ }
+ metaFileFound = TRUE;
+ }
+
+ struct dirent curentry;
+ struct dirent *resultentry;
+ while ((ret = readdir_r(curdir, &curentry, &resultentry)) == 0) {
+ if (resultentry == NULL) {
+ /* No more entry*/
+ break;
+ }
+ if (curentry.d_name[0] != '.') {
+ if (curentry.d_type == DT_DIR) {
+
+ char curpath[PATH_MAX];
+ snprintf(curpath, PATH_MAX, "%s/%s", trace_path, curentry.d_name);
+ ret = lttv_traceset_add_path(ts, curpath);
+ if (ret >= 0) {
+ metaFileFound = TRUE;
+ }
+ }
+ }
+ }
+
+ if (ret != 0) {
+ g_warning("Invalid readdir");
+ }
+
+error:
+ if(metaFileFound)
+ return ret;
+ else
+ return -1;
+}
unsigned lttv_traceset_number(LttvTraceset *s)
{
g_assert(s->traces->len > i);
t = (LttvTrace *)s->traces->pdata[i];
t->ref_count--;
+ bt_context_remove_trace(lttv_traceset_get_context(s), t->id);
g_ptr_array_remove_index(s->traces, i);
}
}
-LttTrace *lttv_trace(LttvTrace *t)
+gint lttv_trace_get_id(LttvTrace *t)
{
- return t->t;
+ return t->id;
}
guint lttv_trace_get_ref_number(LttvTrace * t)
{
+ // todo mdenis: adapt to babeltrace
return t->ref_count;
}
return t->ref_count;
}
+guint lttv_trace_get_num_cpu(LttvTrace *t)
+{
+#warning "TODO - Set the right number of CPU"
+ return 24;
+}
+
+LttvTracesetPosition *lttv_traceset_create_current_position(LttvTraceset *traceset)
+{
+ LttvTracesetPosition *traceset_pos;
+
+ traceset_pos = g_new(LttvTracesetPosition, 1);
+
+ /* Check if the new passed */
+ if(traceset_pos == NULL) {
+ return NULL;
+ }
+
+ traceset_pos->iter = traceset->iter;
+ traceset_pos->bt_pos = bt_iter_get_pos(bt_ctf_get_iter(traceset->iter));
+ traceset_pos->timestamp = G_MAXUINT64;
+ traceset_pos->cpu_id = INT_MAX;
+
+ return traceset_pos;
+}
+
+LttvTracesetPosition *lttv_traceset_create_time_position(LttvTraceset *traceset,
+ LttTime timestamp)
+{
+ LttvTracesetPosition *traceset_pos;
+
+ traceset_pos = g_new(LttvTracesetPosition, 1);
+
+ /* Check if the new passed */
+ if(traceset_pos == NULL) {
+ return NULL;
+ }
+
+ traceset_pos->iter = traceset->iter;
+ traceset_pos->bt_pos = bt_iter_create_time_pos(
+ bt_ctf_get_iter(traceset_pos->iter),
+ ltt_time_to_uint64(timestamp));
+ traceset_pos->timestamp = G_MAXUINT64;
+ traceset_pos->cpu_id = INT_MAX;
+ return traceset_pos;
+}
+
+void lttv_traceset_destroy_position(LttvTracesetPosition *traceset_pos)
+{
+ bt_iter_free_pos(traceset_pos->bt_pos);
+ g_free(traceset_pos);
+}
+
+void lttv_traceset_seek_to_position(const LttvTracesetPosition *traceset_pos)
+{
+ bt_iter_set_pos(bt_ctf_get_iter(traceset_pos->iter), traceset_pos->bt_pos);
+}
+
+guint lttv_traceset_get_cpuid_from_event(LttvEvent *event)
+{
+ unsigned long timestamp;
+ unsigned int cpu_id;
+
+ struct bt_ctf_event *ctf_event = event->bt_event;
+ timestamp = bt_ctf_get_timestamp(ctf_event);
+ if (timestamp == -1ULL) {
+ return 0;
+ }
+ const struct bt_definition *scope = bt_ctf_get_top_level_scope(ctf_event, BT_STREAM_PACKET_CONTEXT);
+ if (bt_ctf_field_get_error()) {
+ return 0;
+ }
+ cpu_id = bt_ctf_get_uint64(bt_ctf_get_field(ctf_event, scope, "cpu_id"));
+ if (bt_ctf_field_get_error()) {
+ return 0;
+ } else {
+ return cpu_id;
+ }
+}
+
+guint64 lttv_traceset_get_timestamp_first_event(LttvTraceset *ts)
+{
+ LttvTracesetPosition begin_position;
+ struct bt_iter_pos pos;
+ begin_position.bt_pos = &pos;
+ begin_position.timestamp = G_MAXUINT64;
+ begin_position.cpu_id = INT_MAX;
+
+ /* Assign iterator to the beginning of the traces */
+ begin_position.bt_pos->type = BT_SEEK_BEGIN;
+ begin_position.iter = ts->iter;
+
+ return lttv_traceset_position_get_timestamp(&begin_position);
+}
+
+guint64 lttv_traceset_get_timestamp_last_event(LttvTraceset *ts)
+{
+ LttvTracesetPosition last_position;
+ struct bt_iter_pos pos;
+ last_position.bt_pos = &pos;
+ last_position.timestamp = G_MAXUINT64;
+ last_position.cpu_id = INT_MAX;
+
+ /* Assign iterator to the last event of the traces */
+ last_position.bt_pos->type = BT_SEEK_LAST;
+ last_position.iter = ts->iter;
+
+ return lttv_traceset_position_get_timestamp(&last_position);
+}
+
+/*
+ * lttv_traceset_get_timestamp_begin : returns the minimum timestamp of
+ * all the traces in the traceset.
+ *
+ */
+guint64 lttv_traceset_get_timestamp_begin(LttvTraceset *traceset)
+{
+ struct bt_context *bt_ctx;
+ bt_ctx = lttv_traceset_get_context(traceset);
+ guint64 timestamp_min, timestamp_cur = 0;
+ int i;
+ int trace_count;
+ LttvTrace *currentTrace;
+ trace_count = traceset->traces->len;
+ if(trace_count == 0)
+ timestamp_min = 0;
+ else{
+ timestamp_min = G_MAXUINT64;
+ for(i = 0; i < trace_count;i++)
+ {
+ currentTrace = g_ptr_array_index(traceset->traces,i);
+ timestamp_cur = bt_trace_handle_get_timestamp_begin(bt_ctx,
+ currentTrace->id,
+ BT_CLOCK_REAL);
+ if(timestamp_cur < timestamp_min)
+ timestamp_min = timestamp_cur;
+ }
+ }
+ return timestamp_min;
+}
+
+/*
+ * lttv_traceset_get_timestamp_end: returns the maximum timestamp of
+ * all the traces in the traceset.
+ *
+ */
+guint64 lttv_traceset_get_timestamp_end(LttvTraceset *traceset)
+{
+ struct bt_context *bt_ctx;
+ bt_ctx = lttv_traceset_get_context(traceset);
+ guint64 timestamp_max, timestamp_cur = 0;
+ int i;
+ int trace_count;
+ LttvTrace *currentTrace;
+ trace_count = traceset->traces->len;
+
+ if(trace_count == 0){
+ timestamp_max = 1;
+ }
+ else{
+ timestamp_max = 0;
+ for(i =0; i < trace_count;i++)
+ {
+ currentTrace = g_ptr_array_index(traceset->traces,i);
+ timestamp_cur = bt_trace_handle_get_timestamp_end(bt_ctx,
+ currentTrace->id,
+ BT_CLOCK_REAL);
+ if(timestamp_cur > timestamp_max){
+ timestamp_max = timestamp_cur;
+ }
+ }
+ }
+ return timestamp_max;
+}
+/*
+ * lttv_traceset_get_time_span_real : return a TimeInterval representing the
+ * minimum timestamp and the maximum timestamp of the traceset.
+ *
+ */
+TimeInterval lttv_traceset_get_time_span_real(LttvTraceset *ts)
+{
+
+
+ if(ltt_time_compare(ts->time_span.start_time,
+ ltt_time_zero) == 0 && ts->traces->len > 0){
+ ts->time_span.start_time = ltt_time_from_uint64(
+ lttv_traceset_get_timestamp_first_event(ts));
+ ts->time_span.end_time = ltt_time_from_uint64(
+ lttv_traceset_get_timestamp_last_event(ts));
+ }
+ return ts->time_span;
+}
+
+/*
+ * lttv_traceset_get_time_span : return a TimeInterval representing the
+ * minimum timestamp and the maximum timestamp of the traceset.
+ *
+ */
+TimeInterval lttv_traceset_get_time_span(LttvTraceset *ts)
+{
+ if(ltt_time_compare(ts->time_span.start_time, ltt_time_zero) == 0){
+ ts->time_span.start_time =ltt_time_from_uint64(
+ lttv_traceset_get_timestamp_begin(ts));
+ ts->time_span.end_time = ltt_time_from_uint64(
+ lttv_traceset_get_timestamp_end(ts));
+ }
+ return ts->time_span;
+}
+
+const char *lttv_traceset_get_name_from_event(LttvEvent *event)
+{
+ return bt_ctf_event_name(event->bt_event);
+}
+
+int set_values_position(const LttvTracesetPosition *pos)
+{
+ LttvTracesetPosition previous_pos;
+ previous_pos.iter = pos->iter;
+ previous_pos.bt_pos = bt_iter_get_pos(bt_ctf_get_iter(pos->iter));
+ /* Seek to the new desired position */
+ lttv_traceset_seek_to_position(pos);
+ /*Read the event*/
+ struct bt_ctf_event *event = bt_ctf_iter_read_event(pos->iter);
+
+ if(event != NULL){
+ ((LttvTracesetPosition *)pos)->timestamp = bt_ctf_get_timestamp(event);
+
+ LttvEvent lttv_event;
+ lttv_event.bt_event = event;
+ ((LttvTracesetPosition *)pos)->cpu_id = lttv_traceset_get_cpuid_from_event(<tv_event);
+ }
+ else {
+ /* The event is null */
+ return 0;
+ }
+
+ /* Reassign the previously saved position */
+ lttv_traceset_seek_to_position(&previous_pos);
+ /*We must desallocate because the function bt_iter_get_pos() does a g_new */
+ bt_iter_free_pos(previous_pos.bt_pos);
+ if (pos->timestamp == G_MAXUINT64) {
+ return 0;
+ }
+ return 1;
+}
+
+guint64 lttv_traceset_position_get_timestamp(const LttvTracesetPosition *pos)
+{
+ if(pos->timestamp == G_MAXUINT64){
+ if(set_values_position(pos) == 0){
+ return 0;
+ }
+ }
+
+ return pos->timestamp;
+}
+
+int lttv_traceset_position_get_cpuid(const LttvTracesetPosition *pos){
+ if(pos->cpu_id == INT_MAX ){
+ if(set_values_position(pos) == 0){
+ return 0;
+ }
+ }
+ return pos->cpu_id;
+}
+
+LttTime lttv_traceset_position_get_time(const LttvTracesetPosition *pos)
+{
+ return ltt_time_from_uint64(lttv_traceset_position_get_timestamp(pos));
+}
+
+
+/* 0 if equals, other is different */
+int lttv_traceset_position_compare(const LttvTracesetPosition *pos1, const LttvTracesetPosition *pos2)
+{
+#warning " TODO :Rename for lttv_traceset_position_equals && Must return COMPARAISON OF THE 2 POSITION && verify if it is the best way to compare position"
+ if(pos1 == NULL || pos2 == NULL){
+ return -1;
+ }
+
+ int res = -1;
+#ifdef HAVE_BT_ITER_EQUALS_POS
+ if(pos1->timestamp == G_MAXUINT64 || pos2->timestamp == G_MAXUINT64) {
+ res = bt_iter_equals_pos(pos1->bt_pos, pos2->bt_pos);
+ }
+#endif
+ if (res < 0) {
+
+ guint64 timeStampPos1,timeStampPos2;
+ guint cpuId1, cpuId2;
+
+ timeStampPos1 = lttv_traceset_position_get_timestamp(pos1);
+ timeStampPos2 = lttv_traceset_position_get_timestamp(pos2);
+
+ if (timeStampPos1 == timeStampPos2) {
+
+ cpuId1 = lttv_traceset_position_get_cpuid(pos1);
+ cpuId2 = lttv_traceset_position_get_cpuid(pos2);
+
+ if(cpuId1 == cpuId2){
+ return 0;
+ }
+ }
+ return 1;
+ } else {
+
+ return !res;
+ }
+}
+
+int lttv_traceset_position_time_compare(const LttvTracesetPosition *pos1,
+ const LttvTracesetPosition *pos2)
+{
+ guint64 timeStampPos1,timeStampPos2;
+
+ timeStampPos1 = lttv_traceset_position_get_timestamp(pos1);
+ timeStampPos2 = lttv_traceset_position_get_timestamp(pos2);
+
+ return timeStampPos1 - timeStampPos2;
+}
+int lttv_traceset_position_compare_current(const LttvTraceset *ts,
+ const LttvTracesetPosition *pos)
+{
+ int result = 0;
+ LttvTracesetPosition *curPos = lttv_traceset_create_current_position(ts);
+
+ result = lttv_traceset_position_compare(curPos,pos);
+
+ lttv_traceset_destroy_position(curPos);
+
+ return result;
+}
+
+LttTime lttv_traceset_get_current_time(const LttvTraceset *ts)
+{
+ LttvTracesetPosition *curPos = lttv_traceset_create_current_position(ts);
+ guint64 currentTimestamp = lttv_traceset_position_get_timestamp(curPos);
+ lttv_traceset_destroy_position(curPos);
+
+ return ltt_time_from_uint64(currentTimestamp);
+}