graph/mip: make bt_get_greatest_operative_mip_version compute operative MIP version
authorSimon Marchi <simon.marchi@efficios.com>
Fri, 11 Mar 2022 02:42:32 +0000 (21:42 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Tue, 23 Aug 2022 16:06:15 +0000 (12:06 -0400)
bt_get_greatest_operative_mip_version is currently implemented assuming
that the only existing MIP version is 0.  It only checks that all
component descriptors support version 0, and then returns 0 as the
computed operative MIP version.

Since the library now supports MIP versions 0 and 1,
bt_get_greatest_operative_mip_version needs to actually compute the
greatest commonly supported version.  Implement something that will work
for any number of MIP versions.

Change validate_operative_mip_version_in_array to
get_supported_mip_version_ranges, make it is solely reponsible for
calling the component class' get_supported_mip_versions method and
append the resulting range set to the `supported_ranges` array.  Or, if
the component class doesn't implement that method, append a range set
with only `[0, 0]`.

Once this is done, we have an array with range sets representing the
supported MIP versions for each soon-to-be component.  Compute (in the
new function find_greatest_compatible_mip_version) the greatest commonly
supported version, if any.

Change-Id: Ief0fe9d3323b4e150fa08282531b55ef15be75cf
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/7579
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
src/lib/graph/mip.c
tests/Makefile.am
tests/lib/Makefile.am
tests/lib/test_mip.c [new file with mode: 0644]

index 10d001989f48a65e913f9ee1825d61a639a1e38a..c70ab21fe0c3afb21faa0424d9580d959eaeda9c 100644 (file)
@@ -20,6 +20,8 @@
 #include "component-descriptor-set.h"
 #include "lib/integer-range-set.h"
 
+#define MAX_MIP_VERSION 1
+
 static
 bool unsigned_integer_range_set_contains(
                const struct bt_integer_range_set *range_set, uint64_t value)
@@ -44,15 +46,49 @@ end:
 }
 
 /*
- * As of this version, this function only validates that all the
- * component descriptors in `descriptors` support MIP version 0, which
- * is the only version supported by this library.
+ * Log the MIP versions (in `range_set`) supported by the component described by
+ * `descr`.
+ */
+static
+void log_supported_mip_versions_range_set(const bt_integer_range_set_unsigned *range_set,
+               const struct bt_component_descriptor_set_entry *descr)
+{
+       uint64_t range_count;
+       uint64_t i;
+
+       if (!BT_LOG_ON_DEBUG) {
+               goto end;
+       }
+
+       range_count = bt_integer_range_set_get_range_count(
+               bt_integer_range_set_unsigned_as_range_set_const(range_set));
+
+       BT_LIB_LOGD("Supported MIP version ranges: %![cc-]C", descr->comp_cls);
+
+       for (i = 0; i < range_count; ++i) {
+               const bt_integer_range_unsigned *range =
+                       bt_integer_range_set_unsigned_borrow_range_by_index_const(
+                               range_set, i);
+               uint64_t lower = bt_integer_range_unsigned_get_lower(range);
+               uint64_t upper = bt_integer_range_unsigned_get_upper(range);
+
+               BT_LIB_LOGD("  [%" PRIu64 ", %" PRIu64 "]", lower, upper);
+       }
+
+end:
+       return;
+}
+
+/*
+ * Get the MIP version ranges supported by descriptors in `descriptors`, append
+ * them to `supported_ranges`.
  *
- * If any component descriptor does not support MIP version 0, then this
- * function returns `BT_FUNC_STATUS_NO_MATCH`.
+ * The elements of `descriptors` are `struct bt_component_descriptor_set_entry *`.
+ * The elements of `supported_ranges` are `bt_integer_range_set_unsigned *`.
  */
 static
