Change behaviour of stream-intersection with multiple traces
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 11 May 2016 17:45:10 +0000 (13:45 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 13 May 2016 16:15:06 +0000 (12:15 -0400)
The stream-intersection currently results in the reading of
the intersection of every stream, in every trace of a Trace
Collection.

Since reading a TraceCollection returns the union of its traces,
the behaviour of this option is changed so that it returns the
union of each trace's individual "active" section, that is the
section for which all streams are active.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
bindings/python/nativebt.i
bindings/python/python-complements.c
bindings/python/python-complements.h
bindings/python/reader.py
formats/ctf-text/ctf-text.c
formats/ctf/ctf.c
formats/ctf/iterator.c
include/babeltrace/babeltrace-internal.h
include/babeltrace/ctf/events-internal.h
include/babeltrace/format-internal.h
lib/iterator.c

index bb67cd58f5223269899eb000ab9f75721d719162..15726ba481008dd38ca32f9b65be7ee0170615cb 100644 (file)
@@ -117,7 +117,7 @@ struct bt_ctf_iter *_bt_python_ctf_iter_create_intersect(
                struct bt_context *ctx,
                struct bt_iter_pos *inter_begin_pos,
                struct bt_iter_pos *inter_end_pos);
-int _bt_python_has_intersection(struct bt_context *ctx);
+int _bt_python_trace_collection_has_intersection(struct bt_context *ctx);
 
 /* context.h, context-internal.h */
 %rename("_bt_context_create") bt_context_create(void);
index 756c54698fbf15f592b34cec3482f1565e5b50d1..0e3bbdf1a3e237859eb4c98998a1148a1f0ed2ee 100644 (file)
@@ -412,12 +412,12 @@ struct bt_ctf_iter *_bt_python_ctf_iter_create_intersect(
                        &inter_end_pos);
 }
 
-int _bt_python_has_intersection(struct bt_context *ctx)
+int _bt_python_trace_collection_has_intersection(struct bt_context *ctx)
 {
        int ret;
-       uint64_t begin = 0, end = ULLONG_MAX;
+       int64_t begin, end;
 
-       ret = ctf_find_packets_intersection(ctx, &begin, &end);
+       ret = ctf_find_tc_stream_packet_intersection_union(ctx, &begin, &end);
 
        return ret == 0 ? 1 : 0;
 }
index e7e1a4113df17b6212c6bc203a2211bbbe57b073..8c8ce87067a77fc18282b056664e1f33fab28611 100644 (file)
@@ -104,4 +104,4 @@ struct bt_ctf_iter *_bt_python_ctf_iter_create_intersect(
                struct bt_context *ctx,
                struct bt_iter_pos *inter_begin_pos,
                struct bt_iter_pos *inter_end_pos);
-int _bt_python_has_intersection(struct bt_context *ctx);
+int _bt_python_trace_collection_has_intersection(struct bt_context *ctx);
index bb3d92811b71f3c4e631deeb37df09536f275ded..7756db195cb336f3736b07cdf9247de6fae0f239 100644 (file)
@@ -139,7 +139,7 @@ class TraceCollection:
 
     @property
     def has_intersection(self):
-        return nbt._bt_python_has_intersection(self._tc)
+        return nbt._bt_python_trace_collection_has_intersection(self._tc)
 
     @property
     def events(self):
