All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philippe Proulx <pproulx@efficios.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	Jeremie Galarneau <jgalar@efficios.com>,
	lttng-dev <lttng-dev@lists.lttng.org>,
	linux-trace-devel@vger.kernel.org
Subject: Re: [lttng-dev] Usage example of libbabeltrace (babeltrace2) to read CTF traces from a GUI
Date: Fri, 18 Jun 2021 23:42:01 -0400 (EDT)	[thread overview]
Message-ID: <1743432091.13845.1624074121104.JavaMail.zimbra@efficios.com> (raw)
In-Reply-To: <20210615115738.46818ace@oasis.local.home>

----- Original Message -----
> From: "Steven Rostedt" <rostedt@goodmis.org>
> To: "Philippe Proulx" <pproulx@efficios.com>
> Cc: "Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>, "Jeremie Galarneau" <jgalar@efficios.com>, "lttng-dev"
> <lttng-dev@lists.lttng.org>, linux-trace-devel@vger.kernel.org
> Sent: Tuesday, 15 June, 2021 11:57:38
> Subject: Re: [lttng-dev] Usage example of libbabeltrace (babeltrace2) to read CTF traces from a GUI

> [ Adding linux-trace-devel too ]
> 
> On Tue, 15 Jun 2021 11:13:41 -0400
> Philippe Proulx <pproulx@efficios.com> wrote:
> 
>> I can cook a minimal working example in the following days.
> 
> That would be great, thanks!