-int validate_operative_mip_version_in_array(GPtrArray *descriptors,
+int get_supported_mip_version_ranges(GPtrArray *descriptors,
+               GPtrArray *supported_ranges,
                enum bt_logging_level log_level)
 {
        typedef bt_component_class_get_supported_mip_versions_method_status
@@ -61,11 +97,11 @@ int validate_operative_mip_version_in_array(GPtrArray *descriptors,
                        const struct bt_value *,
                        void * /* init method data */,
                        enum bt_logging_level,
-                       struct bt_integer_range_set *);
+                       bt_integer_range_set_unsigned *);
 
-       int status = BT_FUNC_STATUS_OK;
+       int status;
        uint64_t i;
-       struct bt_integer_range_set *range_set = NULL;
+       struct bt_integer_range_set_unsigned *range_set = NULL;
 
        for (i = 0; i < descriptors->len; i++) {
                struct bt_component_descriptor_set_entry *descr =
@@ -106,83 +142,138 @@ int validate_operative_mip_version_in_array(GPtrArray *descriptors,
                        bt_common_abort();
                }
 
-               if (!method) {
-                       /* Assume 0 */
-                       continue;
-               }
-
-               range_set = (void *) bt_integer_range_set_unsigned_create();
+               range_set = bt_integer_range_set_unsigned_create();
                if (!range_set) {
                        status = BT_FUNC_STATUS_MEMORY_ERROR;
                        goto end;
                }
 
-               BT_ASSERT(descr->params);
-               BT_LIB_LOGD("Calling user's \"get supported MIP versions\" method: "
-                       "%![cc-]+C, %![params-]+v, init-method-data=%p, "
-                       "log-level=%s",
-                       descr->comp_cls, descr->params,
-                       descr->init_method_data,
-                       bt_common_logging_level_string(log_level));
-               method_status = method(descr->comp_cls, descr->params,
-                       descr->init_method_data, log_level,
-                       range_set);
-               BT_LIB_LOGD("User method returned: status=%s",
-                       bt_common_func_status_string(method_status));
-               BT_ASSERT_POST(method_name, "status-ok-with-at-least-one-range",
-                       method_status != BT_FUNC_STATUS_OK ||
-                       range_set->ranges->len > 0,
-                       "User method returned `BT_FUNC_STATUS_OK` without "
-                       "adding a range to the supported MIP version range set.");
-               BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(method_name,
-                       method_status);
-               if (method_status < 0) {
-                       BT_LIB_LOGW_APPEND_CAUSE(
-                               "Component class's \"get supported MIP versions\" method failed: "
+               if (method) {
+                       BT_ASSERT(descr->params);
+                       BT_LIB_LOGD("Calling user's \"get supported MIP versions\" method: "
                                "%![cc-]+C, %![params-]+v, init-method-data=%p, "
                                "log-level=%s",
                                descr->comp_cls, descr->params,
                                descr->init_method_data,
                                bt_common_logging_level_string(log_level));
-                       status = (int) method_status;
-                       goto end;
-               }
-
-               if (!unsigned_integer_range_set_contains(range_set, 0)) {
+                       method_status = method(descr->comp_cls, descr->params,
+                               descr->init_method_data, log_level,
+                               range_set);
+                       BT_LIB_LOGD("User method returned: status=%s",
+                               bt_common_func_status_string(method_status));
+                       BT_ASSERT_POST(method_name, "status-ok-with-at-least-one-range",
+                               method_status != BT_FUNC_STATUS_OK ||
+                               bt_integer_range_set_get_range_count(
+                                       bt_integer_range_set_unsigned_as_range_set_const(range_set)) > 0,
+                               "User method returned `BT_FUNC_STATUS_OK` without "
+                               "adding a range to the supported MIP version range set.");
+                       BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(method_name,
+                               method_status);
+                       if (method_status < 0) {
+                               BT_LIB_LOGW_APPEND_CAUSE(
+                                       "Component class's \"get supported MIP versions\" method failed: "
+                                       "%![cc-]+C, %![params-]+v, init-method-data=%p, "
+                                       "log-level=%s",
+                                       descr->comp_cls, descr->params,
+                                       descr->init_method_data,
+                                       bt_common_logging_level_string(log_level));
+                               status = (int) method_status;
+                               goto end;
+                       }
+               } else {
                        /*
-                        * Supported MIP versions do not include 0,
-                        * which is the only MIP versions currently
-                        * supported by the library itself.
+                        * Component class does not implement the
+                        * get_supported_mip_versions method, it means it only
+                        * supports version 0.
                         */
-                       status = BT_FUNC_STATUS_NO_MATCH;
-                       goto end;
+                       bt_integer_range_set_add_range_status add_range_status
+                               = bt_integer_range_set_unsigned_add_range(range_set, 0, 0);
+                       if (add_range_status != BT_INTEGER_RANGE_SET_ADD_RANGE_STATUS_OK) {
+                               status = (int) add_range_status;
+                               goto end;
+                       }
                }
 
-               BT_OBJECT_PUT_REF_AND_RESET(range_set);
+               log_supported_mip_versions_range_set(range_set, descr);
+
+               /* Transfer ownership of `range_set` */
+               g_ptr_array_add(supported_ranges, range_set);
+               range_set = NULL;
        }
 
+       status = BT_FUNC_STATUS_OK;
+
 end:
        bt_object_put_ref(range_set);
        return status;
 }
 
 /*
- * The purpose of this function is eventually to find the greatest
- * common supported MIP version amongst all the component descriptors.
- * But as of this version of the library, only MIP version 0 is
- * supported, so it only checks that they all support MIP version 0 and
- * always sets `*operative_mip_version` to 0.
- *
- * When any component descriptor does not support MIP version 0, this
- * function returns `BT_FUNC_STATUS_NO_MATCH`.
+ * Given `supported_ranges`, an array of `bt_integer_range_set_unsigned *`
+ * representing the supported MIP version ranges of multiple eventual
+ * components, find the greatest version supported by all.
  */
+static
+bt_get_greatest_operative_mip_version_status find_greatest_compatible_mip_version(
+               const GPtrArray *supported_ranges,
+               uint64_t *operative_mip_version)
+{
+       bool versions[MAX_MIP_VERSION + 1];
+       guint range_set_i;
+       int v;
+       bt_get_greatest_operative_mip_version_status status;
+
+       /* Start by assuming all existing MIP versions are supported. */
+       for (v = 0; v <= MAX_MIP_VERSION; ++v) {
+               versions[v] = true;
+       }
+
+       /*
+        * Go over each (soon-to-be) component's range set of support MIP
+        * versions.
+        */
+       for (range_set_i = 0; range_set_i < supported_ranges->len; ++range_set_i) {
+               const struct bt_integer_range_set *range_set =
+                       supported_ranges->pdata[range_set_i];
+               uint64_t i;
+
+               /*
+                * For each existing MIP version, clear the flag if that
+                * component would not support it.
+                */
+               for (i = 0; i <= MAX_MIP_VERSION; ++i) {
+                       if (!unsigned_integer_range_set_contains(range_set, i)) {
+                               versions[i] = false;
+                       }
+               }
+       }
+
+       /* Find the greatest MIP version with the flag still set. */
+       for (v = MAX_MIP_VERSION; v >= 0; --v) {
+               if (versions[v]) {
+                       *operative_mip_version = v;
+                       status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_OK;
+                       goto end;
+               }
+       }
+
+       status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_NO_MATCH;
+end:
+       return status;
+}
+
 enum bt_get_greatest_operative_mip_version_status
 bt_get_greatest_operative_mip_version(
                const struct bt_component_descriptor_set *comp_descr_set,
                enum bt_logging_level log_level,
                uint64_t *operative_mip_version)
 {
-       int status = BT_FUNC_STATUS_OK;
+       int status;
+       GPtrArray *supported_ranges;
+       unsigned int comp_count =
+               comp_descr_set->sources->len +
+               comp_descr_set->filters->len +
+               comp_descr_set->sinks->len;
 
        BT_ASSERT_PRE_NO_ERROR();
        BT_ASSERT_PRE_COMP_DESCR_SET_NON_NULL(comp_descr_set);
@@ -190,35 +281,52 @@ bt_get_greatest_operative_mip_version(
                operative_mip_version,
                "Operative MIP version (output)");
        BT_ASSERT_PRE("component-descriptor-set-is-not-empty",
-               comp_descr_set->sources->len +
-               comp_descr_set->filters->len +
-               comp_descr_set->sinks->len > 0,
+               comp_count > 0,
                "Component descriptor set is empty: addr=%p", comp_descr_set);
-       status = validate_operative_mip_version_in_array(
-               comp_descr_set->sources, log_level);
+
+       supported_ranges = g_ptr_array_new_with_free_func(
+               (void *) bt_integer_range_set_unsigned_put_ref);
+       if (!supported_ranges) {
+               BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN("Get greatest MIP",
+                       "Failed to allocate one GPtrArray");
+               status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_MEMORY_ERROR;
+               goto end;
+       }
+
+       status = get_supported_mip_version_ranges(
+               comp_descr_set->sources, supported_ranges, log_level);
        if (status) {
                goto end;
        }
 
-       status = validate_operative_mip_version_in_array(
-               comp_descr_set->filters, log_level);
+       status = get_supported_mip_version_ranges(
+               comp_descr_set->filters, supported_ranges, log_level);
        if (status) {
                goto end;
        }
 
-       status = validate_operative_mip_version_in_array(
-               comp_descr_set->sinks, log_level);
+       status = get_supported_mip_version_ranges(
+               comp_descr_set->sinks, supported_ranges, log_level);
        if (status) {
                goto end;
        }
 
-       *operative_mip_version = 0;
+       status = find_greatest_compatible_mip_version(
+               supported_ranges, operative_mip_version);
+       if (status == BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_OK) {
+               BT_LIB_LOGD("Found a compatible MIP version: version=%d",
+                       *operative_mip_version);
+       } else {
+               BT_LIB_LOGD("Failed to find a compatible MIP version: status=%s",
+                       bt_common_func_status_string(status));
+       }
 
 end:
+       g_ptr_array_free(supported_ranges, TRUE);
        return status;
 }
 
 uint64_t bt_get_maximal_mip_version(void)
 {
-       return 1;
+       return MAX_MIP_VERSION;
 }
index 1b44a9ccbb9711fa0d624f05ddde4bd30ca3a23d..0ebc7cc8fdcc276fe811d2ea0b97873b2489eaac 100644 (file)
@@ -83,6 +83,7 @@ TESTS_LIB = \
        lib/test_bt_uuid \
        lib/test_bt_values \
        lib/test_graph_topo \
+       lib/test_mip \
        lib/test_remove_destruction_listener_in_destruction_listener \
        lib/test_simple_sink \
        lib/test_trace_ir_ref
index c1b68d7ffeb2c978ee3496b0fce678b20da9a87a..25cb46abdb0c7ae961e0bb40e7af184b1c718ec1 100644 (file)
@@ -29,10 +29,15 @@ test_remove_destruction_listener_in_destruction_listener_LDADD = \
        $(COMMON_TEST_LDADD) \
        $(top_builddir)/src/lib/libbabeltrace2.la
 
+test_mip_LDADD = \
+       $(COMMON_TEST_LDADD) \
+       $(top_builddir)/src/lib/libbabeltrace2.la
+
 noinst_PROGRAMS = \
        test_bt_uuid \
        test_bt_values \
        test_graph_topo \
+       test_mip \
        test_remove_destruction_listener_in_destruction_listener \
        test_simple_sink \
        test_trace_ir_ref
@@ -44,6 +49,7 @@ test_trace_ir_ref_SOURCES = test_trace_ir_ref.c
 test_graph_topo_SOURCES = test_graph_topo.c
 test_remove_destruction_listener_in_destruction_listener_SOURCES = \
        test_remove_destruction_listener_in_destruction_listener.c
+test_mip_SOURCES = test_mip.c
 
 if !ENABLE_BUILT_IN_PLUGINS
 noinst_PROGRAMS += plugin
diff --git a/tests/lib/test_mip.c b/tests/lib/test_mip.c
new file mode 100644 (file)
index 0000000..0fecdab
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2022 EfficiOS, Inc.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "common/assert.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <glib.h>
+
+#include "tap/tap.h"
+
+#define NR_TESTS 13
+
+static
+bt_component_class_sink_consume_method_status dummy_consume(
+               bt_self_component_sink *self_component)
+{
+       return BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
+}
+
+static
+bt_component_class *create_cls(const char *name,
+               bt_component_class_sink_get_supported_mip_versions_method get_supported_method)
+{
+       bt_component_class_sink *sink;
+       bt_component_class_set_method_status set_method_status;
+
+       sink = bt_component_class_sink_create(name, dummy_consume);
+       BT_ASSERT(sink);
+
+       set_method_status =
+               bt_component_class_sink_set_get_supported_mip_versions_method(
+                       sink, get_supported_method);
+       BT_ASSERT(set_method_status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+
+       return bt_component_class_sink_as_component_class(sink);
+}
+
+static
+bt_component_class_get_supported_mip_versions_method_status
+get_supported_contains_non_existent(bt_self_component_class_sink *source_component_class,
+               const bt_value *params, void *initialize_method_data,
+               bt_logging_level logging_level,
+               bt_integer_range_set_unsigned *supported_versions)
+{
+       bt_integer_range_set_unsigned_add_range(supported_versions,
+               0, 0xfffffffffff);
+       return BT_COMPONENT_CLASS_GET_SUPPORTED_MIP_VERSIONS_METHOD_STATUS_OK;
+}
+
+static
+bt_component_class_get_supported_mip_versions_method_status
+get_supported_only_non_existent(bt_self_component_class_sink *source_component_class,
+               const bt_value *params, void *initialize_method_data,
+               bt_logging_level logging_level,
+               bt_integer_range_set_unsigned *supported_versions)
+{
+       bt_integer_range_set_unsigned_add_range(supported_versions,
+               0xffffffffff0, 0xfffffffffff);
+       return BT_COMPONENT_CLASS_GET_SUPPORTED_MIP_VERSIONS_METHOD_STATUS_OK;
+}
+
+static
+bt_component_class_get_supported_mip_versions_method_status
+get_supported_00(bt_self_component_class_sink *source_component_class,
+               const bt_value *params, void *initialize_method_data,
+               bt_logging_level logging_level,
+               bt_integer_range_set_unsigned *supported_versions)
+{
+       bt_integer_range_set_unsigned_add_range(supported_versions,
+               0, 0);
+       return BT_COMPONENT_CLASS_GET_SUPPORTED_MIP_VERSIONS_METHOD_STATUS_OK;
+}
+
+static
+bt_component_class_get_supported_mip_versions_method_status
+get_supported_01(bt_self_component_class_sink *source_component_class,
+               const bt_value *params, void *initialize_method_data,
+               bt_logging_level logging_level,
+               bt_integer_range_set_unsigned *supported_versions)
+{
+       bt_integer_range_set_unsigned_add_range(supported_versions,
+               0, 1);
+       return BT_COMPONENT_CLASS_GET_SUPPORTED_MIP_VERSIONS_METHOD_STATUS_OK;
+}
+
+
+static
+bt_component_class_get_supported_mip_versions_method_status
+get_supported_11(bt_self_component_class_sink *source_component_class,
+               const bt_value *params, void *initialize_method_data,
+               bt_logging_level logging_level,
+               bt_integer_range_set_unsigned *supported_versions)
+{
+       bt_integer_range_set_unsigned_add_range(supported_versions,
+               1, 1);
+       return BT_COMPONENT_CLASS_GET_SUPPORTED_MIP_VERSIONS_METHOD_STATUS_OK;
+}
+
+static
+bt_component_class_get_supported_mip_versions_method_status
+get_supported_error(bt_self_component_class_sink *source_component_class,
+               const bt_value *params, void *initialize_method_data,
+               bt_logging_level logging_level,
+               bt_integer_range_set_unsigned *supported_versions)
+{
+       return BT_COMPONENT_CLASS_GET_SUPPORTED_MIP_VERSIONS_METHOD_STATUS_ERROR;
+}
+
+static
+void add_descr(bt_component_descriptor_set *descrs, bt_component_class *cls)
+{
+       bt_component_descriptor_set_add_descriptor_status status =
+               bt_component_descriptor_set_add_descriptor(descrs, cls, NULL);
+       BT_ASSERT(status == BT_COMPONENT_DESCRIPTOR_SET_ADD_DESCRIPTOR_STATUS_OK);
+}
+
+static
+void test_common(
+               bt_component_class_sink_get_supported_mip_versions_method get_supported_a,
+               bt_component_class_sink_get_supported_mip_versions_method get_supported_b,
+               bt_get_greatest_operative_mip_version_status expected_status,
+               uint64_t expected_mip_version)
+{
+       bt_component_descriptor_set *descrs;
+       uint64_t mip_version;
+       bt_get_greatest_operative_mip_version_status status;
+       bt_component_class *cls_a = create_cls("cls_a", get_supported_a);
+       bt_component_class *cls_b = create_cls("cls_b", get_supported_b);
+
+       descrs = bt_component_descriptor_set_create();
+       BT_ASSERT(descrs);
+
+       add_descr(descrs, cls_a);
+       add_descr(descrs, cls_b);
+
+       status = bt_get_greatest_operative_mip_version(descrs,
+               BT_LOGGING_LEVEL_INFO, &mip_version);
+       ok(status == expected_status, "status is as expected");
+
+       if (expected_status == BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_OK) {
+               ok(mip_version == expected_mip_version, "MIP version is as expected");
+       }
+
+       bt_component_class_put_ref(cls_a);
+       bt_component_class_put_ref(cls_b);
+       bt_component_descriptor_set_put_ref(descrs);
+}
+
+static
+void test_ok(bt_component_class_sink_get_supported_mip_versions_method get_supported_a,
+               bt_component_class_sink_get_supported_mip_versions_method get_supported_b,
+               uint64_t expected_mip_version)
+{
+       test_common(get_supported_a, get_supported_b,
+               BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_OK,
+               expected_mip_version);
+}
+
+static
+void test_no_match(bt_component_class_sink_get_supported_mip_versions_method get_supported_a,
+               bt_component_class_sink_get_supported_mip_versions_method get_supported_b)
+{
+       test_common(get_supported_a, get_supported_b,
+               BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_NO_MATCH, 0);
+}
+
+static
+void test_error(bt_component_class_sink_get_supported_mip_versions_method get_supported_a,
+               bt_component_class_sink_get_supported_mip_versions_method get_supported_b)
+{
+       test_common(get_supported_a, get_supported_b,
+               BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR, 0);
+}
+
+int main(int argc, char **argv)
+{
+       plan_tests(NR_TESTS);
+
+       test_no_match(get_supported_00, get_supported_only_non_existent);
+       test_no_match(get_supported_00, get_supported_11);
+
+       test_ok(get_supported_00, get_supported_contains_non_existent, 0);
+       test_ok(get_supported_00, get_supported_00, 0);
+       test_ok(get_supported_00, get_supported_01, 0);
+       test_ok(get_supported_01, get_supported_01, 1);
+       test_ok(get_supported_01, get_supported_11, 1);
+
+       test_error(get_supported_01, get_supported_error);
+
+       return exit_status();
+}
This page took 0.080513 seconds and 5 git commands to generate.