From: Simon Marchi Date: Fri, 9 Feb 2024 21:25:24 +0000 (-0500) Subject: graph/mip: make bt_get_greatest_operative_mip_version compute operative MIP version X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=8f83c12b0c24f2e69e2283f4f4e8d2898ce77064;p=babeltrace.git graph/mip: make bt_get_greatest_operative_mip_version compute operative MIP version 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 Reviewed-on: https://review.lttng.org/c/babeltrace/+/7579 Tested-by: jenkins Reviewed-by: Philippe Proulx Reviewed-on: https://review.lttng.org/c/babeltrace/+/7572 --- diff --git a/src/lib/graph/mip.c b/src/lib/graph/mip.c index c74437bb..46670185 100644 --- a/src/lib/graph/mip.c +++ b/src/lib/graph/mip.c @@ -22,6 +22,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) @@ -46,15 +48,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 @@ -63,11 +99,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 = @@ -108,76 +144,126 @@ 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; +} + BT_EXPORT enum bt_get_greatest_operative_mip_version_status bt_get_greatest_operative_mip_version( @@ -185,7 +271,12 @@ bt_get_greatest_operative_mip_version( 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); @@ -193,36 +284,53 @@ 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; } BT_EXPORT uint64_t bt_get_maximal_mip_version(void) { - return 1; + return MAX_MIP_VERSION; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 6136c771..b1953af9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -119,6 +119,7 @@ TESTS_LIB = \ lib/test-bt-values \ lib/test-fields.sh \ lib/test-graph-topo \ + lib/test-mip \ lib/test-remove-destruction-listener-in-destruction-listener \ lib/test-simple-sink \ lib/test-trace-ir-ref diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am index bdba6b80..f58d4f41 100644 --- a/tests/lib/Makefile.am +++ b/tests/lib/Makefile.am @@ -56,11 +56,17 @@ test_remove_destruction_listener_in_destruction_listener_LDADD = \ $(top_builddir)/src/lib/libbabeltrace2.la nodist_EXTRA_test_remove_destruction_listener_in_destruction_listener_SOURCES = dummy.cpp +test_mip_SOURCES = test-mip.c +test_mip_LDADD = \ + $(COMMON_TEST_LDADD) \ + $(top_builddir)/src/lib/libbabeltrace2.la + noinst_PROGRAMS = \ test-bt-uuid \ test-bt-values \ test-graph-topo \ test-fields-bin \ + test-mip \ test-remove-destruction-listener-in-destruction-listener \ test-simple-sink \ test-trace-ir-ref diff --git a/tests/lib/test-mip.c b/tests/lib/test-mip.c new file mode 100644 index 00000000..d6806467 --- /dev/null +++ b/tests/lib/test-mip.c @@ -0,0 +1,208 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2022 EfficiOS, Inc. + */ + +#include +#include "common/assert.h" +#include +#include +#include +#include + +#include "tap/tap.h" + +#define NR_TESTS 13 + +static +bt_component_class_sink_consume_method_status dummy_consume( + bt_self_component_sink *self_component __attribute__((unused))) +{ + 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 __attribute__((unused)), + const bt_value *params __attribute__((unused)), + void *initialize_method_data __attribute__((unused)), + bt_logging_level logging_level __attribute__((unused)), + 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 __attribute__((unused)), + const bt_value *params __attribute__((unused)), + void *initialize_method_data __attribute__((unused)), + bt_logging_level logging_level __attribute__((unused)), + 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 __attribute__((unused)), + const bt_value *params __attribute__((unused)), + void *initialize_method_data __attribute__((unused)), + bt_logging_level logging_level __attribute__((unused)), + 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 __attribute__((unused)), + const bt_value *params __attribute__((unused)), + void *initialize_method_data __attribute__((unused)), + bt_logging_level logging_level __attribute__((unused)), + 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 __attribute__((unused)), + const bt_value *params __attribute__((unused)), + void *initialize_method_data __attribute__((unused)), + bt_logging_level logging_level __attribute__((unused)), + 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 __attribute__((unused)), + const bt_value *params __attribute__((unused)), + void *initialize_method_data __attribute__((unused)), + bt_logging_level logging_level __attribute__((unused)), + bt_integer_range_set_unsigned *supported_versions __attribute__((unused))) +{ + 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(void) +{ + 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(); +}