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>
struct distill {
};
static
const bt_value *params,
void *initialize_method_data)
{
struct distill *distill = malloc(sizeof(*distill));
distill->names_value =
distill);
"in", NULL, &distill->in_port);
"out", NULL, NULL);
}
static
{
free(distill);
}
struct distill_message_iterator {
struct distill *distill;
};
static
distill_message_iterator_initialize(
{
struct distill_message_iterator *distill_iter =
malloc(sizeof(*distill_iter));
distill_iter->distill = distill;
distill->in_port, &distill_iter->message_iterator);
}
static
void distill_message_iterator_finalize(
{
struct distill_message_iterator *distill_iter =
free(distill_iter);
}
static
bool message_passes(struct distill_message_iterator *distill_iter,
{
bool passes = true;
goto end;
}
distill_iter->distill->names_value); i++) {
distill_iter->distill->names_value, i));
if (strcmp(name, discard_name) == 0) {
passes = false;
goto end;
}
}
end:
return passes;
}
static
uint64_t *count)
{
struct distill_message_iterator *distill_iter =
uint64_t upstream_message_count;
consume_upstream_messages:
&upstream_messages, &upstream_message_count);
switch (next_status) {
goto end;
goto end;
goto end;
goto end;
default:
break;
}
uint64_t i = 0;
for (uint64_t upstream_i = 0; upstream_i < upstream_message_count;
upstream_i++) {
const bt_message *upstream_message = upstream_messages[upstream_i];
if (message_passes(distill_iter, upstream_message)) {
messages[i] = upstream_message;
i++;
continue;
}
}
if (i == 0) {
goto consume_upstream_messages;
}
*count = i;
end:
return status;
}
theone, distill_message_iterator_initialize);
distill_message_iterator_finalize);
As per the Compile and link a Babeltrace 2 shared object plugin guide, you can build the shared object plugin as such:
1 $ cc distill.c -fPIC -c $(pkg-config --cflags babeltrace2)
2 $ 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:
1 $ babeltrace2 --plugin-path=. /path/to/ctf/trace \
2 --component=filter.distill.theone \
3 --params='names=["sched_switch", "rcu_utilization", "kmem_kfree"]'