index b57eb93dc931d1a0ef3ecb0ad9fb339380db756c..26df6eed2bc49fae320f913412eb08536b2f6a56 100644 (file)
@@ -547,6 +547,10 @@ struct bt_trace_descriptor *ctf_text_open_trace(const char *path, int flags,
        FILE *fp;
 
        pos = g_new0(struct ctf_text_stream_pos, 1);
+       if (!pos) {
+               goto error;
+       }
+       init_trace_descriptor(&pos->trace_descriptor);
 
        pos->last_real_timestamp = -1ULL;
        pos->last_cycles_timestamp = -1ULL;
index c87da63d7e8821bac70a78097304907c67423e7c..c2e387017eb471660de7b1fa78b63e3bb4cb7098 100644 (file)
@@ -27,6 +27,7 @@
  */
 
 #include <babeltrace/format.h>
+#include <babeltrace/format-internal.h>
 #include <babeltrace/ctf/types.h>
 #include <babeltrace/ctf/metadata.h>
 #include <babeltrace/babeltrace-internal.h>
  */
 #define WRITE_PACKET_LEN       (getpagesize() * 8 * CHAR_BIT)
 
-#ifndef min
-#define min(a, b)      (((a) < (b)) ? (a) : (b))
-#endif
-
 #define NSEC_PER_SEC 1000000000LL
 
 #define INDEX_PATH "./index/%s.idx"
@@ -932,13 +929,25 @@ void ctf_update_current_packet_index(struct ctf_stream_definition *stream,
  * empty streams and return a negative value on error.
  */
 static
-int ctf_intersect_trace(struct bt_trace_descriptor *td_read,
-               uint64_t *begin, uint64_t *end)
+int ctf_find_stream_intersection(struct bt_trace_descriptor *td_read,
+               struct packet_index_time *_real,
+               struct packet_index_time *_cycles)
 {
-       struct ctf_trace *tin;
        int stream_id, ret = 0;
+       struct packet_index_time real = { INT64_MIN, INT64_MAX },
+                       cycles = { INT64_MIN, INT64_MAX };
+       struct ctf_trace *tin = container_of(td_read, struct ctf_trace, parent);
 
-       tin = container_of(td_read, struct ctf_trace, parent);
+       /* At least one of the two return args must be provided. */
+       if (!_real && !_cycles) {
+               ret = -1;
+               goto end;
+       }
+
+       if (tin->streams->len == 0) {
+               ret = 1;
+               goto end;
+       }
 
        for (stream_id = 0; stream_id < tin->streams->len;
                        stream_id++) {
@@ -967,56 +976,111 @@ int ctf_intersect_trace(struct bt_trace_descriptor *td_read,
                        }
                        index = &g_array_index(stream_pos->packet_index,
                                        struct packet_index, 0);
-                       if (index->ts_real.timestamp_begin > *begin) {
-                               *begin = index->ts_real.timestamp_begin;
-                       }
+                       real.timestamp_begin = max(real.timestamp_begin,
+                                       index->ts_real.timestamp_begin);
+                       cycles.timestamp_begin = max(cycles.timestamp_begin,
+                                       index->ts_cycles.timestamp_begin);
+
                        index = &g_array_index(stream_pos->packet_index,
                                        struct packet_index,
                                        stream_pos->packet_index->len - 1);
-                       if (index->ts_real.timestamp_end < *end) {
-                               *end = index->ts_real.timestamp_end;
-                       }
+                       real.timestamp_end = min(real.timestamp_end,
+                                       index->ts_real.timestamp_end);
+                       cycles.timestamp_end = min(cycles.timestamp_end,
+                                       index->ts_cycles.timestamp_end);
                }
        }
-
 end:
+       if (ret == 0) {
+               if (_real) {
+                       *_real = real;
+               }
+               if (_cycles) {
+                       *_cycles = cycles;
+               }
+       }
        return ret;
 }
 
 /*
- * Find the timerange where all streams in the trace collection are active
- * simultaneously.
+ * Find the union of all active regions in the trace collection's traces.
+ * Returns "real" timestamps.
  *
  * Return 0 on success.
  * Return 1 if no intersections are found.
  * Return a negative value on error.
  */
-int ctf_find_packets_intersection(struct bt_context *ctx,
-               uint64_t *ts_begin, uint64_t *ts_end)
+int ctf_find_tc_stream_packet_intersection_union(struct bt_context *ctx,
+               int64_t *_ts_begin, int64_t *_ts_end)
 {
-       int ret, i;
+       int ret = 0, i;
+       int64_t ts_begin = INT64_MAX, ts_end = INT64_MIN;
 
-       if (!ctx || !ctx->tc || !ctx->tc->array) {
+       if (!ctx || !ctx->tc || !ctx->tc->array || !_ts_begin || !_ts_end) {
                ret = -EINVAL;
                goto end;
        }
 
        for (i = 0; i < ctx->tc->array->len; i++) {
                struct bt_trace_descriptor *td_read;
+               struct packet_index_time intersection_real;
 
                td_read = g_ptr_array_index(ctx->tc->array, i);
                if (!td_read) {
                        continue;
                }
-               ret = ctf_intersect_trace(td_read, ts_begin, ts_end);
-               if (ret) {
+               ret = ctf_find_stream_intersection(td_read, &intersection_real,
+                               NULL);
+               if (ret == 1) {
+                       /* Empty trace or no stream intersection. */
+                       continue;
+               } else if (ret < 0) {
                        goto end;
                }
+
+               ts_begin = min(intersection_real.timestamp_begin, ts_begin);
+               ts_end = max(intersection_real.timestamp_end, ts_end);
        }
-       if (*ts_end < *ts_begin) {
+
+       if (ts_end < ts_begin) {
                ret = 1;
-       } else {
-               ret = 0;
+               goto end;
+       }
+       *_ts_begin = ts_begin;
+       *_ts_end = ts_end;
+end:
+       return ret;
+}
+
+int ctf_tc_set_stream_intersection_mode(struct bt_context *ctx)
+{
+       int ret = 0, i;
+
+       if (!ctx || !ctx->tc || !ctx->tc->array) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       for (i = 0; i < ctx->tc->array->len; i++) {
+               struct bt_trace_descriptor *td_read;
+               struct packet_index_time intersection_real;
+
+               td_read = g_ptr_array_index(ctx->tc->array, i);
+               if (!td_read) {
+                       continue;
+               }
+
+               ret = ctf_find_stream_intersection(td_read, &intersection_real,
+                               NULL);
+               if (ret == 1) {
+                       /* Empty trace or no stream intersection. */
+                       continue;
+               } else if (ret < 0) {
+                       goto end;
+               }
+
+               td_read->interval_real = intersection_real;
+               td_read->interval_set = true;
        }
 end:
        return ret;
@@ -2397,6 +2461,10 @@ struct bt_trace_descriptor *ctf_open_trace(const char *path, int flags,
                packet_seek = ctf_packet_seek;
 
        td = g_new0(struct ctf_trace, 1);
+       if (!td) {
+               goto error;
+       }
+       init_trace_descriptor(&td->parent);
 
        switch (flags & O_ACCMODE) {
        case O_RDONLY:
index 6f8eb88a9de7b769817de518a1abf56db9e7f115..31bb30c399f110b6b193d09ba5ab718cfe5cfc68 100644 (file)
@@ -67,10 +67,18 @@ struct bt_ctf_iter *bt_ctf_iter_create_intersect(struct bt_context *ctx,
                struct bt_iter_pos **inter_begin_pos,
                struct bt_iter_pos **inter_end_pos)
 {
-       uint64_t begin = 0, end = ULLONG_MAX;
        int ret;
+       int64_t begin, end;
 
-       ret = ctf_find_packets_intersection(ctx, &begin, &end);
+       /*
+        * The iterator's range is the union of each trace's intersection of
+        * streams. This means that we determine the "active" region of each
+        * trace (that is the region where all of its streams are active), and
+        * use the TraceCollection to merge all of these active regions.
+        *
+        * This results in a union of the traces' active regions.
+        */
+       ret = ctf_find_tc_stream_packet_intersection_union(ctx, &begin, &end);
        if (ret == 1) {
                fprintf(stderr, "[error] No intersection found between trace files.\n");
                goto error;
@@ -86,6 +94,11 @@ struct bt_ctf_iter *bt_ctf_iter_create_intersect(struct bt_context *ctx,
                goto error;
        }
 
+       ret = ctf_tc_set_stream_intersection_mode(ctx);
+       if (ret) {
+               goto error;
+       }
+
        /*
         * bt_ctf_iter does not take ownership of begin and end positions,
         * so we return them to the caller who must still assume their ownership
@@ -97,7 +110,6 @@ error:
        return NULL;
 }
 
-
 void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
 {
        struct bt_stream_callbacks *bt_stream_cb;
index 64d562b789c6fb8d77d0203989ee45fb5c076b83..2f15a681a8db5ccdc550e9f8ba37d13474972295 100644 (file)
@@ -151,6 +151,14 @@ extern int babeltrace_verbose, babeltrace_debug;
 # endif
 #endif
 
+#ifndef min
+#define min(a, b)      (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b)      (((a) > (b)) ? (a) : (b))
+#endif
+
 /*
  * BT_HIDDEN: set the hidden attribute for internal functions
  */
index 0968dca1f4f0e12eaa44ee62b42bf61e57a2a31d..37a7bf6fca125f6e7329fd4b7f7746b4a47c1dca 100644 (file)
@@ -311,11 +311,13 @@ int bt_ctf_get_decl_fields(struct bt_ctf_event_decl *event_decl,
  * bt_ctf_get_decl_field_name: return the name of a field decl or NULL on error
  */
 const char *bt_ctf_get_decl_field_name(const struct bt_ctf_field_decl *field);
-int ctf_find_packets_intersection(struct bt_context *ctx,
-               uint64_t *ts_begin, uint64_t *ts_end);
+int ctf_find_tc_stream_packet_intersection_union(struct bt_context *ctx,
+               int64_t *ts_begin, int64_t *ts_end);
 
 void ctf_update_current_packet_index(struct ctf_stream_definition *stream,
                struct packet_index *prev_index,
                struct packet_index *cur_index);
 
+int ctf_tc_set_stream_intersection_mode(struct bt_context *ctx);
+
 #endif /*_BABELTRACE_CTF_EVENTS_INTERNAL_H */
index e0359eacdf95b86caa095b964304c84971430b78..9d5ba3307645edb1d1acd9648e9202b384a4211b 100644 (file)
@@ -32,6 +32,7 @@
 #include <babeltrace/compat/limits.h>
 #include <babeltrace/context-internal.h>
 #include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/ctf/types.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -45,8 +46,20 @@ struct bt_trace_descriptor {
        struct trace_collection *collection;    /* Container of this trace */
        GHashTable *clocks;
        struct ctf_clock *single_clock;         /* currently supports only one clock */
+       bool interval_set;
+       struct packet_index_time interval_real; /* Interval of events to consider */
 };
 
+static inline void init_trace_descriptor(struct bt_trace_descriptor *td) {
+       if (!td) {
+               return;
+       }
+
+       td->interval_real.timestamp_begin = INT64_MIN;
+       td->interval_real.timestamp_end = INT64_MAX;
+       td->interval_set = false;
+}
+
 #ifdef __cplusplus
 }
 #endif
index 4ee0d5d22d454394075e3e3e68c2051d1c9202ba..70f25edd9f0a0948a7820b894fec2bb7143426a3 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <stdlib.h>
 #include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/context.h>
 #include <babeltrace/context-internal.h>
 #include <babeltrace/iterator-internal.h>
@@ -72,6 +73,7 @@ static int stream_read_event(struct ctf_file_stream *sin)
                fprintf(stderr, "[error] Reading event failed.\n");
                return ret;
        }
+
        return 0;
 }
 
@@ -170,6 +172,16 @@ static int seek_ctf_trace_by_timestamp(struct ctf_trace *tin,
 {
        int i, j, ret;
        int found = 0;
+       struct bt_trace_descriptor *td = &tin->parent;
+
+       if (td->interval_set) {
+               /*
+                * If this trace has an interval selected, don't allow seeks
+                * before the selected interval. We seek to the start of the
+                * interval, thereby presenting a shorter "virtual" trace.
+                */
+               timestamp = max(timestamp, td->interval_real.timestamp_begin);
+       }
 
        /* for each stream_class */
        for (i = 0; i < tin->streams->len; i++) {
@@ -748,6 +760,9 @@ int bt_iter_init(struct bt_iter *iter,
        ctx->current_iterator = iter;
        if (begin_pos && begin_pos->type != BT_SEEK_BEGIN) {
                ret = bt_iter_set_pos(iter, begin_pos);
+               if (ret) {
+                       goto error;
+               }
        }
 
        return ret;
@@ -802,6 +817,7 @@ int bt_iter_next(struct bt_iter *iter)
 {
        struct ctf_file_stream *file_stream, *removed;
        int ret;
+       bool event_outside_interval = false;
 
        if (!iter)
                return -EINVAL;
@@ -814,7 +830,12 @@ int bt_iter_next(struct bt_iter *iter)
        }
 
        ret = stream_read_event(file_stream);
-       if (ret == EOF) {
+       if (file_stream->pos.parent.trace->interval_set) {
+               event_outside_interval =
+                               file_stream->parent.real_timestamp >
+                               file_stream->pos.parent.trace->interval_real.timestamp_end;
+       }
+       if (ret == EOF || event_outside_interval) {
                removed = bt_heap_remove(iter->stream_heap);
                assert(removed == file_stream);
                ret = 0;
This page took 0.03248 seconds and 4 git commands to generate.