Here you go (Pastebin: <https://pastebin.com/0MFQkiAw>):

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <babeltrace2/babeltrace.h>

/*
 * Shared data between our relay sink component and the
 * bt_graph_run_once() call site.
 */
struct relay_data {
	bt_message_array_const msgs;
	uint64_t msg_count;
};

/*
 * Consumer method of our relay sink component class.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html#ga301a677396bd8f5bd8b920fd5fa60418>.
 */
static bt_graph_simple_sink_component_consume_func_status relay_consume(
		bt_message_iterator * const msg_iter,
		void * const user_data)
{
	struct relay_data * const relay_data =
		(struct relay_data *) user_data;
	bt_message_iterator_next_status msg_iter_next_status;
	bt_graph_simple_sink_component_consume_func_status status =
		BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_OK;

	/* Consume the next messages, storing them in `*relay_data` */
	msg_iter_next_status = bt_message_iterator_next(msg_iter,
		&relay_data->msgs, &relay_data->msg_count);
	switch (msg_iter_next_status) {
	case BT_MESSAGE_ITERATOR_NEXT_STATUS_END:
		status = BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_END;
		break;
	case BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_MEMORY_ERROR:
		status = BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_MEMORY_ERROR;
		break;
	case BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_ERROR:
		status = BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_ERROR;
		break;
	default:
		assert(status ==
			BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_OK);
		break;
	}

	return status;
}

/*
 * Adds our own sink component named `relay` to the trace processing
 * graph `graph`.
 *
 * On success, `*comp` is the added sink component.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html#api-graph-lc-add-ss>.
 */
static bt_graph_add_component_status add_relay_comp(bt_graph * const graph,
		struct relay_data * const relay_data,
		const bt_component_sink ** const comp)
{
	return bt_graph_add_simple_sink_component(graph, "relay", NULL,
		relay_consume, NULL, relay_data, comp);
}

/*
 * Creates and returns the parameters to initialize the `src.ctf.fs`
 * component with the trace directory `trace_dir`.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-val.html>.
 */
static bt_value *create_ctf_fs_comp_params(const char * const trace_dir)
{
	bt_value *params;
	bt_value *inputs = NULL;
	bt_value_map_insert_entry_status insert_entry_status;
	bt_value_array_append_element_status append_elem_status;

	/* Create an empty map value */
	params = bt_value_map_create();
	if (!params) {
		goto error;
	}

	/*
	 * Insert an empty array value having the key `inputs`.
	 *
	 * `inputs` is a borrowed value object here, _not_ our
	 * reference.
	 */
	insert_entry_status = bt_value_map_insert_empty_array_entry(params,
		"inputs", &inputs);
	if (insert_entry_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
		goto error;
	}

	/* Append the trace directory to the `inputs` array value */
	append_elem_status = bt_value_array_append_string_element(inputs,
		trace_dir);
	if (append_elem_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
		goto error;
	}

	goto end;

error:
	BT_VALUE_PUT_REF_AND_RESET(params);

end:
	return params;
}

/*
 * Adds a `src.ctf.fs` component named `ctf` to read the trace directory
 * `trace_dir` to the trace processing graph `graph`.
 *
 * See <https://babeltrace.org/docs/v2.0/man7/babeltrace2-source.ctf.fs.7/>.
 *
 * On success, `*comp` is the added source component.
 */
static bt_graph_add_component_status add_ctf_fs_comp(bt_graph * const graph,
		const char * const trace_dir,
		const bt_component_source ** const comp)
{
	const bt_plugin *plugin;
	bt_plugin_find_status plugin_find_status;
	const bt_component_class_source *comp_cls;
	bt_value *params = NULL;
	bt_graph_add_component_status add_comp_status;

	/* Find the `ctf` plugin */
	plugin_find_status = bt_plugin_find("ctf", BT_TRUE, BT_TRUE,
		BT_TRUE, BT_TRUE, BT_TRUE, &plugin);
	if (plugin_find_status != BT_PLUGIN_FIND_STATUS_OK) {
		goto error;
	}

	/* Borrow the `fs` source component class within the `ctf` plugin */
	comp_cls = bt_plugin_borrow_source_component_class_by_name_const(
		plugin, "fs");
	if (!comp_cls) {
		goto error;
	}

	/* Create the parameters to initialize the source component */
	params = create_ctf_fs_comp_params(trace_dir);
	if (!params) {
		goto error;
	}

	/* Add the source component to the graph */
	add_comp_status = bt_graph_add_source_component(graph, comp_cls,
		"ctf", params, BT_LOGGING_LEVEL_NONE, comp);
	goto end;

error:
	add_comp_status = BT_GRAPH_ADD_COMPONENT_STATUS_ERROR;

end:
	bt_plugin_put_ref(plugin);
	bt_value_put_ref(params);
	return add_comp_status;
}

/*
 * Adds a `flt.utils.muxer` component named `muxer` to the trace
 * processing graph `graph`.
 *
 * See <https://babeltrace.org/docs/v2.0/man7/babeltrace2-filter.utils.muxer.7/>.
 *
 * On success, `*comp` is the added filter component.
 */
static bt_graph_add_component_status add_muxer_comp(bt_graph * const graph,
		const bt_component_filter ** const comp)
{
	const bt_plugin *plugin;
	bt_plugin_find_status plugin_find_status;
	const bt_component_class_filter *comp_cls;
	bt_graph_add_component_status add_comp_status;

	/* Find the `utils` plugin */
	plugin_find_status = bt_plugin_find("utils", BT_TRUE, BT_TRUE,
		BT_TRUE, BT_TRUE, BT_TRUE, &plugin);
	if (plugin_find_status != BT_PLUGIN_FIND_STATUS_OK) {
		goto error;
	}

	/* Borrow the `muxer` filter comp. class within the `utils` plugin */
	comp_cls = bt_plugin_borrow_filter_component_class_by_name_const(
		plugin, "muxer");
	if (!comp_cls) {
		goto error;
	}

	/* Add the filter component to the graph (no init. parameters) */
	add_comp_status = bt_graph_add_filter_component(graph, comp_cls,
		"muxer", NULL, BT_LOGGING_LEVEL_NONE, comp);
	goto end;

error:
	add_comp_status = BT_GRAPH_ADD_COMPONENT_STATUS_ERROR;

end:
	bt_plugin_put_ref(plugin);
	return add_comp_status;
}

/*
 * Creates a trace processing graph having this layout:
 *
 *     +------------+    +-----------------+    +--------------+
 *     | src.ctf.fs |    | flt.utils.muxer |    | Our own sink |
 *     |    [ctf]   |    |     [muxer]     |    |    [relay]   |
 *     |            |    |                 |    |              |
 *     |    stream0 @--->@ in0         out @--->@ in           |
 *     |    stream1 @--->@ in1             |    +--------------+
 *     |    stream2 @--->@ in2             |
 *     |    stream3 @--->@ in3             |
 *     +------------+    @ in4             |
 *                       +-----------------+
 *
 * In the example above, the `src.ctf.fs` component reads a CTF trace
 * having four data streams. The `trace_dir` parameter is the directory
 * containing the CTF trace to read.
 *
 * Our own relay sink component, of which the consuming method is
 * relay_consume(), consumes messages from the `flt.utils.muxer`
 * component, storing them to a structure (`*relay_data`) shared with
 * the bt_graph_run_once() call site.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html>.
 */
static bt_graph *create_graph(const char * const trace_dir,
		struct relay_data * const relay_data)
{
	bt_graph *graph;
	const bt_component_source *ctf_fs_comp;
	const bt_component_filter *muxer_comp;
	const bt_component_sink *relay_comp;
	bt_graph_add_component_status add_comp_status;
	bt_graph_connect_ports_status connect_ports_status;
	uint64_t i;

	/* Create an empty trace processing graph */
	graph = bt_graph_create(0);
	if (!graph) {
		goto error;
	}

	/* Create and add the three required components to `graph` */
	add_comp_status = add_ctf_fs_comp(graph, trace_dir, &ctf_fs_comp);
	if (add_comp_status != BT_GRAPH_ADD_COMPONENT_STATUS_OK) {
		goto error;
	}

	add_comp_status = add_muxer_comp(graph, &muxer_comp);
	if (add_comp_status != BT_GRAPH_ADD_COMPONENT_STATUS_OK) {
		goto error;
	}

	add_comp_status = add_relay_comp(graph, relay_data, &relay_comp);
	if (add_comp_status != BT_GRAPH_ADD_COMPONENT_STATUS_OK) {
		goto error;
	}

	/*
	 * Connect all the output ports of the `ctf` source component to
	 * the input ports of the `muxer` filter component.
	 *
	 * An `flt.utils.muxer` component adds an input port every time
	 * you connect one, making one always available.
	 *
	 * See <https://babeltrace.org/docs/v2.0/man7/babeltrace2-filter.utils.muxer.7/#doc-_input>.
	 */
	for (i = 0; i < bt_component_source_get_output_port_count(ctf_fs_comp);
			i++) {
		const bt_port_output * const out_port =
			bt_component_source_borrow_output_port_by_index_const(
				ctf_fs_comp, i);
		const bt_port_input * const in_port =
			bt_component_filter_borrow_input_port_by_index_const(
				muxer_comp, i);

		/* Connect ports */
		connect_ports_status = bt_graph_connect_ports(graph,
			out_port, in_port, NULL);

		if (connect_ports_status != BT_GRAPH_CONNECT_PORTS_STATUS_OK) {
			goto error;
		}
	}

	/* Connect the `muxer` output port to the `relay` input port */
	connect_ports_status = bt_graph_connect_ports(graph,
		bt_component_filter_borrow_output_port_by_index_const(
			muxer_comp, 0),
		bt_component_sink_borrow_input_port_by_index_const(
			relay_comp, 0), NULL);
	if (connect_ports_status != BT_GRAPH_CONNECT_PORTS_STATUS_OK) {
		goto error;
	}

	goto end;

error:
	BT_GRAPH_PUT_REF_AND_RESET(graph);

end:
	return graph;
}

/*
 * Handles a single message `msg`, printing its name if it's an event
 * message.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-msg.html>.
 */
static void handle_msg(const bt_message * const msg)
{
	const bt_event *event;

	if (bt_message_get_type(msg) != BT_MESSAGE_TYPE_EVENT) {
		goto end;
	}

	event = bt_message_event_borrow_event_const(msg);
	puts(bt_event_class_get_name(bt_event_borrow_class_const(event)));

end:
	return;
}

/*
 * Runs the trace processing graph `graph`, our relay sink component
 * transferring its consumed messages to `*relay_data`.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html#api-graph-lc-run>.
 */
static int run_graph(bt_graph * const graph,
		struct relay_data * const relay_data)
{
	bt_graph_run_once_status status;

	while (true) {
		uint64_t i;

		/*
		 * bt_graph_run_once() calls the consuming method of
		 * our relay sink component (relay_consume()).
		 *
		 * relay_consume() consumes a batch of messages from the
		 * `flt.utils.muxer` component and stores them in
		 * `*relay_data`.
		 */
		status = bt_graph_run_once(graph);
		assert(status != BT_GRAPH_RUN_ONCE_STATUS_AGAIN);
		if (status != BT_GRAPH_RUN_ONCE_STATUS_OK) {
			break;
		}

		/* Handle each consumed message */
		for (i = 0; i < relay_data->msg_count; i++) {
			const bt_message * const msg = relay_data->msgs[i];

			handle_msg(msg);

			/*
			 * The message reference `msg` is ours: release
			 * it now.
			 */
			bt_message_put_ref(msg);
		}
	}

	return status == BT_GRAPH_RUN_ONCE_STATUS_END ? 0 : -1;
}

/*
 * Reads the CTF trace located in the directory `argv[1]`, printing one
 * event name per line to the standard output.
 */
int main(const int argc, const char * const * const argv)
{
	int ret = EXIT_SUCCESS;
	struct relay_data relay_data = { 0 };
	bt_graph *graph;

	assert(argc == 2);

	/* Create the trace processing graph */
	graph = create_graph(argv[1], &relay_data);
	if (!graph) {
		ret = EXIT_FAILURE;
		goto end;
	}

	/* Run the graph, printing one event name per line */
	if (run_graph(graph, &relay_data)) {
		ret = EXIT_FAILURE;
	}

end:
	bt_graph_put_ref(graph);
	return ret;
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Build as such:

    $ cc -Wextra -Wall -o read-ctf-example read-ctf-example.c \
         $(pkg-config babeltrace2 --cflags --libs)

Feel free to ask us any questions.

Philippe Proulx
EfficiOS Inc.
https://www.efficios.com/

> 
> -- Steve
> 
>> 
>> Phil
>> 
>> [1]: https://babeltrace.org/docs/v2.0/libbabeltrace2/
>> [2]:
>> https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html#gaa8432f03a967d01b764fb1bc959c8e89
>> 
>> >
>> > Thanks,
>> >
>> > Mathieu
>> >
>> > --
>> > Mathieu Desnoyers
>> > EfficiOS Inc.
>> > http://www.efficios.com
>> > _______________________________________________
>> > lttng-dev mailing list
>> > lttng-dev@lists.lttng.org
> > > https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev

WARNING: multiple messages have this Message-ID (diff)
From: Philippe Proulx via lttng-dev <lttng-dev@lists.lttng.org>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: lttng-dev <lttng-dev@lists.lttng.org>,
	Jeremie Galarneau <jgalar@efficios.com>,
	linux-trace-devel@vger.kernel.org
Subject: Re: [lttng-dev] Usage example of libbabeltrace (babeltrace2) to read CTF traces from a GUI
Date: Fri, 18 Jun 2021 23:42:01 -0400 (EDT)	[thread overview]
Message-ID: <1743432091.13845.1624074121104.JavaMail.zimbra@efficios.com> (raw)
In-Reply-To: <20210615115738.46818ace@oasis.local.home>

----- Original Message -----
> From: "Steven Rostedt" <rostedt@goodmis.org>
> To: "Philippe Proulx" <pproulx@efficios.com>
> Cc: "Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>, "Jeremie Galarneau" <jgalar@efficios.com>, "lttng-dev"
> <lttng-dev@lists.lttng.org>, linux-trace-devel@vger.kernel.org
> Sent: Tuesday, 15 June, 2021 11:57:38
> Subject: Re: [lttng-dev] Usage example of libbabeltrace (babeltrace2) to read CTF traces from a GUI

> [ Adding linux-trace-devel too ]
> 
> On Tue, 15 Jun 2021 11:13:41 -0400
> Philippe Proulx <pproulx@efficios.com> wrote:
> 
>> I can cook a minimal working example in the following days.
> 
> That would be great, thanks!

Here you go (Pastebin: <https://pastebin.com/0MFQkiAw>):

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <babeltrace2/babeltrace.h>

/*
 * Shared data between our relay sink component and the
 * bt_graph_run_once() call site.
 */
struct relay_data {
	bt_message_array_const msgs;
	uint64_t msg_count;
};

/*
 * Consumer method of our relay sink component class.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html#ga301a677396bd8f5bd8b920fd5fa60418>.
 */
static bt_graph_simple_sink_component_consume_func_status relay_consume(
		bt_message_iterator * const msg_iter,
		void * const user_data)
{
	struct relay_data * const relay_data =
		(struct relay_data *) user_data;
	bt_message_iterator_next_status msg_iter_next_status;
	bt_graph_simple_sink_component_consume_func_status status =
		BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_OK;

	/* Consume the next messages, storing them in `*relay_data` */
	msg_iter_next_status = bt_message_iterator_next(msg_iter,
		&relay_data->msgs, &relay_data->msg_count);
	switch (msg_iter_next_status) {
	case BT_MESSAGE_ITERATOR_NEXT_STATUS_END:
		status = BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_END;
		break;
	case BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_MEMORY_ERROR:
		status = BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_MEMORY_ERROR;
		break;
	case BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_ERROR:
		status = BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_ERROR;
		break;
	default:
		assert(status ==
			BT_GRAPH_SIMPLE_SINK_COMPONENT_CONSUME_FUNC_STATUS_OK);
		break;
	}

	return status;
}

/*
 * Adds our own sink component named `relay` to the trace processing
 * graph `graph`.
 *
 * On success, `*comp` is the added sink component.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html#api-graph-lc-add-ss>.
 */
static bt_graph_add_component_status add_relay_comp(bt_graph * const graph,
		struct relay_data * const relay_data,
		const bt_component_sink ** const comp)
{
	return bt_graph_add_simple_sink_component(graph, "relay", NULL,
		relay_consume, NULL, relay_data, comp);
}

/*
 * Creates and returns the parameters to initialize the `src.ctf.fs`
 * component with the trace directory `trace_dir`.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-val.html>.
 */
static bt_value *create_ctf_fs_comp_params(const char * const trace_dir)
{
	bt_value *params;
	bt_value *inputs = NULL;
	bt_value_map_insert_entry_status insert_entry_status;
	bt_value_array_append_element_status append_elem_status;

	/* Create an empty map value */
	params = bt_value_map_create();
	if (!params) {
		goto error;
	}

	/*
	 * Insert an empty array value having the key `inputs`.
	 *
	 * `inputs` is a borrowed value object here, _not_ our
	 * reference.
	 */
	insert_entry_status = bt_value_map_insert_empty_array_entry(params,
		"inputs", &inputs);
	if (insert_entry_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
		goto error;
	}

	/* Append the trace directory to the `inputs` array value */
	append_elem_status = bt_value_array_append_string_element(inputs,
		trace_dir);
	if (append_elem_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
		goto error;
	}

	goto end;

error:
	BT_VALUE_PUT_REF_AND_RESET(params);

end:
	return params;
}

/*
 * Adds a `src.ctf.fs` component named `ctf` to read the trace directory
 * `trace_dir` to the trace processing graph `graph`.
 *
 * See <https://babeltrace.org/docs/v2.0/man7/babeltrace2-source.ctf.fs.7/>.
 *
 * On success, `*comp` is the added source component.
 */
static bt_graph_add_component_status add_ctf_fs_comp(bt_graph * const graph,
		const char * const trace_dir,
		const bt_component_source ** const comp)
{
	const bt_plugin *plugin;
	bt_plugin_find_status plugin_find_status;
	const bt_component_class_source *comp_cls;
	bt_value *params = NULL;
	bt_graph_add_component_status add_comp_status;

	/* Find the `ctf` plugin */
	plugin_find_status = bt_plugin_find("ctf", BT_TRUE, BT_TRUE,
		BT_TRUE, BT_TRUE, BT_TRUE, &plugin);
	if (plugin_find_status != BT_PLUGIN_FIND_STATUS_OK) {
		goto error;
	}

	/* Borrow the `fs` source component class within the `ctf` plugin */
	comp_cls = bt_plugin_borrow_source_component_class_by_name_const(
		plugin, "fs");
	if (!comp_cls) {
		goto error;
	}

	/* Create the parameters to initialize the source component */
	params = create_ctf_fs_comp_params(trace_dir);
	if (!params) {
		goto error;
	}

	/* Add the source component to the graph */
	add_comp_status = bt_graph_add_source_component(graph, comp_cls,
		"ctf", params, BT_LOGGING_LEVEL_NONE, comp);
	goto end;

error:
	add_comp_status = BT_GRAPH_ADD_COMPONENT_STATUS_ERROR;

end:
	bt_plugin_put_ref(plugin);
	bt_value_put_ref(params);
	return add_comp_status;
}

/*
 * Adds a `flt.utils.muxer` component named `muxer` to the trace
 * processing graph `graph`.
 *
 * See <https://babeltrace.org/docs/v2.0/man7/babeltrace2-filter.utils.muxer.7/>.
 *
 * On success, `*comp` is the added filter component.
 */
static bt_graph_add_component_status add_muxer_comp(bt_graph * const graph,
		const bt_component_filter ** const comp)
{
	const bt_plugin *plugin;
	bt_plugin_find_status plugin_find_status;
	const bt_component_class_filter *comp_cls;
	bt_graph_add_component_status add_comp_status;

	/* Find the `utils` plugin */
	plugin_find_status = bt_plugin_find("utils", BT_TRUE, BT_TRUE,
		BT_TRUE, BT_TRUE, BT_TRUE, &plugin);
	if (plugin_find_status != BT_PLUGIN_FIND_STATUS_OK) {
		goto error;
	}

	/* Borrow the `muxer` filter comp. class within the `utils` plugin */
	comp_cls = bt_plugin_borrow_filter_component_class_by_name_const(
		plugin, "muxer");
	if (!comp_cls) {
		goto error;
	}

	/* Add the filter component to the graph (no init. parameters) */
	add_comp_status = bt_graph_add_filter_component(graph, comp_cls,
		"muxer", NULL, BT_LOGGING_LEVEL_NONE, comp);
	goto end;

error:
	add_comp_status = BT_GRAPH_ADD_COMPONENT_STATUS_ERROR;

end:
	bt_plugin_put_ref(plugin);
	return add_comp_status;
}

/*
 * Creates a trace processing graph having this layout:
 *
 *     +------------+    +-----------------+    +--------------+
 *     | src.ctf.fs |    | flt.utils.muxer |    | Our own sink |
 *     |    [ctf]   |    |     [muxer]     |    |    [relay]   |
 *     |            |    |                 |    |              |
 *     |    stream0 @--->@ in0         out @--->@ in           |
 *     |    stream1 @--->@ in1             |    +--------------+
 *     |    stream2 @--->@ in2             |
 *     |    stream3 @--->@ in3             |
 *     +------------+    @ in4             |
 *                       +-----------------+
 *
 * In the example above, the `src.ctf.fs` component reads a CTF trace
 * having four data streams. The `trace_dir` parameter is the directory
 * containing the CTF trace to read.
 *
 * Our own relay sink component, of which the consuming method is
 * relay_consume(), consumes messages from the `flt.utils.muxer`
 * component, storing them to a structure (`*relay_data`) shared with
 * the bt_graph_run_once() call site.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html>.
 */
static bt_graph *create_graph(const char * const trace_dir,
		struct relay_data * const relay_data)
{
	bt_graph *graph;
	const bt_component_source *ctf_fs_comp;
	const bt_component_filter *muxer_comp;
	const bt_component_sink *relay_comp;
	bt_graph_add_component_status add_comp_status;
	bt_graph_connect_ports_status connect_ports_status;
	uint64_t i;

	/* Create an empty trace processing graph */
	graph = bt_graph_create(0);
	if (!graph) {
		goto error;
	}

	/* Create and add the three required components to `graph` */
	add_comp_status = add_ctf_fs_comp(graph, trace_dir, &ctf_fs_comp);
	if (add_comp_status != BT_GRAPH_ADD_COMPONENT_STATUS_OK) {
		goto error;
	}

	add_comp_status = add_muxer_comp(graph, &muxer_comp);
	if (add_comp_status != BT_GRAPH_ADD_COMPONENT_STATUS_OK) {
		goto error;
	}

	add_comp_status = add_relay_comp(graph, relay_data, &relay_comp);
	if (add_comp_status != BT_GRAPH_ADD_COMPONENT_STATUS_OK) {
		goto error;
	}

	/*
	 * Connect all the output ports of the `ctf` source component to
	 * the input ports of the `muxer` filter component.
	 *
	 * An `flt.utils.muxer` component adds an input port every time
	 * you connect one, making one always available.
	 *
	 * See <https://babeltrace.org/docs/v2.0/man7/babeltrace2-filter.utils.muxer.7/#doc-_input>.
	 */
	for (i = 0; i < bt_component_source_get_output_port_count(ctf_fs_comp);
			i++) {
		const bt_port_output * const out_port =
			bt_component_source_borrow_output_port_by_index_const(
				ctf_fs_comp, i);
		const bt_port_input * const in_port =
			bt_component_filter_borrow_input_port_by_index_const(
				muxer_comp, i);

		/* Connect ports */
		connect_ports_status = bt_graph_connect_ports(graph,
			out_port, in_port, NULL);

		if (connect_ports_status != BT_GRAPH_CONNECT_PORTS_STATUS_OK) {
			goto error;
		}
	}

	/* Connect the `muxer` output port to the `relay` input port */
	connect_ports_status = bt_graph_connect_ports(graph,
		bt_component_filter_borrow_output_port_by_index_const(
			muxer_comp, 0),
		bt_component_sink_borrow_input_port_by_index_const(
			relay_comp, 0), NULL);
	if (connect_ports_status != BT_GRAPH_CONNECT_PORTS_STATUS_OK) {
		goto error;
	}

	goto end;

error:
	BT_GRAPH_PUT_REF_AND_RESET(graph);

end:
	return graph;
}

/*
 * Handles a single message `msg`, printing its name if it's an event
 * message.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-msg.html>.
 */
static void handle_msg(const bt_message * const msg)
{
	const bt_event *event;

	if (bt_message_get_type(msg) != BT_MESSAGE_TYPE_EVENT) {
		goto end;
	}

	event = bt_message_event_borrow_event_const(msg);
	puts(bt_event_class_get_name(bt_event_borrow_class_const(event)));

end:
	return;
}

/*
 * Runs the trace processing graph `graph`, our relay sink component
 * transferring its consumed messages to `*relay_data`.
 *
 * See <https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html#api-graph-lc-run>.
 */
static int run_graph(bt_graph * const graph,
		struct relay_data * const relay_data)
{
	bt_graph_run_once_status status;

	while (true) {
		uint64_t i;

		/*
		 * bt_graph_run_once() calls the consuming method of
		 * our relay sink component (relay_consume()).
		 *
		 * relay_consume() consumes a batch of messages from the
		 * `flt.utils.muxer` component and stores them in
		 * `*relay_data`.
		 */
		status = bt_graph_run_once(graph);
		assert(status != BT_GRAPH_RUN_ONCE_STATUS_AGAIN);
		if (status != BT_GRAPH_RUN_ONCE_STATUS_OK) {
			break;
		}

		/* Handle each consumed message */
		for (i = 0; i < relay_data->msg_count; i++) {
			const bt_message * const msg = relay_data->msgs[i];

			handle_msg(msg);

			/*
			 * The message reference `msg` is ours: release
			 * it now.
			 */
			bt_message_put_ref(msg);
		}
	}

	return status == BT_GRAPH_RUN_ONCE_STATUS_END ? 0 : -1;
}

/*
 * Reads the CTF trace located in the directory `argv[1]`, printing one
 * event name per line to the standard output.
 */
int main(const int argc, const char * const * const argv)
{
	int ret = EXIT_SUCCESS;
	struct relay_data relay_data = { 0 };
	bt_graph *graph;

	assert(argc == 2);

	/* Create the trace processing graph */
	graph = create_graph(argv[1], &relay_data);
	if (!graph) {
		ret = EXIT_FAILURE;
		goto end;
	}

	/* Run the graph, printing one event name per line */
	if (run_graph(graph, &relay_data)) {
		ret = EXIT_FAILURE;
	}

end:
	bt_graph_put_ref(graph);
	return ret;
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Build as such:

    $ cc -Wextra -Wall -o read-ctf-example read-ctf-example.c \
         $(pkg-config babeltrace2 --cflags --libs)

Feel free to ask us any questions.

Philippe Proulx
EfficiOS Inc.
https://www.efficios.com/

> 
> -- Steve
> 
>> 
>> Phil
>> 
>> [1]: https://babeltrace.org/docs/v2.0/libbabeltrace2/
>> [2]:
>> https://babeltrace.org/docs/v2.0/libbabeltrace2/group__api-graph.html#gaa8432f03a967d01b764fb1bc959c8e89
>> 
>> >
>> > Thanks,
>> >
>> > Mathieu
>> >
>> > --
>> > Mathieu Desnoyers
>> > EfficiOS Inc.
>> > http://www.efficios.com
>> > _______________________________________________
>> > lttng-dev mailing list
>> > lttng-dev@lists.lttng.org
> > > https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
_______________________________________________
lttng-dev mailing list
lttng-dev@lists.lttng.org
https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev

  reply	other threads:[~2021-06-19  3:42 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-14 20:00 [lttng-dev] Usage example of libbabeltrace (babeltrace2) to read CTF traces from a GUI Mathieu Desnoyers via lttng-dev
2021-06-15 15:13 ` Philippe Proulx via lttng-dev
2021-06-15 15:57   ` Steven Rostedt
2021-06-15 15:57     ` Steven Rostedt via lttng-dev
2021-06-19  3:42     ` Philippe Proulx [this message]
2021-06-19  3:42       ` Philippe Proulx via lttng-dev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1743432091.13845.1624074121104.JavaMail.zimbra@efficios.com \
    --to=pproulx@efficios.com \
    --cc=jgalar@efficios.com \
    --cc=linux-trace-devel@vger.kernel.org \
    --cc=lttng-dev@lists.lttng.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=rostedt@goodmis.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.