Babeltrace 2 C API 2.1.0
Open-source trace manipulation framework
Loading...
Searching...
No Matches
Simple filter component class

This example shows a basic filter component class packaged as a shared object plugin.

The name of the plugin is distill and the name of the filter component class is theone. Therefore the component class is identified in the babeltrace2 command-line tool as filter.distill.theone.

A filter.distill.theone component removes specific event messages from a stream based on the name of their event class.

A filter.distill.theone component accepts a single initialization parameter, names, which is an array value of string values. The array value contains the names of the classes of the events to discard.

A filter.distill.theone component creates a single input port named in and a single output port named out.

To simplify this example, a filter.distill.theone component isn't resilient and needs a valid input and valid initialization parameters. The code also doesn't check the return status codes of API functions for simplicity, but you must check them in production code.

The filter component class implementation and the shared object plugin macros are in the same file, distill.c:

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdbool.h>
#include <babeltrace2/babeltrace.h>
/* Filter component's private data */
struct distill {
/* Names of the classes of the events to discard (owned by this) */
const bt_value *names_value;
/* Component's input port (weak) */
};
/*
* Initializes the filter component.
*/
static
bt_self_component_filter *self_component_filter,
const bt_value *params, void *initialize_method_data)
{
/* Allocate a private data structure */
struct distill *distill = malloc(sizeof(*distill));
/*
* Keep a reference of the `names` array value parameter so that the
* "next" method of a message iterator can access it to decide
* whether or not to discard an event message.
*/
distill->names_value =
bt_value_get_ref(distill->names_value);
/* Set the component's user data to our private data structure */
distill);
/*
* Add an input port named `in` to the filter component.
*
* This is needed so that this filter component can be connected to
* a filter or a source component. With a connected upstream
* component, this filter component's message iterator can create a
* message iterator to consume messages.
*
* Add an output port named `out` to the filter component.
*
* This is needed so that this filter component can be connected to
* a filter or a sink component. Once a downstream component is
* connected, it can create our message iterator.
*/
"in", NULL, &distill->in_port);
"out", NULL, NULL);
}
/*
* Finalizes the filter component.
*/
static
void distill_finalize(bt_self_component_filter *self_component_filter)
{
/* Retrieve our private data from the component's user data */
struct distill *distill = bt_self_component_get_data(
/* Put all references */
bt_value_put_ref(distill->names_value);
/* Free the allocated structure */
free(distill);
}
/* Message iterator's private data */
struct distill_message_iterator {
/* (Weak) link to the component's private data */
struct distill *distill;
/* Upstream message iterator (owned by this) */
bt_message_iterator *message_iterator;
};
/*
* Initializes the message iterator.
*/
static
distill_message_iterator_initialize(
bt_self_message_iterator *self_message_iterator,
{
/* Allocate a private data structure */
struct distill_message_iterator *distill_iter =
malloc(sizeof(*distill_iter));
/* Retrieve the component's private data from its user data */
struct distill *distill = bt_self_component_get_data(
/* Keep a link to the component's private data */
distill_iter->distill = distill;
/* Create the upstream message iterator */
distill->in_port, &distill_iter->message_iterator);
/* Set the message iterator's user data to our private data structure */
bt_self_message_iterator_set_data(self_message_iterator, distill_iter);
}
/*
* Finalizes the message iterator.
*/
static
void distill_message_iterator_finalize(
bt_self_message_iterator *self_message_iterator)
{
/* Retrieve our private data from the message iterator's user data */
struct distill_message_iterator *distill_iter =
bt_self_message_iterator_get_data(self_message_iterator);
/* Free the allocated structure */
free(distill_iter);
}
/*
* Returns `true` if `message` passes, that is, one of:
*
* * It's not an event message.
* * The event message doesn't need to be discarded based on its event
* class's name.
*/
static
bool message_passes(struct distill_message_iterator *distill_iter,
const bt_message *message)
{
bool passes = true;
/* Move as is if it's not an event message */
goto end;
}
/* Borrow the event message's event and its class */
const bt_event *event =
const bt_event_class *event_class = bt_event_borrow_class_const(event);
/* Get the event class's name */
const char *name = bt_event_class_get_name(event_class);
for (uint64_t i = 0; i < bt_value_array_get_length(
distill_iter->distill->names_value); i++) {
const char *discard_name = bt_value_string_get(
distill_iter->distill->names_value, i));
if (strcmp(name, discard_name) == 0) {
passes = false;
goto end;
}
}
end:
return passes;
}
/*
* Returns the next message to the message iterator's user.
*
* This method can fill the `messages` array with up to `capacity`
* messages.
*
* To keep this example simple, we put a single message into `messages`
* and set `*count` to 1 (if the message iterator isn't ended).
*/
static
bt_message_iterator_class_next_method_status distill_message_iterator_next(
bt_self_message_iterator *self_message_iterator,
bt_message_array_const messages, uint64_t capacity,
uint64_t *count)
{
/* Retrieve our private data from the message iterator's user data */
struct distill_message_iterator *distill_iter =
bt_self_message_iterator_get_data(self_message_iterator);
/* Consume a batch of messages from the upstream message iterator */
bt_message_array_const upstream_messages;
uint64_t upstream_message_count;
consume_upstream_messages:
next_status = bt_message_iterator_next(distill_iter->message_iterator,
&upstream_messages, &upstream_message_count);
/* Initialize the return status to a success */
switch (next_status) {
/* End of iteration: put the message iterator's reference */
bt_message_iterator_put_ref(distill_iter->message_iterator);
goto end;
goto end;
goto end;
goto end;
default:
break;
}
/* Output message array index */
uint64_t i = 0;
/* For each consumed message */
for (uint64_t upstream_i = 0; upstream_i < upstream_message_count;
upstream_i++) {
/* Current message */
const bt_message *upstream_message = upstream_messages[upstream_i];
/* Check if the upstream message passes */
if (message_passes(distill_iter, upstream_message)) {
/* Move upstream message to output message array */
messages[i] = upstream_message;
i++;
continue;
}
/* Discard upstream message: put its reference */
bt_message_put_ref(upstream_message);
}
if (i == 0) {
/*
* We discarded all the upstream messages: get a new batch of
* messages, because this method _cannot_ return
* `BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK` and put no
* messages into its output message array.
*/
goto consume_upstream_messages;
}
*count = i;
end:
return status;
}
/* Mandatory */
/* Define the `distill` plugin */
BT_PLUGIN(distill);
/* Define the `theone` filter component class */
BT_PLUGIN_FILTER_COMPONENT_CLASS(theone, distill_message_iterator_next);
/* Set some of the `theone` filter component class's optional methods */
theone, distill_message_iterator_initialize);
distill_message_iterator_finalize);
bt_message const ** bt_message_array_const
Array of constant messages.
Definition types.h:182
bt_component_class_initialize_method_status
Status codes for bt_component_class_source_initialize_method, bt_component_class_filter_initialize_me...
Definition component-class-dev.h:891
@ BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK
Success.
Definition component-class-dev.h:896
bt_message_iterator_class_initialize_method_status
Status codes for bt_message_iterator_class_initialize_method.
Definition message-iterator-class.h:661
bt_message_iterator_class_next_method_status
Status codes for bt_message_iterator_class_next_method.
Definition message-iterator-class.h:718
@ BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK
Success.
Definition message-iterator-class.h:666
@ BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR
Out of memory.
Definition message-iterator-class.h:741
@ BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK
Success.
Definition message-iterator-class.h:723
@ BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END
End of iteration.
Definition message-iterator-class.h:729
@ BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR
User error.
Definition message-iterator-class.h:747
@ BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_AGAIN
Try again.
Definition message-iterator-class.h:735
void bt_message_iterator_put_ref(const bt_message_iterator *message_iterator)
Decrements the reference count of the message iterator message_iterator.
bt_message_iterator_next_status bt_message_iterator_next(bt_message_iterator *message_iterator, bt_message_array_const *messages, uint64_t *count)
Returns the next messages of the message iterator message_iterator into the *messages array of size *...
bt_message_iterator_create_from_message_iterator_status bt_message_iterator_create_from_message_iterator(bt_self_message_iterator *self_message_iterator, bt_self_component_port_input *port, bt_message_iterator **message_iterator)
Creates a message iterator on the input port port from another message iterator self_message_iterator...
bt_message_iterator_next_status
Status code for bt_message_iterator_next().
Definition message-iterator.h:371
struct bt_message_iterator bt_message_iterator
Message iterator.
Definition types.h:59
@ BT_MESSAGE_ITERATOR_NEXT_STATUS_END
End of iteration.
Definition message-iterator.h:382
@ BT_MESSAGE_ITERATOR_NEXT_STATUS_MEMORY_ERROR
Out of memory.
Definition message-iterator.h:394
@ BT_MESSAGE_ITERATOR_NEXT_STATUS_ERROR
Other error.
Definition message-iterator.h:400
@ BT_MESSAGE_ITERATOR_NEXT_STATUS_AGAIN
Try again.
Definition message-iterator.h:388
struct bt_message bt_message
Message.
Definition types.h:58
const bt_event * bt_message_event_borrow_event_const(const bt_message *message)
Borrows the event of the event message message (const version).
bt_message_type bt_message_get_type(const bt_message *message)
Returns the type enumerator of the message message.
void bt_message_put_ref(const bt_message *message)
Decrements the reference count of the message message.
@ BT_MESSAGE_TYPE_EVENT
Event message.
Definition message.h:993
#define BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(_name, _method)
Alias of BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD_WITH_ID() with the _plugin_id parameter set...
Definition plugin-dev.h:1696
#define BT_PLUGIN_FILTER_COMPONENT_CLASS_INITIALIZE_METHOD(_name, _method)
Alias of BT_PLUGIN_FILTER_COMPONENT_CLASS_INITIALIZE_METHOD_WITH_ID() with the _plugin_id parameter s...
Definition plugin-dev.h:1787
#define BT_PLUGIN_MODULE()
Defines a plugin module.
Definition plugin-dev.h:335
#define BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_FINALIZE_METHOD(_name, _method)
Alias of BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_FINALIZE_METHOD_WITH_ID() with the _...
Definition plugin-dev.h:1880
#define BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD(_name, _method)
Alias of BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_WITH_ID() with the...
Definition plugin-dev.h:1926
#define BT_PLUGIN_FILTER_COMPONENT_CLASS(_name, _message_iterator_class_next_method)
Alias of BT_PLUGIN_FILTER_COMPONENT_CLASS_WITH_ID() with the _plugin_id parameter set to auto,...
Definition plugin-dev.h:839
#define BT_PLUGIN(_name)
Alias of BT_PLUGIN_WITH_ID() with the _id parameter set to auto.
Definition plugin-dev.h:423
struct bt_self_component_port_output bt_self_component_port_output
Self component output port.
Definition types.h:81
struct bt_self_component_port_input bt_self_component_port_input
Self component input port.
Definition types.h:79
bt_self_component_add_port_status bt_self_component_filter_add_input_port(bt_self_component_filter *self_component, const char *name, void *user_data, bt_self_component_port_input **self_component_port)
Adds an input port named name and having the user data user_data to the filter component self_compone...
struct bt_self_component_filter_configuration bt_self_component_filter_configuration
Self filter component configuration.
Definition types.h:77
bt_self_component_add_port_status bt_self_component_filter_add_output_port(bt_self_component_filter *self_component, const char *name, void *user_data, bt_self_component_port_output **self_component_port)
Adds an output port named name and having the user data user_data to the filter component self_compon...
void * bt_self_component_get_data(const bt_self_component *self_component)
Returns the user data of the component self_component.
static bt_self_component * bt_self_component_filter_as_self_component(bt_self_component_filter *self_component)
Upcasts the self filter component self_component to the common bt_self_component type.
Definition self-component.h:834
struct bt_self_component_filter bt_self_component_filter
Self filter component.
Definition types.h:76
void bt_self_component_set_data(bt_self_component *self_component, void *user_data)
Sets the user data of the component self_component to data.
struct bt_self_message_iterator_configuration bt_self_message_iterator_configuration
Self message iterator configuration.
Definition types.h:87
bt_self_component * bt_self_message_iterator_borrow_component(bt_self_message_iterator *self_message_iterator)
Borrows the component which provides the message iterator self_message_iterator.
void * bt_self_message_iterator_get_data(const bt_self_message_iterator *self_message_iterator)
Returns the user data of the message iterator self_message_iterator.
struct bt_self_message_iterator bt_self_message_iterator
Self message iterator.
Definition types.h:86
void bt_self_message_iterator_set_data(bt_self_message_iterator *self_message_iterator, void *user_data)
Sets the user data of the message iterator self_message_iterator to data.
const char * bt_event_class_get_name(const bt_event_class *event_class)
Returns the name of the event class event_class.
struct bt_event_class bt_event_class
Event class.
Definition types.h:37
const bt_event_class * bt_event_borrow_class_const(const bt_event *event)
Borrows the class of the event event (const version).
struct bt_event bt_event
Event.
Definition types.h:36
struct bt_value bt_value
Value.
Definition types.h:93
void bt_value_get_ref(const bt_value *value)
Increments the reference count of the value value.
void bt_value_put_ref(const bt_value *value)
Decrements the reference count of the value value.
const char * bt_value_string_get(const bt_value *value)
Returns the raw value of the string value value.
const bt_value * bt_value_map_borrow_entry_value_const(const bt_value *value, const char *key)
Borrows the value of the entry with the key key in the map value value (const version).
const bt_value * bt_value_array_borrow_element_by_index_const(const bt_value *value, uint64_t index)
Borrows the element at index index from the array value value (const version).
uint64_t bt_value_array_get_length(const bt_value *value)
Returns the length of the array value value.

As per the Compile and link a Babeltrace 2 shared object plugin guide, you can build the shared object plugin as such:

$ cc distill.c -fPIC -c $(pkg-config --cflags babeltrace2)
$ ld distill.o -o distill.so -shared $(pkg-config --libs babeltrace2)

With the babeltrace2 tool, you can use a filter.distill.theone component, reading a CTF trace (see babeltrace2-source.ctf.fs(7)) for example:

$ babeltrace2 --plugin-path=. /path/to/ctf/trace \
--component=filter.distill.theone \
--params='names=["sched_switch", "rcu_utilization", "kmem_kfree"]'