diff --git a/src/inference/dev_api/openvino/runtime/plugin_config.hpp b/src/inference/dev_api/openvino/runtime/plugin_config.hpp index 16985d70b2841a..78f8da4fe61ca2 100644 --- a/src/inference/dev_api/openvino/runtime/plugin_config.hpp +++ b/src/inference/dev_api/openvino/runtime/plugin_config.hpp @@ -118,6 +118,9 @@ class OPENVINO_RUNTIME_API PluginConfig { template T get_property(const ov::Property& property) const { + if (is_set_by_user(property)) { + return user_properties.at(property.name()).template as(); + } OPENVINO_ASSERT(m_options_map.find(property.name()) != m_options_map.end(), "Property not found: ", property.name()); return static_cast*>(m_options_map.at(property.name()))->value; } diff --git a/src/inference/src/dev/plugin_config.cpp b/src/inference/src/dev/plugin_config.cpp index c3ac86e05ba04b..c4489cdc1bc69f 100644 --- a/src/inference/src/dev/plugin_config.cpp +++ b/src/inference/src/dev/plugin_config.cpp @@ -76,9 +76,12 @@ void PluginConfig::finalize(std::shared_ptr context, const ov::R } void PluginConfig::apply_debug_options(std::shared_ptr context) { - ov::AnyMap config_properties = read_config_file("config.json", context->get_device_name()); - cleanup_unsupported(config_properties); - set_user_property(config_properties); + if (context) { + ov::AnyMap config_properties = read_config_file("config.json", context->get_device_name()); + cleanup_unsupported(config_properties); + set_user_property(config_properties); + } + ov::AnyMap env_properties = read_env({"OV_"}); set_user_property(env_properties); } diff --git a/src/inference/tests/unit/config_test.cpp b/src/inference/tests/unit/config_test.cpp new file mode 100644 index 00000000000000..db832247dd2bd6 --- /dev/null +++ b/src/inference/tests/unit/config_test.cpp @@ -0,0 +1,202 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/core/any.hpp" +#include "openvino/runtime/plugin_config.hpp" + +#include +#include + +#include "common_test_utils/common_utils.hpp" + +using namespace ::testing; +using namespace ov; + +static constexpr Property unsupported_property{"UNSUPPORTED_PROPERTY"}; +static constexpr Property bool_property{"BOOL_PROPERTY"}; +static constexpr Property int_property{"INT_PROPERTY"}; +static constexpr Property high_level_property{"HIGH_LEVEL_PROPERTY"}; +static constexpr Property low_level_property{"LOW_LEVEL_PROPERTY"}; + + +struct EmptyTestConfig : public ov::PluginConfig { + std::vector get_supported_properties() const { + std::vector supported_properties; + for (const auto& kv : m_options_map) { + supported_properties.push_back(kv.first); + } + return supported_properties; + } +}; + +struct NotEmptyTestConfig : public ov::PluginConfig { + NotEmptyTestConfig() { + m_options_map[bool_property.name()] = &m_bool_property; + m_options_map[int_property.name()] = &m_int_property; + m_options_map[high_level_property.name()] = &m_high_level_property; + m_options_map[low_level_property.name()] = &m_low_level_property; + } + + NotEmptyTestConfig(const NotEmptyTestConfig& other) : NotEmptyTestConfig() { + user_properties = other.user_properties; + for (const auto& kv : other.m_options_map) { + m_options_map.at(kv.first)->set_any(kv.second->get_any()); + } + } + + ConfigOption m_bool_property = ConfigOption(true); + ConfigOption m_int_property = ConfigOption(-1); + ConfigOption m_high_level_property = ConfigOption(""); + ConfigOption m_low_level_property = ConfigOption(""); + + std::vector get_supported_properties() const { + std::vector supported_properties; + for (const auto& kv : m_options_map) { + supported_properties.push_back(kv.first); + } + return supported_properties; + } + + void finalize_impl(std::shared_ptr context) override { + if (!is_set_by_user(low_level_property)) { + m_low_level_property.value = m_high_level_property.value; + } + } + + void apply_rt_info(std::shared_ptr context, const ov::RTMap& rt_info) override { + apply_rt_info_property(high_level_property, rt_info); + } + + using ov::PluginConfig::is_set_by_user; +}; + +TEST(plugin_config, can_create_empty_config) { + ASSERT_NO_THROW( + EmptyTestConfig cfg; + ASSERT_EQ(cfg.get_supported_properties().size(), 0); + ); +} + +TEST(plugin_config, can_create_not_empty_config) { + ASSERT_NO_THROW( + NotEmptyTestConfig cfg; + ASSERT_EQ(cfg.get_supported_properties().size(), 4); + ); +} + +TEST(plugin_config, can_set_get_property) { + NotEmptyTestConfig cfg; + ASSERT_NO_THROW(cfg.get_property(bool_property)); + ASSERT_EQ(cfg.get_property(bool_property), true); + ASSERT_NO_THROW(cfg.set_property(bool_property(false))); + ASSERT_EQ(cfg.get_property(bool_property), false); + + ASSERT_NO_THROW(cfg.set_user_property(bool_property(true))); + ASSERT_EQ(cfg.get_property(bool_property), true); +} + +TEST(plugin_config, throw_for_unsupported_property) { + NotEmptyTestConfig cfg; + ASSERT_ANY_THROW(cfg.get_property(unsupported_property)); + ASSERT_ANY_THROW(cfg.set_property(unsupported_property(10.0f))); + ASSERT_ANY_THROW(cfg.set_user_property(unsupported_property(10.0f))); +} + +TEST(plugin_config, can_direct_access_to_properties) { + NotEmptyTestConfig cfg; + ASSERT_EQ(cfg.m_bool_property.value, cfg.get_property(bool_property)); + ASSERT_NO_THROW(cfg.set_property(bool_property(false))); + ASSERT_EQ(cfg.m_bool_property.value, cfg.get_property(bool_property)); + ASSERT_EQ(cfg.m_bool_property.value, false); + + ASSERT_NO_THROW(cfg.set_user_property(bool_property(true))); + ASSERT_EQ(cfg.m_bool_property.value, false); // user property doesn't impact member value until finalize() is called + + cfg.m_bool_property.value = true; + ASSERT_EQ(cfg.get_property(bool_property), true); +} + +TEST(plugin_config, finalization_updates_member) { + NotEmptyTestConfig cfg; + ASSERT_NO_THROW(cfg.set_user_property(bool_property(false))); + ASSERT_EQ(cfg.m_bool_property.value, true); // user property doesn't impact member value until finalize() is called + + cfg.finalize(nullptr, {}); + + ASSERT_EQ(cfg.m_bool_property.value, false); // now the value has changed +} + +TEST(plugin_config, get_property_before_finalization_returns_user_property_if_set) { + NotEmptyTestConfig cfg; + + ASSERT_EQ(cfg.get_property(bool_property), true); // default value + ASSERT_EQ(cfg.m_bool_property.value, true); // default value + + cfg.m_bool_property.value = false; // update member directly + ASSERT_EQ(cfg.get_property(bool_property), false); // OK, return the class member value as no user property was set + + ASSERT_NO_THROW(cfg.set_user_property(bool_property(true))); + ASSERT_TRUE(cfg.is_set_by_user(bool_property)); + ASSERT_EQ(cfg.get_property(bool_property), true); // now user property value is returned + ASSERT_EQ(cfg.m_bool_property.value, false); // but class member is not updated + + cfg.finalize(nullptr, {}); + ASSERT_EQ(cfg.get_property(bool_property), cfg.m_bool_property.value); // equal after finalization + ASSERT_FALSE(cfg.is_set_by_user(bool_property)); // and user property is cleared +} + +TEST(plugin_config, finalization_updates_dependant_properties) { + NotEmptyTestConfig cfg; + + cfg.set_user_property(high_level_property("value1")); + ASSERT_TRUE(cfg.is_set_by_user(high_level_property)); + ASSERT_FALSE(cfg.is_set_by_user(low_level_property)); + + cfg.finalize(nullptr, {}); + ASSERT_EQ(cfg.m_high_level_property.value, "value1"); + ASSERT_EQ(cfg.m_low_level_property.value, "value1"); + ASSERT_FALSE(cfg.is_set_by_user(high_level_property)); + ASSERT_FALSE(cfg.is_set_by_user(low_level_property)); +} + +TEST(plugin_config, can_set_property_from_rt_info) { + NotEmptyTestConfig cfg; + + RTMap rt_info = { + {high_level_property.name(), "value1"}, + {int_property.name(), 10} // int_property is not applied from rt info + }; + + // default values + ASSERT_EQ(cfg.m_high_level_property.value, ""); + ASSERT_EQ(cfg.m_low_level_property.value, ""); + ASSERT_EQ(cfg.m_int_property.value, -1); + + cfg.finalize(nullptr, rt_info); + + ASSERT_EQ(cfg.m_high_level_property.value, "value1"); + ASSERT_EQ(cfg.m_low_level_property.value, "value1"); // dependant is updated too + ASSERT_EQ(cfg.m_int_property.value, -1); // still default +} + +TEST(plugin_config, can_copy_config) { + NotEmptyTestConfig cfg1; + + cfg1.m_high_level_property.value = "value1"; + cfg1.m_low_level_property.value = "value2"; + cfg1.m_int_property.value = 1; + cfg1.set_user_property(bool_property(false)); + + NotEmptyTestConfig cfg2 = cfg1; + ASSERT_EQ(cfg2.m_high_level_property.value, "value1"); + ASSERT_EQ(cfg2.m_low_level_property.value, "value2"); + ASSERT_EQ(cfg2.m_int_property.value, 1); + ASSERT_EQ(cfg2.get_property(bool_property), false); // ensure user properties are copied too + + // check that cfg1 modification doesn't impact a copy + cfg1.set_property(high_level_property("value3")); + cfg1.m_int_property.value = 3; + ASSERT_EQ(cfg2.m_high_level_property.value, "value1"); + ASSERT_EQ(cfg2.m_int_property.value, 1); +} diff --git a/src/plugins/intel_gpu/include/intel_gpu/runtime/plugin_config.hpp b/src/plugins/intel_gpu/include/intel_gpu/runtime/plugin_config.hpp index 5931a60ffae37a..f18b32cd8b7cbb 100644 --- a/src/plugins/intel_gpu/include/intel_gpu/runtime/plugin_config.hpp +++ b/src/plugins/intel_gpu/include/intel_gpu/runtime/plugin_config.hpp @@ -23,7 +23,7 @@ struct NewExecutionConfig : public ov::PluginConfig { NewExecutionConfig& operator=(const NewExecutionConfig& other); #define OV_CONFIG_OPTION(PropertyNamespace, PropertyVar, ...) \ - ConfigOption PropertyVar = \ + ConfigOption m_ ## PropertyVar = \ ConfigOption(GET_EXCEPT_LAST(__VA_ARGS__)); #include "options_release.inl" diff --git a/src/plugins/intel_gpu/src/runtime/plugin_config.cpp b/src/plugins/intel_gpu/src/runtime/plugin_config.cpp index 330d3ed40c2175..8f4319734d3e9f 100644 --- a/src/plugins/intel_gpu/src/runtime/plugin_config.cpp +++ b/src/plugins/intel_gpu/src/runtime/plugin_config.cpp @@ -14,7 +14,7 @@ namespace intel_gpu { NewExecutionConfig::NewExecutionConfig() : ov::PluginConfig() { #define OV_CONFIG_OPTION(PropertyNamespace, PropertyVar, ...) \ - m_options_map[PropertyNamespace::PropertyVar.name()] = &PropertyVar; + m_options_map[PropertyNamespace::PropertyVar.name()] = & m_ ## PropertyVar; #include "intel_gpu/runtime/options_release.inl" #include "intel_gpu/runtime/options_debug.inl" diff --git a/src/plugins/intel_gpu/tests/unit/module_tests/config_test.cpp b/src/plugins/intel_gpu/tests/unit/module_tests/config_test.cpp index 930128ef53bff6..b14c5b0bf4623d 100644 --- a/src/plugins/intel_gpu/tests/unit/module_tests/config_test.cpp +++ b/src/plugins/intel_gpu/tests/unit/module_tests/config_test.cpp @@ -14,10 +14,11 @@ TEST(config_test, basic) { ov::intel_gpu::NewExecutionConfig cfg; std::cerr << cfg.to_string(); + std::cerr << cfg.get_property("PERFORMANCE_HINT").as(); cfg.set_user_property(ov::hint::execution_mode(ov::hint::ExecutionMode::ACCURACY)); cfg.set_property(ov::hint::inference_precision(ov::element::f32)); - std::cerr << "PROF: " << cfg.enable_profiling.value << std::endl; + std::cerr << "PROF: " << cfg.m_enable_profiling.value << std::endl; std::cerr << cfg.to_string();