From 14b7ef9e86ccb63ce371b741449d5ee1b8e512ed Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 20 Jun 2017 15:40:17 -0400 Subject: [PATCH] Add sink.utils.counter MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit A sink.utils.counter component counts the number of received notifications (one count per notification type) and prints the counts every 1000 notifications (total) by default and at the end. You can use the `step` parameter to modify how frequent the component prints the counts: babeltrace /path/to/trace -c sink.utils.counter -p step=5000 You can set `step` to 0 to print the counts only at the end: babeltrace /path/to/trace -c sink.utils.counter -p step=0 Notifications of which the type is not known (if this component is used in future releases of Babeltrace 2) are classified under "Other (unknown)", which is only printed if there's at least one unknown notification. You can use the `hide-zero` parameter (boolean) to hide the counts which are 0. The goal of this component class is to have a dummy sink component with regular updates, for debugging and benchmarking purposes. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- configure.ac | 1 + plugins/text/plugin.c | 2 +- plugins/utils/Makefile.am | 3 +- plugins/utils/counter/Makefile.am | 4 + plugins/utils/counter/counter.c | 322 ++++++++++++++++++++++++++++++ plugins/utils/counter/counter.h | 62 ++++++ plugins/utils/plugin.c | 16 +- 7 files changed, 405 insertions(+), 5 deletions(-) create mode 100644 plugins/utils/counter/Makefile.am create mode 100644 plugins/utils/counter/counter.c create mode 100644 plugins/utils/counter/counter.h diff --git a/configure.ac b/configure.ac index 3a6eca9a..f7503d5c 100644 --- a/configure.ac +++ b/configure.ac @@ -523,6 +523,7 @@ AC_CONFIG_FILES([ plugins/text/pretty/Makefile plugins/utils/Makefile plugins/utils/dummy/Makefile + plugins/utils/counter/Makefile plugins/utils/trimmer/Makefile plugins/utils/muxer/Makefile python-plugin-provider/Makefile diff --git a/plugins/text/plugin.c b/plugins/text/plugin.c index 563c8d77..302c079f 100644 --- a/plugins/text/plugin.c +++ b/plugins/text/plugin.c @@ -39,4 +39,4 @@ BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(pretty, pretty_finalize); BT_PLUGIN_SINK_COMPONENT_CLASS_PORT_CONNECTED_METHOD(pretty, pretty_port_connected); BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(pretty, - "Pretty-printing text output (`text` format of Babeltrace 1)."); + "Pretty-print notifications (`text` format of Babeltrace 1)."); diff --git a/plugins/utils/Makefile.am b/plugins/utils/Makefile.am index decee2c5..e0b3094f 100644 --- a/plugins/utils/Makefile.am +++ b/plugins/utils/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins -SUBDIRS = dummy trimmer muxer . +SUBDIRS = dummy counter trimmer muxer . plugindir = "$(PLUGINSDIR)" plugin_LTLIBRARIES = babeltrace-plugin-utils.la @@ -11,6 +11,7 @@ babeltrace_plugin_utils_la_LDFLAGS = \ -avoid-version -module babeltrace_plugin_utils_la_LIBADD = \ dummy/libbabeltrace-plugin-dummy-cc.la \ + counter/libbabeltrace-plugin-counter-cc.la \ trimmer/libbabeltrace-plugin-trimmer.la \ muxer/libbabeltrace-plugin-muxer.la diff --git a/plugins/utils/counter/Makefile.am b/plugins/utils/counter/Makefile.am new file mode 100644 index 00000000..d46bafe6 --- /dev/null +++ b/plugins/utils/counter/Makefile.am @@ -0,0 +1,4 @@ +AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins + +noinst_LTLIBRARIES = libbabeltrace-plugin-counter-cc.la +libbabeltrace_plugin_counter_cc_la_SOURCES = counter.c counter.h diff --git a/plugins/utils/counter/counter.c b/plugins/utils/counter/counter.c new file mode 100644 index 00000000..a1c1cd4b --- /dev/null +++ b/plugins/utils/counter/counter.c @@ -0,0 +1,322 @@ +/* + * Copyright 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "counter.h" + +#define PRINTF_COUNT(_what_sing, _what_plur, _var, args...) \ + do { \ + if (counter->count._var != 0 || !counter->hide_zero) { \ + printf("%15" PRIu64 " %s\n", \ + counter->count._var, \ + counter->count._var == 1 ? _what_sing : _what_plur); \ + } \ + } while (0) + +static +uint64_t get_total_count(struct counter *counter) +{ + return counter->count.event + + counter->count.stream_begin + + counter->count.stream_end + + counter->count.packet_begin + + counter->count.packet_end + + counter->count.inactivity + + counter->count.discarded_events + + counter->count.discarded_packets + + counter->count.other; +} + +static +void print_count(struct counter *counter, uint64_t total) +{ + PRINTF_COUNT("event", "events", event); + PRINTF_COUNT("stream beginning", "stream beginnings", stream_begin); + PRINTF_COUNT("stream end", "stream ends", stream_end); + PRINTF_COUNT("packet beginning", "packet beginnings", packet_begin); + PRINTF_COUNT("packet end", "packet ends", packet_end); + PRINTF_COUNT("inactivity", "inactivities", inactivity); + PRINTF_COUNT("discarded events notification", + "discarded events notifications", discarded_events_notifs); + PRINTF_COUNT(" known discarded event", " known discarded events", + discarded_events); + PRINTF_COUNT("discarded packets notification", + "discarded packets notifications", discarded_packets_notifs); + PRINTF_COUNT(" known discarded packet", " known discarded packets", + discarded_packets); + + if (counter->count.other > 0) { + PRINTF_COUNT(" other (unknown) notification", + " other (unknown) notifications", other); + } + + printf("%s%15" PRIu64 " notification%s (TOTAL)%s\n", + bt_common_color_bold(), total, total == 1 ? "" : "s", + bt_common_color_reset()); + counter->last_printed_total = total; +} + +static +void try_print_count(struct counter *counter) +{ + uint64_t total; + + if (counter->step == 0) { + /* No update */ + return; + } + + total = get_total_count(counter); + + if (total % counter->step == 0) { + print_count(counter, total); + putchar('\n'); + } +} + +static +void try_print_last(struct counter *counter) +{ + const uint64_t total = get_total_count(counter); + + if (total != counter->last_printed_total) { + print_count(counter, total); + } +} + +void destroy_private_counter_data(struct counter *counter) +{ + bt_put(counter->notif_iter); + g_free(counter); +} + +void counter_finalize(struct bt_private_component *component) +{ + struct counter *counter; + + assert(component); + counter = bt_private_component_get_user_data(component); + assert(counter); + try_print_last(counter); + bt_put(counter->notif_iter); + g_free(counter); +} + +enum bt_component_status counter_init(struct bt_private_component *component, + struct bt_value *params, UNUSED_VAR void *init_method_data) +{ + enum bt_component_status ret; + struct counter *counter = g_new0(struct counter, 1); + struct bt_value *step = NULL; + struct bt_value *hide_zero = NULL; + + if (!counter) { + ret = BT_COMPONENT_STATUS_NOMEM; + goto end; + } + + ret = bt_private_component_sink_add_input_private_port(component, + "in", NULL, NULL); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + + counter->last_printed_total = -1ULL; + counter->step = 1000; + step = bt_value_map_get(params, "step"); + if (bt_value_is_integer(step)) { + int64_t val; + int vret = bt_value_integer_get(step, &val); + + assert(vret == 0); + + if (val >= 0) { + counter->step = (uint64_t) val; + } + } + + hide_zero = bt_value_map_get(params, "hide-zero"); + if (bt_value_is_bool(hide_zero)) { + bt_bool val; + int vret = bt_value_bool_get(hide_zero, &val); + + assert(vret == 0); + counter->hide_zero = (bool) val; + } + + ret = bt_private_component_set_user_data(component, counter); + if (ret != BT_COMPONENT_STATUS_OK) { + goto error; + } + + goto end; + +error: + destroy_private_counter_data(counter); + +end: + bt_put(step); + bt_put(hide_zero); + return ret; +} + +void counter_port_connected( + struct bt_private_component *component, + struct bt_private_port *self_port, + struct bt_port *other_port) +{ + struct counter *counter; + struct bt_notification_iterator *iterator; + struct bt_private_connection *connection; + enum bt_connection_status conn_status; + + counter = bt_private_component_get_user_data(component); + assert(counter); + connection = bt_private_port_get_private_connection(self_port); + assert(connection); + conn_status = bt_private_connection_create_notification_iterator( + connection, NULL, &iterator); + if (conn_status != BT_CONNECTION_STATUS_OK) { + counter->error = true; + goto end; + } + + BT_MOVE(counter->notif_iter, iterator); + +end: + bt_put(connection); +} + +enum bt_component_status counter_consume(struct bt_private_component *component) +{ + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + struct bt_notification *notif = NULL; + struct counter *counter; + enum bt_notification_iterator_status it_ret; + int64_t count; + + counter = bt_private_component_get_user_data(component); + assert(counter); + + if (unlikely(counter->error)) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + + if (unlikely(!counter->notif_iter)) { + try_print_last(counter); + ret = BT_COMPONENT_STATUS_END; + goto end; + } + + /* Consume one notification */ + it_ret = bt_notification_iterator_next(counter->notif_iter); + if (it_ret < 0) { + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + + switch (it_ret) { + case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN: + ret = BT_COMPONENT_STATUS_AGAIN; + goto end; + case BT_NOTIFICATION_ITERATOR_STATUS_END: + try_print_last(counter); + ret = BT_COMPONENT_STATUS_END; + goto end; + case BT_NOTIFICATION_ITERATOR_STATUS_OK: + { + struct bt_notification *notif = + bt_notification_iterator_get_notification(counter->notif_iter); + + assert(notif); + switch (bt_notification_get_type(notif)) { + case BT_NOTIFICATION_TYPE_EVENT: + counter->count.event++; + break; + case BT_NOTIFICATION_TYPE_INACTIVITY: + counter->count.inactivity++; + break; + case BT_NOTIFICATION_TYPE_STREAM_BEGIN: + counter->count.stream_begin++; + break; + case BT_NOTIFICATION_TYPE_STREAM_END: + counter->count.stream_end++; + break; + case BT_NOTIFICATION_TYPE_PACKET_BEGIN: + counter->count.packet_begin++; + break; + case BT_NOTIFICATION_TYPE_PACKET_END: + counter->count.packet_end++; + break; + case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS: + counter->count.discarded_events_notifs++; + count = bt_notification_discarded_events_get_count( + notif); + if (count >= 0) { + counter->count.discarded_events += count; + } + break; + case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS: + counter->count.discarded_packets_notifs++; + count = bt_notification_discarded_packets_get_count( + notif); + if (count >= 0) { + counter->count.discarded_packets += count; + } + break; + default: + counter->count.other++; + } + + bt_put(notif); + } + default: + break; + } + + try_print_count(counter); + +end: + bt_put(notif); + return ret; +} diff --git a/plugins/utils/counter/counter.h b/plugins/utils/counter/counter.h new file mode 100644 index 00000000..33dda03e --- /dev/null +++ b/plugins/utils/counter/counter.h @@ -0,0 +1,62 @@ +#ifndef BABELTRACE_PLUGINS_UTILS_COUNTER_H +#define BABELTRACE_PLUGINS_UTILS_COUNTER_H + +/* + * Copyright 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +struct counter { + struct bt_notification_iterator *notif_iter; + struct { + uint64_t event; + uint64_t stream_begin; + uint64_t stream_end; + uint64_t packet_begin; + uint64_t packet_end; + uint64_t inactivity; + uint64_t discarded_events_notifs; + uint64_t discarded_events; + uint64_t discarded_packets_notifs; + uint64_t discarded_packets; + uint64_t other; + } count; + uint64_t last_printed_total; + uint64_t step; + bool hide_zero; + bool error; +}; + +enum bt_component_status counter_init(struct bt_private_component *component, + struct bt_value *params, void *init_method_data); +void counter_finalize(struct bt_private_component *component); +void counter_port_connected(struct bt_private_component *component, + struct bt_private_port *self_port, + struct bt_port *other_port); +enum bt_component_status counter_consume(struct bt_private_component *component); + +#endif /* BABELTRACE_PLUGINS_UTILS_COUNTER_H */ diff --git a/plugins/utils/plugin.c b/plugins/utils/plugin.c index c5ed25a3..be39891b 100644 --- a/plugins/utils/plugin.c +++ b/plugins/utils/plugin.c @@ -22,6 +22,7 @@ #include #include "dummy/dummy.h" +#include "counter/counter.h" #include "trimmer/trimmer.h" #include "trimmer/iterator.h" #include "muxer/muxer.h" @@ -35,7 +36,7 @@ BT_PLUGIN_DESCRIPTION("Graph utilities"); BT_PLUGIN_AUTHOR("Julien Desfossez, Jérémie Galarneau, Philippe Proulx"); BT_PLUGIN_LICENSE("MIT"); -/* dummy sink */ +/* sink.utils.dummy */ BT_PLUGIN_SINK_COMPONENT_CLASS(dummy, dummy_consume); BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(dummy, dummy_init); BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(dummy, dummy_finalize); @@ -44,7 +45,16 @@ BT_PLUGIN_SINK_COMPONENT_CLASS_PORT_CONNECTED_METHOD(dummy, BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(dummy, "Consume notifications and discard them."); -/* trimmer filter */ +/* sink.utils.counter */ +BT_PLUGIN_SINK_COMPONENT_CLASS(counter, counter_consume); +BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(counter, counter_init); +BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(counter, counter_finalize); +BT_PLUGIN_SINK_COMPONENT_CLASS_PORT_CONNECTED_METHOD(counter, + counter_port_connected); +BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(counter, + "Count notifications and print the results."); + +/* flt.utils.trimmer */ BT_PLUGIN_FILTER_COMPONENT_CLASS(trimmer, trimmer_iterator_next); BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(trimmer, "Keep notifications that occur within a specific time range."); @@ -57,7 +67,7 @@ BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_FINALIZE_METHOD(trimmer, BT_PLUGIN_FILTER_COMPONENT_CLASS_NOTIFICATION_ITERATOR_SEEK_TIME_METHOD(trimmer, trimmer_iterator_seek_time); -/* muxer filter */ +/* flt.utils.muxer */ BT_PLUGIN_FILTER_COMPONENT_CLASS(muxer, muxer_notif_iter_next); BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(muxer, "Sort notifications from multiple input ports to a single output port by time."); -- 2.34.1