From 40af9f9fb5d827c8c58e32efd6fca204da1194c8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 11 May 2016 13:45:10 -0400 Subject: [PATCH] Change behaviour of stream-intersection with multiple traces MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- bindings/python/nativebt.i | 2 +- bindings/python/python-complements.c | 6 +- bindings/python/python-complements.h | 2 +- bindings/python/reader.py | 2 +- formats/ctf-text/ctf-text.c | 4 + formats/ctf/ctf.c | 120 ++++++++++++++++++----- formats/ctf/iterator.c | 18 +++- include/babeltrace/babeltrace-internal.h | 8 ++ include/babeltrace/ctf/events-internal.h | 6 +- include/babeltrace/format-internal.h | 13 +++ lib/iterator.c | 23 ++++- 11 files changed, 166 insertions(+), 38 deletions(-) diff --git a/bindings/python/nativebt.i b/bindings/python/nativebt.i index bb67cd58..15726ba4 100644 --- a/bindings/python/nativebt.i +++ b/bindings/python/nativebt.i @@ -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); diff --git a/bindings/python/python-complements.c b/bindings/python/python-complements.c index 756c5469..0e3bbdf1 100644 --- a/bindings/python/python-complements.c +++ b/bindings/python/python-complements.c @@ -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; } diff --git a/bindings/python/python-complements.h b/bindings/python/python-complements.h index e7e1a411..8c8ce870 100644 --- a/bindings/python/python-complements.h +++ b/bindings/python/python-complements.h @@ -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); diff --git a/bindings/python/reader.py b/bindings/python/reader.py index bb3d9281..7756db19 100644 --- a/bindings/python/reader.py +++ b/bindings/python/reader.py @@ -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): diff --git a/formats/ctf-text/ctf-text.c b/formats/ctf-text/ctf-text.c index b57eb93d..26df6eed 100644 --- a/formats/ctf-text/ctf-text.c +++ b/formats/ctf-text/ctf-text.c @@ -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; diff --git a/formats/ctf/ctf.c b/formats/ctf/ctf.c index c87da63d..c2e38701 100644 --- a/formats/ctf/ctf.c +++ b/formats/ctf/ctf.c @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -68,10 +69,6 @@ */ #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: diff --git a/formats/ctf/iterator.c b/formats/ctf/iterator.c index 6f8eb88a..31bb30c3 100644 --- a/formats/ctf/iterator.c +++ b/formats/ctf/iterator.c @@ -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; diff --git a/include/babeltrace/babeltrace-internal.h b/include/babeltrace/babeltrace-internal.h index 64d562b7..2f15a681 100644 --- a/include/babeltrace/babeltrace-internal.h +++ b/include/babeltrace/babeltrace-internal.h @@ -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 */ diff --git a/include/babeltrace/ctf/events-internal.h b/include/babeltrace/ctf/events-internal.h index 0968dca1..37a7bf6f 100644 --- a/include/babeltrace/ctf/events-internal.h +++ b/include/babeltrace/ctf/events-internal.h @@ -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 */ diff --git a/include/babeltrace/format-internal.h b/include/babeltrace/format-internal.h index e0359eac..9d5ba330 100644 --- a/include/babeltrace/format-internal.h +++ b/include/babeltrace/format-internal.h @@ -32,6 +32,7 @@ #include #include #include +#include #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 diff --git a/lib/iterator.c b/lib/iterator.c index 4ee0d5d2..70f25edd 100644 --- a/lib/iterator.c +++ b/lib/iterator.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -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; -- 2.34.1