diff --git a/resource/policies/base/test/CMakeLists.txt b/resource/policies/base/test/CMakeLists.txt index 4f19c04cb..bf3661bf0 100644 --- a/resource/policies/base/test/CMakeLists.txt +++ b/resource/policies/base/test/CMakeLists.txt @@ -1,3 +1,9 @@ +add_executable(matcher_policy_factory_test + ${CMAKE_CURRENT_SOURCE_DIR}/matcher_policy_factory_test02.cpp + ) +target_link_libraries(matcher_policy_factory_test PRIVATE libtap resource) +add_sanitizers(matcher_policy_factory_test) +flux_add_test(NAME matcher_policy_factory_test COMMAND matcher_policy_factory_test) add_executable(matcher_util_api_test ${CMAKE_CURRENT_SOURCE_DIR}/matcher_util_api_test01.cpp ) diff --git a/resource/policies/base/test/matcher_policy_factory_test02.cpp b/resource/policies/base/test/matcher_policy_factory_test02.cpp new file mode 100644 index 000000000..42f3c7552 --- /dev/null +++ b/resource/policies/base/test/matcher_policy_factory_test02.cpp @@ -0,0 +1,61 @@ +/*****************************************************************************\ + * Copyright 2024 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, LICENSE) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\*****************************************************************************/ + +/* + * Test for the dfu_match_policy class(es). Compares shared pointers + * expected values to string inputs to these classes. Strings can be + * specified in config for custom policies, or some are provided. + */ + +extern "C" { +#if HAVE_CONFIG_H +#include <config.h> +#endif +} + +#include <string> +#include "resource/policies/dfu_match_policy_factory.hpp" +#include "src/common/libtap/tap.h" + +using namespace Flux; +using namespace Flux::resource_model; + +int test_parsers () +{ + std::string policy_opts = policies.find ("first")->second; + bool first = Flux::resource_model::parse_bool_match_options ("high", policy_opts); + ok (first == true, "policy first uses option high"); + + policy_opts = policies.find ("high")->second; + bool fourth = Flux::resource_model::option_exists ("stop_on_k_matches", policy_opts); + ok (fourth == false, "policy high does not have stop_on_k_matches as substring"); + + policy_opts = policies.find ("firstnodex")->second; + bool second = Flux::resource_model::parse_bool_match_options ("node_exclusive", policy_opts); + ok (second == true, "policy first uses option node_centric"); + bool third = Flux::resource_model::option_exists ("stop_on_k_matches", policy_opts); + ok (third == true, "policy firstnodex has stop_on_k_matches as substring"); + int stop = Flux::resource_model::parse_int_match_options ("stop_on_k_matches", policy_opts); + ok (stop == 1, "policy firstnodex stops on first match"); + + return 0; +} + +int main (int argc, char *argv[]) +{ + plan (5); + test_parsers (); + done_testing (); + return 0; +} + +/* + * vi: ts=4 sw=4 expandtab + */ diff --git a/resource/policies/dfu_match_policy_factory.cpp b/resource/policies/dfu_match_policy_factory.cpp index 8e7a4f645..9f1f00f6c 100644 --- a/resource/policies/dfu_match_policy_factory.cpp +++ b/resource/policies/dfu_match_policy_factory.cpp @@ -13,7 +13,7 @@ extern "C" { #include <config.h> #endif } - +#include <iostream> #include <string> #include "resource/policies/dfu_match_policy_factory.hpp" @@ -22,50 +22,98 @@ namespace resource_model { bool known_match_policy (const std::string &policy) { - bool rc = true; - if (policy != FIRST_MATCH && policy != FIRST_NODEX_MATCH && policy != HIGH_ID_FIRST - && policy != LOW_ID_FIRST && policy != LOW_NODE_FIRST && policy != HIGH_NODE_FIRST - && policy != LOW_NODEX_FIRST && policy != HIGH_NODEX_FIRST && policy != LOCALITY_AWARE - && policy != VAR_AWARE) - rc = false; - - return rc; + if (policies.contains (policy)) { + return true; + } + return false; } -std::shared_ptr<dfu_match_cb_t> create_match_cb (const std::string &policy) +bool parse_bool_match_options (const std::string match_option, const std::string policy_options) { - std::shared_ptr<dfu_match_cb_t> matcher = nullptr; + // Return anything from after the = and before space or newline + size_t spot = policy_options.find (match_option, 0); + size_t start_pos = policy_options.find ("=", spot); + size_t end_pos = policy_options.find (" ", spot); + size_t end_str = policy_options.length (); + std::string return_opt; + if ((end_pos == std::string::npos) && (start_pos != std::string::npos)) { + return_opt = policy_options.substr ((start_pos + 1), (end_str - start_pos - 1)); + } else { + return_opt = policy_options.substr ((start_pos + 1), (end_pos - start_pos - 1)); + } + if (return_opt == "true") { + return true; + } + return false; +} + +bool option_exists (const std::string match_option, const std::string policy_options) +{ + size_t found = policy_options.find (match_option, 0); + if (found == std::string::npos) { + return false; + } + return true; +} + +int parse_int_match_options (const std::string match_option, const std::string policy_options) +{ + size_t spot = policy_options.find (match_option, 0); + size_t start_pos = policy_options.find ("=", spot); + size_t end_pos = policy_options.find (" ", spot); + size_t end_str = policy_options.length (); + int return_opt; + if ((end_pos == std::string::npos) && (start_pos != std::string::npos)) { + return_opt = stoi(policy_options.substr ((start_pos + 1), (end_str - start_pos - 1))); + } else { + return_opt = stoi(policy_options.substr ((start_pos + 1), (end_pos - start_pos - 1))); + } + return return_opt; +} - resource_type_t node_rt ("node"); +std::shared_ptr<dfu_match_cb_t> create_match_cb (const std::string &policy_requested) +{ + std::string policy = policies.find (policy_requested)->second; + std::shared_ptr<dfu_match_cb_t> matcher = nullptr; try { - if (policy == FIRST_MATCH || policy == FIRST_NODEX_MATCH) { + if (policy_requested == "locality") { + matcher = std::make_shared<greater_interval_first_t> (); + } + if (policy_requested == "variation") { + matcher = std::make_shared<var_aware_t> (); + } + + if (parse_bool_match_options ("high", policy)) { std::shared_ptr<high_first_t> ptr = std::make_shared<high_first_t> (); - ptr->add_score_factor (node_rt, 1, 10000); - ptr->set_stop_on_k_matches (1); - if (policy == FIRST_NODEX_MATCH) + if (parse_bool_match_options ("node_centric", policy)) { + ptr->add_score_factor (node_rt, 1, 10000); + } + + if (parse_bool_match_options ("node_exclusive", policy)) { ptr->add_exclusive_resource_type (node_rt); + } + + if (option_exists ("stop_on_k_matches", policy)) { + ptr->set_stop_on_k_matches (parse_int_match_options ("stop_on_k_matches", policy)); + } matcher = ptr; - } else if (policy == HIGH_ID_FIRST) { - matcher = std::make_shared<high_first_t> (); - } else if (policy == LOW_ID_FIRST) { - matcher = std::make_shared<low_first_t> (); - } else if (policy == LOW_NODE_FIRST || policy == LOW_NODEX_FIRST) { + + } else if (parse_bool_match_options ("low", policy)) { std::shared_ptr<low_first_t> ptr = std::make_shared<low_first_t> (); - ptr->add_score_factor (node_rt, 1, 10000); - if (policy == LOW_NODEX_FIRST) - ptr->add_exclusive_resource_type (node_rt); - matcher = ptr; - } else if (policy == HIGH_NODE_FIRST || policy == HIGH_NODEX_FIRST) { - std::shared_ptr<high_first_t> ptr = std::make_shared<high_first_t> (); - ptr->add_score_factor (node_rt, 1, 10000); - if (policy == HIGH_NODEX_FIRST) + if (parse_bool_match_options ("node_centric", policy)) { + ptr->add_score_factor (node_rt, 1, 10000); + } + + if (parse_bool_match_options ("node_exclusive", policy)) { ptr->add_exclusive_resource_type (node_rt); + } + + if (option_exists ("stop_on_k_matches", policy)) { + ptr->set_stop_on_k_matches (parse_int_match_options ("stop_on_k_matches", policy)); + } matcher = ptr; - } else if (policy == LOCALITY_AWARE) { - matcher = std::make_shared<greater_interval_first_t> (); - } else if (policy == VAR_AWARE) { - matcher = std::make_shared<var_aware_t> (); } + } catch (std::bad_alloc &e) { errno = ENOMEM; matcher = nullptr; diff --git a/resource/policies/dfu_match_policy_factory.hpp b/resource/policies/dfu_match_policy_factory.hpp index 5fbbed0f8..4f2a52efc 100644 --- a/resource/policies/dfu_match_policy_factory.hpp +++ b/resource/policies/dfu_match_policy_factory.hpp @@ -13,6 +13,7 @@ #include <string> #include <memory> +#include <map> #include "resource/policies/base/dfu_match_cb.hpp" #include "resource/policies/dfu_match_high_id_first.hpp" #include "resource/policies/dfu_match_low_id_first.hpp" @@ -24,19 +25,28 @@ namespace Flux { namespace resource_model { -const std::string FIRST_MATCH = "first"; -const std::string FIRST_NODEX_MATCH = "firstnodex"; -const std::string HIGH_ID_FIRST = "high"; -const std::string LOW_ID_FIRST = "low"; -const std::string LOW_NODE_FIRST = "lonode"; -const std::string HIGH_NODE_FIRST = "hinode"; -const std::string LOW_NODEX_FIRST = "lonodex"; -const std::string HIGH_NODEX_FIRST = "hinodex"; -const std::string LOCALITY_AWARE = "locality"; -const std::string VAR_AWARE = "variation"; - bool known_match_policy (const std::string &policy); +const std::map<std::string, std::string> policies = + {{"first", "name=FIRST_MATCH high=true node_centric=true stop_on_k_matches=1"}, + {"firstnodex", + "name=FIRST_NODEX_MATCH high=true node_centric=true node_exclusive=true stop_on_k_matches=1"}, + {"high", "name=HIGH_ID_FIRST high=true"}, + {"low", "name=LOW_ID_FIRST low=true"}, + {"lonode", "name=LOW_NODE_FIRST low=true node_centric=true"}, + {"hinode", "name=HIGH_NODE_FIRST high=true node_centric=true"}, + {"lonodex", "name=LOW_NODEX_FIRST low=true node_centric=true node_exclusive=true"}, + {"hinodex", "name=HIGH_NODEX_FIRST high=true node_centric=true node_exclusive=true"}, + {"locality", "name=LOCALITY_AWARE"}, + {"variation", "name=VAR_AWARE"}, + {"custom", ""}}; + +bool parse_bool_match_options (const std::string match_option, const std::string policy_options); + +bool option_exists (const std::string match_option, const std::string policy_options); + +int parse_int_match_options (const std::string match_option, const std::string policy_options); + /*! Factory method for creating a matching callback * object, representing a matching policy. */