[lttng-dev] [PATCH babeltrace] Add a format-agnostic iterator creation mechanism
Jérémie Galarneau
jeremie.galarneau at efficios.com
Mon May 27 23:38:47 EDT 2013
Iterators now expose an event providing function so that a user does not
need to know the input trace format to get "bt_ctf_event"s.
A context can now create a specialized iterator depending on its input
trace format.
Signed-off-by: Jérémie Galarneau <jeremie.galarneau at efficios.com>
---
converter/babeltrace.c | 10 +++---
formats/ctf/ctf.c | 3 ++
formats/ctf/iterator.c | 34 +++++++++++++-------
include/babeltrace/context-internal.h | 1 +
include/babeltrace/context.h | 31 ++++++++++++++++++
include/babeltrace/ctf/iterator.h | 6 ++--
include/babeltrace/format.h | 14 +++++++++
include/babeltrace/iterator-internal.h | 1 +
include/babeltrace/iterator.h | 11 +++++++
lib/context.c | 57 ++++++++++++++++++++++++++++++++++
lib/iterator.c | 14 +++++++++
tests/lib/test-seeks.c | 42 ++++++++++++-------------
12 files changed, 183 insertions(+), 41 deletions(-)
diff --git a/converter/babeltrace.c b/converter/babeltrace.c
index 8f09845..c86df93 100644
--- a/converter/babeltrace.c
+++ b/converter/babeltrace.c
@@ -617,19 +617,19 @@ static
int convert_trace(struct bt_trace_descriptor *td_write,
struct bt_context *ctx)
{
- struct bt_ctf_iter *iter;
+ struct bt_iter *iter;
struct bt_iter_pos begin_pos;
struct bt_ctf_event *ctf_event;
int ret;
const GPtrArray *out_streams = bt_trace_descriptor_get_stream_pos(td_write);
begin_pos.type = BT_SEEK_BEGIN;
- iter = bt_ctf_iter_create(ctx, &begin_pos, NULL);
+ iter = bt_context_create_iterator(ctx, &begin_pos, NULL);
if (!iter) {
ret = -1;
goto error_iter;
}
- while ((ctf_event = bt_ctf_iter_read_event(iter))) {
+ while ((ctf_event = bt_iter_get_event(iter))) {
int sout_nr;
for (sout_nr = 0; sout_nr < out_streams->len; ++sout_nr) {
struct bt_stream_pos *sout =
@@ -643,7 +643,7 @@ int convert_trace(struct bt_trace_descriptor *td_write,
goto end;
}
}
- ret = bt_iter_next(bt_ctf_get_iter(iter));
+ ret = bt_iter_next(iter);
if (ret < 0) {
goto end;
}
@@ -651,7 +651,7 @@ int convert_trace(struct bt_trace_descriptor *td_write,
ret = 0;
end:
- bt_ctf_iter_destroy(iter);
+ bt_context_destroy_iterator(ctx, iter);
error_iter:
return ret;
}
diff --git a/formats/ctf/ctf.c b/formats/ctf/ctf.c
index aee80b1..c029791 100644
--- a/formats/ctf/ctf.c
+++ b/formats/ctf/ctf.c
@@ -29,6 +29,7 @@
#include <babeltrace/format.h>
#include <babeltrace/ctf/types.h>
#include <babeltrace/ctf/metadata.h>
+#include <babeltrace/ctf/iterator.h>
#include <babeltrace/babeltrace-internal.h>
#include <babeltrace/ctf/events-internal.h>
#include <babeltrace/trace-handle-internal.h>
@@ -144,6 +145,8 @@ struct bt_format ctf_format = {
.timestamp_begin = ctf_timestamp_begin,
.timestamp_end = ctf_timestamp_end,
.convert_index_timestamp = ctf_convert_index_timestamp,
+ .iterator_create = bt_ctf_iter_create,
+ .iterator_destroy = bt_ctf_iter_destroy
};
static
diff --git a/formats/ctf/iterator.c b/formats/ctf/iterator.c
index d2cd914..a294167 100644
--- a/formats/ctf/iterator.c
+++ b/formats/ctf/iterator.c
@@ -30,6 +30,7 @@
#include <babeltrace/babeltrace.h>
#include <babeltrace/format.h>
#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
#include <babeltrace/ctf-ir/metadata.h>
#include <babeltrace/prio_heap.h>
#include <babeltrace/iterator-internal.h>
@@ -39,7 +40,7 @@
#include "events-private.h"
-struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx,
+struct bt_iter *bt_ctf_iter_create(struct bt_context *ctx,
const struct bt_iter_pos *begin_pos,
const struct bt_iter_pos *end_pos)
{
@@ -60,10 +61,11 @@ struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx,
iter->recalculate_dep_graph = 0;
iter->main_callbacks.callback = NULL;
iter->dep_gc = g_ptr_array_new();
- return iter;
+ iter->parent.get_event = bt_ctf_iter_read_event;
+ return &iter->parent;
}
-void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
+void bt_ctf_iter_destroy(struct bt_iter *iter)
{
struct bt_stream_callbacks *bt_stream_cb;
struct bt_callback_chain *bt_chain;
@@ -71,13 +73,16 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
assert(iter);
+ struct bt_ctf_iter *ctf_iter =
+ container_of(iter, struct bt_ctf_iter, parent);
+
/* free all events callbacks */
- if (iter->main_callbacks.callback)
- g_array_free(iter->main_callbacks.callback, TRUE);
+ if (ctf_iter->main_callbacks.callback)
+ g_array_free(ctf_iter->main_callbacks.callback, TRUE);
/* free per-event callbacks */
- for (i = 0; i < iter->callbacks->len; i++) {
- bt_stream_cb = &g_array_index(iter->callbacks,
+ for (i = 0; i < ctf_iter->callbacks->len; i++) {
+ bt_stream_cb = &g_array_index(ctf_iter->callbacks,
struct bt_stream_callbacks, i);
if (!bt_stream_cb || !bt_stream_cb->per_id_callbacks)
continue;
@@ -90,10 +95,10 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter)
}
g_array_free(bt_stream_cb->per_id_callbacks, TRUE);
}
- g_array_free(iter->callbacks, TRUE);
- g_ptr_array_free(iter->dep_gc, TRUE);
+ g_array_free(ctf_iter->callbacks, TRUE);
+ g_ptr_array_free(ctf_iter->dep_gc, TRUE);
- bt_iter_fini(&iter->parent);
+ bt_iter_fini(iter);
g_free(iter);
}
@@ -158,9 +163,14 @@ stop:
return NULL;
}
-struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter)
+struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_iter *iter)
{
- return bt_ctf_iter_read_event_flags(iter, NULL);
+ struct bt_ctf_iter *ctf_iter;
+ if (!iter) {
+ return NULL;
+ }
+ ctf_iter = container_of(iter, struct bt_ctf_iter, parent);
+ return bt_ctf_iter_read_event_flags(ctf_iter, NULL);
}
uint64_t bt_ctf_get_lost_events_count(struct bt_ctf_iter *iter)
diff --git a/include/babeltrace/context-internal.h b/include/babeltrace/context-internal.h
index 17d6202..7600d8d 100644
--- a/include/babeltrace/context-internal.h
+++ b/include/babeltrace/context-internal.h
@@ -51,6 +51,7 @@ struct bt_context {
int refcount;
int last_trace_handle_id;
struct bt_iter *current_iterator;
+ struct bt_format *input_trace_format;
};
#endif /* _BABELTRACE_CONTEXT_INTERNAL_H */
diff --git a/include/babeltrace/context.h b/include/babeltrace/context.h
index b28df09..6455b65 100644
--- a/include/babeltrace/context.h
+++ b/include/babeltrace/context.h
@@ -32,6 +32,7 @@
*/
#include <unistd.h>
+#include <stdio.h>
#include <babeltrace/format.h>
#ifdef __cplusplus
@@ -96,6 +97,36 @@ int bt_context_add_trace(struct bt_context *ctx, const char *path,
int bt_context_remove_trace(struct bt_context *ctx, int trace_id);
/*
+ * bt_context_create_iterator: Allocate an iterator on the current trace
+ * collection's events.
+ *
+ * begin_pos and end_pos are optional parameters to specify the position
+ * at which the trace collection should be seeked upon iterator
+ * creation, and the position at which iteration will start returning
+ * "EOF".
+ *
+ * By default, if begin_pos is NULL, a BT_SEEK_CUR is performed at
+ * creation. By default, if end_pos is NULL, a BT_SEEK_END (end of
+ * trace) is the EOF criterion.
+ *
+ * Return a pointer to the newly allocated iterator.
+ *
+ * Only one iterator can be created against a context. If more than one
+ * iterator is being created for the same context, the second creation
+ * will return NULL. The previous iterator must be destroyed before
+ * creation of the new iterator for this function to succeed.
+ */
+struct bt_iter *bt_context_create_iterator(struct bt_context *ctx,
+ const struct bt_iter_pos *position_begin,
+ const struct bt_iter_pos *position_end);
+
+/*
+ * bt_context_destroy_iterator: Free a trace collection iterator.
+ */
+void bt_context_destroy_iterator(struct bt_context *ctx,
+ struct bt_iter *iterator);
+
+/*
* bt_context_get and bt_context_put : increments and decrement the
* refcount of the context
*
diff --git a/include/babeltrace/ctf/iterator.h b/include/babeltrace/ctf/iterator.h
index ec6aac7..159e4a4 100644
--- a/include/babeltrace/ctf/iterator.h
+++ b/include/babeltrace/ctf/iterator.h
@@ -59,7 +59,7 @@ struct bt_ctf_event;
* will return NULL. The previous iterator must be destroyed before
* creation of the new iterator for this function to succeed.
*/
-struct bt_ctf_iter *bt_ctf_iter_create(struct bt_context *ctx,
+struct bt_iter *bt_ctf_iter_create(struct bt_context *ctx,
const struct bt_iter_pos *begin_pos,
const struct bt_iter_pos *end_pos);
@@ -71,7 +71,7 @@ struct bt_iter *bt_ctf_get_iter(struct bt_ctf_iter *iter);
/*
* bt_ctf_iter_destroy - Free a CTF trace collection iterator.
*/
-void bt_ctf_iter_destroy(struct bt_ctf_iter *iter);
+void bt_ctf_iter_destroy(struct bt_iter *iter);
/*
* bt_ctf_iter_read_event: Read the iterator's current event data.
@@ -80,7 +80,7 @@ void bt_ctf_iter_destroy(struct bt_ctf_iter *iter);
*
* Return current event on success, NULL on end of trace.
*/
-struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_ctf_iter *iter);
+struct bt_ctf_event *bt_ctf_iter_read_event(struct bt_iter *iter);
/*
* bt_ctf_iter_read_event_flags: Read the iterator's current event data.
diff --git a/include/babeltrace/format.h b/include/babeltrace/format.h
index 9f3d1c8..c170d83 100644
--- a/include/babeltrace/format.h
+++ b/include/babeltrace/format.h
@@ -45,6 +45,9 @@ typedef int bt_intern_str;
struct bt_stream_pos;
struct bt_context;
struct bt_trace_handle;
+struct bt_trace_descriptor;
+struct bt_iter;
+struct bt_iter_pos;
struct bt_mmap_stream {
int fd;
@@ -77,6 +80,17 @@ struct bt_format {
uint64_t (*timestamp_end)(struct bt_trace_descriptor *descriptor,
struct bt_trace_handle *handle, enum bt_clock_type type);
int (*convert_index_timestamp)(struct bt_trace_descriptor *descriptor);
+
+ /*
+ * Only one iterator can be created against a context. If more than one
+ * iterator is being created for the same context, the second creation
+ * will return NULL. The previous iterator must be destroyed before
+ * creation of the new iterator for this function to succeed.
+ */
+ struct bt_iter *(*iterator_create)(struct bt_context *ctx,
+ const struct bt_iter_pos *begin_pos,
+ const struct bt_iter_pos *end_pos);
+ void (*iterator_destroy)(struct bt_iter *iterator);
};
extern struct bt_format *bt_lookup_format(bt_intern_str qname);
diff --git a/include/babeltrace/iterator-internal.h b/include/babeltrace/iterator-internal.h
index 2b0b2f2..2008d76 100644
--- a/include/babeltrace/iterator-internal.h
+++ b/include/babeltrace/iterator-internal.h
@@ -39,6 +39,7 @@ struct bt_iter {
struct ptr_heap *stream_heap;
struct bt_context *ctx;
const struct bt_iter_pos *end_pos;
+ struct bt_ctf_event *(*get_event)(struct bt_iter *iter);
};
/*
diff --git a/include/babeltrace/iterator.h b/include/babeltrace/iterator.h
index 360a9c7..aa189a8 100644
--- a/include/babeltrace/iterator.h
+++ b/include/babeltrace/iterator.h
@@ -27,6 +27,7 @@
#include <babeltrace/format.h>
#include <babeltrace/context.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -40,6 +41,7 @@ enum {
/* Forward declarations */
struct bt_iter;
struct bt_saved_pos;
+struct bt_ctf_event;
/*
* bt_iter is an abstract class, each format has to implement its own
@@ -123,6 +125,15 @@ int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos *pos);
struct bt_iter_pos *bt_iter_create_time_pos(struct bt_iter *iter,
uint64_t timestamp);
+/*
+ * bt_iter_get_event: Get the iterator's current event data
+ *
+ * @iter trace collection iterator (input). Should not be NULL.
+ *
+ * Return current event on success, NULL on end of trace.
+ */
+struct bt_ctf_event *bt_iter_get_event(struct bt_iter *iter);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/context.c b/lib/context.c
index dc77366..61215a3 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -87,6 +87,12 @@ int bt_context_add_trace(struct bt_context *ctx, const char *path,
ret = -1;
goto end;
}
+ if (ctx->input_trace_format && ctx->input_trace_format != fmt) {
+ fprintf(stderr, "[error] [Context] Opening traces of different formats in the same context is not supported.\n");
+ ret = -1;
+ goto end;
+ }
+ ctx->input_trace_format = fmt;
if (path) {
td = fmt->open_trace(path, O_RDONLY, packet_seek, NULL);
if (!td) {
@@ -211,3 +217,54 @@ void bt_context_put(struct bt_context *ctx)
if (ctx->refcount == 0)
bt_context_destroy(ctx);
}
+
+struct bt_iter *bt_context_create_iterator(struct bt_context *ctx,
+ const struct bt_iter_pos *position_begin,
+ const struct bt_iter_pos *position_end)
+{
+ struct bt_iter *iter = NULL;
+ struct bt_format *fmt;
+ assert(ctx);
+
+ if (!ctx->input_trace_format) {
+ fprintf(stderr, "[error] No trace opened in context.\n");
+ goto end;
+ }
+ fmt = ctx->input_trace_format;
+ if (!fmt->iterator_create) {
+ fprintf(stderr, "[error] The %s format plug-in did not register an iterator creation function.\n", g_quark_to_string(fmt->name));
+ goto end;
+ }
+ iter = fmt->iterator_create(ctx, position_begin, position_end);
+
+ if (!ctx->current_iterator) {
+ fprintf(stderr, "[error] The %s format plug-in did not call bt_iter_init in its iterator creation function.\n",
+ g_quark_to_string(fmt->name));
+ }
+
+end:
+ return iter;
+}
+
+void bt_context_destroy_iterator(struct bt_context *ctx,
+ struct bt_iter *iter)
+{
+ struct bt_format *fmt;
+ assert(ctx);
+
+ if (!ctx->input_trace_format) {
+ fprintf(stderr, "[error] No trace opened in context.\n");
+ return;
+ }
+ fmt = ctx->input_trace_format;
+ if (!fmt->iterator_destroy) {
+ fprintf(stderr, "[error] The %s format plug-in did not register an iterator destruction function.\n",
+ g_quark_to_string(fmt->name));
+ return;
+ }
+ fmt->iterator_destroy(iter);
+ if (ctx->current_iterator) {
+ fprintf(stderr, "[warn] The %s format plug-in did not call bt_iter_fini in its iterator destruction function.\n",
+ g_quark_to_string(fmt->name));
+ }
+}
diff --git a/lib/iterator.c b/lib/iterator.c
index 4190e65..b838000 100644
--- a/lib/iterator.c
+++ b/lib/iterator.c
@@ -805,3 +805,17 @@ int bt_iter_next(struct bt_iter *iter)
end:
return ret;
}
+
+struct bt_ctf_event *bt_iter_get_event(struct bt_iter *iter)
+{
+ struct bt_ctf_event *event;
+ if (!iter->get_event) {
+ event = NULL;
+ fprintf(stderr, "[error] No get_event callback registered by the output plug-in.\n");
+ goto end;
+ }
+ event = iter->get_event(iter);
+
+end:
+ return event;
+}
diff --git a/tests/lib/test-seeks.c b/tests/lib/test-seeks.c
index 47bb42e..69e4d4b 100644
--- a/tests/lib/test-seeks.c
+++ b/tests/lib/test-seeks.c
@@ -37,7 +37,7 @@
void run_seek_begin(char *path, uint64_t expected_begin)
{
struct bt_context *ctx;
- struct bt_ctf_iter *iter;
+ struct bt_iter *iter;
struct bt_ctf_event *event;
struct bt_iter_pos newpos;
int ret;
@@ -51,12 +51,12 @@ void run_seek_begin(char *path, uint64_t expected_begin)
}
/* Create iterator with null begin and end */
- iter = bt_ctf_iter_create(ctx, NULL, NULL);
+ iter = bt_context_create_iterator(ctx, NULL, NULL);
if (!iter) {
plan_skip_all("Cannot create valid iterator");
}
- event = bt_ctf_iter_read_event(iter);
+ event = bt_iter_get_event(iter);
ok(event, "Event valid");
@@ -67,7 +67,7 @@ void run_seek_begin(char *path, uint64_t expected_begin)
/* Validate that we get the same value after a seek begin */
newpos.type = BT_SEEK_BEGIN;
- ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+ ret = bt_iter_set_pos(iter, &newpos);
ok(ret == 0, "Seek begin retval %d", ret);
@@ -86,7 +86,7 @@ void run_seek_begin(char *path, uint64_t expected_begin)
void run_seek_last(char *path, uint64_t expected_last)
{
struct bt_context *ctx;
- struct bt_ctf_iter *iter;
+ struct bt_iter *iter;
struct bt_ctf_event *event;
struct bt_iter_pos newpos;
int ret;
@@ -99,18 +99,18 @@ void run_seek_last(char *path, uint64_t expected_last)
}
/* Create iterator with null last and end */
- iter = bt_ctf_iter_create(ctx, NULL, NULL);
+ iter = bt_context_create_iterator(ctx, NULL, NULL);
if (!iter) {
plan_skip_all("Cannot create valid iterator");
}
- event = bt_ctf_iter_read_event(iter);
+ event = bt_iter_get_event(iter);
ok(event, "Event valid at beginning");
/* Seek to last */
newpos.type = BT_SEEK_LAST;
- ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+ ret = bt_iter_set_pos(iter, &newpos);
ok(ret == 0, "Seek last retval %d", ret);
@@ -123,11 +123,11 @@ void run_seek_last(char *path, uint64_t expected_last)
ok1(timestamp_last == expected_last);
/* Try to read next event */
- ret = bt_iter_next(bt_ctf_get_iter(iter));
+ ret = bt_iter_next(iter);
ok(ret == 0, "iter next should return an error");
- event = bt_ctf_iter_read_event(iter);
+ event = bt_iter_get_event(iter);
ok(event == 0, "Event after last should be invalid");
@@ -139,7 +139,7 @@ void run_seek_cycles(char *path,
uint64_t expected_last)
{
struct bt_context *ctx;
- struct bt_ctf_iter *iter;
+ struct bt_iter *iter;
struct bt_ctf_event *event;
struct bt_iter_pos newpos;
int ret;
@@ -152,22 +152,22 @@ void run_seek_cycles(char *path,
}
/* Create iterator with null last and end */
- iter = bt_ctf_iter_create(ctx, NULL, NULL);
+ iter = bt_context_create_iterator(ctx, NULL, NULL);
if (!iter) {
plan_skip_all("Cannot create valid iterator");
}
- event = bt_ctf_iter_read_event(iter);
+ event = bt_iter_get_event(iter);
ok(event, "Event valid at beginning");
/* Seek to last */
newpos.type = BT_SEEK_LAST;
- ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+ ret = bt_iter_set_pos(iter, &newpos);
ok(ret == 0, "Seek last retval %d", ret);
- event = bt_ctf_iter_read_event(iter);
+ event = bt_iter_get_event(iter);
ok(event, "Event valid at last position");
@@ -176,21 +176,21 @@ void run_seek_cycles(char *path,
ok1(timestamp == expected_last);
/* Try to read next event */
- ret = bt_iter_next(bt_ctf_get_iter(iter));
+ ret = bt_iter_next(iter);
ok(ret == 0, "iter next should return an error");
- event = bt_ctf_iter_read_event(iter);
+ event = bt_iter_get_event(iter);
ok(event == 0, "Event after last should be invalid");
/* Seek to BEGIN */
newpos.type = BT_SEEK_BEGIN;
- ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+ ret = bt_iter_set_pos(iter, &newpos);
ok(ret == 0, "Seek begin retval %d", ret);
- event = bt_ctf_iter_read_event(iter);
+ event = bt_iter_get_event(iter);
ok(event, "Event valid at first position");
@@ -200,11 +200,11 @@ void run_seek_cycles(char *path,
/* Seek last again */
newpos.type = BT_SEEK_LAST;
- ret = bt_iter_set_pos(bt_ctf_get_iter(iter), &newpos);
+ ret = bt_iter_set_pos(iter, &newpos);
ok(ret == 0, "Seek last retval %d", ret);
- event = bt_ctf_iter_read_event(iter);
+ event = bt_iter_get_event(iter);
ok(event, "Event valid at last position");
--
1.8.2.3
More information about the lttng-dev
mailing list