diff --git a/src/bindings/c/include/openvino/c/ov_property.h b/src/bindings/c/include/openvino/c/ov_property.h index 1b8a580c42a..0f99d2870f6 100644 --- a/src/bindings/c/include/openvino/c/ov_property.h +++ b/src/bindings/c/include/openvino/c/ov_property.h @@ -206,3 +206,17 @@ ov_property_key_device_priorities; */ OPENVINO_C_VAR(const char*) ov_property_key_hint_execution_mode; + +/** + * @brief Read-write property to set whether force terminate tbb when ov core destruction + * @ingroup ov_property_c_api + */ +OPENVINO_C_VAR(const char*) +ov_property_key_force_tbb_terminate; + +/** + * @brief Read-write property to configure `mmap()` use for model read + * @ingroup ov_property_c_api + */ +OPENVINO_C_VAR(const char*) +ov_property_key_enable_mmap; diff --git a/src/bindings/c/src/ov_property.cpp b/src/bindings/c/src/ov_property.cpp index a7ea7697856..78b3bfe4576 100644 --- a/src/bindings/c/src/ov_property.cpp +++ b/src/bindings/c/src/ov_property.cpp @@ -33,3 +33,5 @@ const char* ov_property_key_log_level = "LOG_LEVEL"; const char* ov_property_key_enable_profiling = "PERF_COUNT"; const char* ov_property_key_device_priorities = "MULTI_DEVICE_PRIORITIES"; const char* ov_property_key_hint_execution_mode = "EXECUTION_MODE_HINT"; +const char* ov_property_key_force_tbb_terminate = "FORCE_TBB_TERMINATE"; +const char* ov_property_key_enable_mmap = "ENABLE_MMAP"; diff --git a/src/bindings/c/tests/ov_core_test.cpp b/src/bindings/c/tests/ov_core_test.cpp index 1a4c7045f92..621f35dcf96 100644 --- a/src/bindings/c/tests/ov_core_test.cpp +++ b/src/bindings/c/tests/ov_core_test.cpp @@ -312,55 +312,38 @@ TEST_P(ov_core_test, ov_core_set_and_get_property_enum) { OV_EXPECT_OK(ov_core_create(&core)); EXPECT_NE(nullptr, core); - const char* key = ov_property_key_hint_performance_mode; - const char* affinity = "LATENCY"; - OV_EXPECT_OK(ov_core_set_property(core, device_name.c_str(), key, affinity)); - char* ret = nullptr; - OV_EXPECT_OK(ov_core_get_property(core, device_name.c_str(), key, &ret)); - EXPECT_STREQ(affinity, ret); - ov_free(ret); + std::map properties = {{ov_property_key_hint_performance_mode, "LATENCY"}, + {ov_property_key_hint_scheduling_core_type, "PCORE_ONLY"}, + {ov_property_key_hint_enable_hyper_threading, "YES"}, + {ov_property_key_enable_profiling, "YES"}}; - const char* key_pin = ov_property_key_hint_enable_cpu_pinning; - const char* val_pin = "YES"; - OV_EXPECT_OK(ov_core_set_property(core, device_name.c_str(), key_pin, val_pin)); - ret = nullptr; - OV_EXPECT_OK(ov_core_get_property(core, device_name.c_str(), key_pin, &ret)); - EXPECT_STREQ(val_pin, ret); - ov_free(ret); - - const char* key_type = ov_property_key_hint_scheduling_core_type; - const char* val_type = "PCORE_ONLY"; - OV_EXPECT_OK(ov_core_set_property(core, device_name.c_str(), key_type, val_type)); - ret = nullptr; - OV_EXPECT_OK(ov_core_get_property(core, device_name.c_str(), key_type, &ret)); - EXPECT_STREQ(val_type, ret); - ov_free(ret); - - const char* key_ht = ov_property_key_hint_enable_hyper_threading; - const char* val_ht = "YES"; - OV_EXPECT_OK(ov_core_set_property(core, device_name.c_str(), key_ht, val_ht)); - ret = nullptr; - OV_EXPECT_OK(ov_core_get_property(core, device_name.c_str(), key_ht, &ret)); - EXPECT_STREQ(val_ht, ret); - ov_free(ret); + for (const auto& property : properties) { + OV_EXPECT_OK(ov_core_set_property(core, device_name.c_str(), property.first, property.second)); + char* ret = nullptr; + OV_EXPECT_OK(ov_core_get_property(core, device_name.c_str(), property.first, &ret)); + EXPECT_STREQ(property.second, ret); + ov_free(ret); + } ov_core_free(core); } -TEST_P(ov_core_test, ov_core_set_and_get_property_bool) { - auto device_name = GetParam(); +TEST_F(ov_core_test, ov_core_set_and_get_property_no_device) { ov_core_t* core = nullptr; OV_EXPECT_OK(ov_core_create(&core)); EXPECT_NE(nullptr, core); - const char* key = ov_property_key_enable_profiling; - const char* enable = "YES"; - OV_EXPECT_OK(ov_core_set_property(core, device_name.c_str(), key, enable)); + std::map properties = {{ov_property_key_force_tbb_terminate, "YES"}, + {ov_property_key_enable_mmap, "NO"}}; + + for (const auto& property : properties) { + OV_EXPECT_OK(ov_core_set_property(core, "", property.first, property.second)); + char* ret = nullptr; + OV_EXPECT_OK(ov_core_get_property(core, "", property.first, &ret)); + EXPECT_STREQ(property.second, ret); + ov_free(ret); + } - char* ret = nullptr; - OV_EXPECT_OK(ov_core_get_property(core, device_name.c_str(), key, &ret)); - EXPECT_STREQ(enable, ret); - ov_free(ret); ov_core_free(core); } diff --git a/src/bindings/python/src/pyopenvino/core/properties/properties.cpp b/src/bindings/python/src/pyopenvino/core/properties/properties.cpp index 01471f27218..96149c7df6d 100644 --- a/src/bindings/python/src/pyopenvino/core/properties/properties.cpp +++ b/src/bindings/python/src/pyopenvino/core/properties/properties.cpp @@ -30,6 +30,7 @@ void regmodule_properties(py::module m) { wrap_property_RW(m_properties, ov::compilation_num_threads, "compilation_num_threads"); wrap_property_RW(m_properties, ov::affinity, "affinity"); wrap_property_RW(m_properties, ov::force_tbb_terminate, "force_tbb_terminate"); + wrap_property_RW(m_properties, ov::enable_mmap, "enable_mmap"); wrap_property_RO(m_properties, ov::supported_properties, "supported_properties"); wrap_property_RO(m_properties, ov::available_devices, "available_devices"); diff --git a/src/bindings/python/tests/test_runtime/test_properties.py b/src/bindings/python/tests/test_runtime/test_properties.py index ea7dd3ba6db..f21a204ae8d 100644 --- a/src/bindings/python/tests/test_runtime/test_properties.py +++ b/src/bindings/python/tests/test_runtime/test_properties.py @@ -213,7 +213,8 @@ def test_properties_ro(ov_property_ro, expected_value): "AFFINITY", ((properties.Affinity.NONE, properties.Affinity.NONE),), ), - (properties.force_tbb_terminate, "FORCE_TBB_TERMINATE", ((True, True),)), + (properties.force_tbb_terminate, "FORCE_TBB_TERMINATE", ((True, True), (False, False))), + (properties.enable_mmap, "ENABLE_MMAP", ((True, True), (False, False))), (properties.hint.inference_precision, "INFERENCE_PRECISION_HINT", ((Type.f32, Type.f32),)), ( properties.hint.model_priority, diff --git a/src/frontends/ir/src/frontend.cpp b/src/frontends/ir/src/frontend.cpp index 4dcbb931e6d..0215eee96b0 100644 --- a/src/frontends/ir/src/frontend.cpp +++ b/src/frontends/ir/src/frontend.cpp @@ -183,8 +183,7 @@ InputModel::Ptr FrontEnd::load_impl(const std::vector& variants) const weights = variant.as>(); } } - bool use_map_allocator = - variants[variants.size() - 1].is() ? variants[variants.size() - 1].as() : false; + bool enable_mmap = variants[variants.size() - 1].is() ? variants[variants.size() - 1].as() : false; // Find weights if only path to xml was provided if (weights_path.empty()) { @@ -202,7 +201,7 @@ InputModel::Ptr FrontEnd::load_impl(const std::vector& variants) const } } if (!weights_path.empty()) { - if (use_map_allocator) + if (enable_mmap) weights = ov::load_mmap_object(weights_path); else { std::ifstream bin_stream; diff --git a/src/frontends/ir/tests/frontend_test_basic.cpp b/src/frontends/ir/tests/frontend_test_basic.cpp index 78d0099bed1..29f412e9b21 100644 --- a/src/frontends/ir/tests/frontend_test_basic.cpp +++ b/src/frontends/ir/tests/frontend_test_basic.cpp @@ -16,6 +16,15 @@ protected: } }; +class IRFrontendMMapTests : public ::testing::TestWithParam, public IRFrontendTestsImpl { +protected: + void SetUp() override {} + + void TearDown() override { + RemoveTemporalFiles(); + } +}; + TEST_F(IRFrontendTests, elementary_model_reading_v11) { std::string testModelV11 = R"V0G0N( @@ -241,7 +250,7 @@ TEST_F(IRFrontendTests, model_with_missing_weights) { ASSERT_THROW(core.read_model(testModelV11, ov::Tensor()), ov::Exception); } -TEST_F(IRFrontendTests, model_with_weights_reading_from_disk) { +TEST_P(IRFrontendMMapTests, model_with_weights_reading_from_disk) { std::string xmlModel = R"V0G0N( @@ -316,7 +325,9 @@ TEST_F(IRFrontendTests, model_with_weights_reading_from_disk) { std::shared_ptr model; - ASSERT_NO_THROW(model = core.read_model(xmlFileName, binFileName)); + ov::Core new_core; + new_core.set_property(ov::enable_mmap(GetParam())); + ASSERT_NO_THROW(model = new_core.read_model(xmlFileName, binFileName)); ASSERT_TRUE(!!model); std::shared_ptr modelRef; @@ -343,6 +354,8 @@ TEST_F(IRFrontendTests, model_with_weights_reading_from_disk) { EXPECT_TRUE(res.valid) << res.message; } +INSTANTIATE_TEST_SUITE_P(EnableMMapPropery, IRFrontendMMapTests, ::testing::Bool()); + TEST_F(IRFrontendTests, model_without_weights_reading_from_disk) { std::string xmlModel = R"V0G0N( diff --git a/src/inference/include/openvino/runtime/properties.hpp b/src/inference/include/openvino/runtime/properties.hpp index 1dbf47db03e..b2b81b51c24 100644 --- a/src/inference/include/openvino/runtime/properties.hpp +++ b/src/inference/include/openvino/runtime/properties.hpp @@ -678,6 +678,17 @@ static constexpr Property, */ static constexpr Property force_tbb_terminate{"FORCE_TBB_TERMINATE"}; +/** + * @brief Read-write property to configure `mmap()` use for model read. Enabled by default. + * For the moment only IR Frontend supports the property. + * + * value type: boolean + * - True enable `mmap()` use and map model + * - False disable `mmap()` use and read model + * @ingroup ov_runtime_cpp_prop_api + */ +static constexpr Property enable_mmap{"ENABLE_MMAP"}; + /** * @brief Namespace with device properties */ diff --git a/src/inference/src/dev/core_impl.cpp b/src/inference/src/dev/core_impl.cpp index 0be7703087b..1f1a88c39e4 100644 --- a/src/inference/src/dev/core_impl.cpp +++ b/src/inference/src/dev/core_impl.cpp @@ -924,6 +924,9 @@ ov::Any ov::CoreImpl::get_property_for_core(const std::string& name) const { } else if (name == ov::hint::allow_auto_batching.name()) { const auto flag = coreConfig.get_allow_auto_batch(); return decltype(ov::hint::allow_auto_batching)::value_type(flag); + } else if (name == ov::enable_mmap.name()) { + const auto flag = coreConfig.get_enable_mmap(); + return decltype(ov::enable_mmap)::value_type(flag); } OPENVINO_THROW("Exception is thrown while trying to call get_property with unsupported property: '", name, "'"); @@ -1298,6 +1301,13 @@ void ov::CoreImpl::CoreConfig::set_and_update(ov::AnyMap& config) { _flag_allow_auto_batching = flag; config.erase(it); } + + it = config.find(ov::enable_mmap.name()); + if (it != config.end()) { + auto flag = it->second.as(); + _flag_enable_mmap = flag; + config.erase(it); + } } void ov::CoreImpl::CoreConfig::set_cache_dir_for_device(const std::string& dir, const std::string& name) { @@ -1314,6 +1324,10 @@ bool ov::CoreImpl::CoreConfig::get_allow_auto_batch() const { return _flag_allow_auto_batching; } +bool ov::CoreImpl::CoreConfig::get_enable_mmap() const { + return _flag_enable_mmap; +} + // Creating thread-safe copy of config including shared_ptr to ICacheManager // Passing empty or not-existing name will return global cache config ov::CoreImpl::CoreConfig::CacheConfig ov::CoreImpl::CoreConfig::get_cache_config_for_device( diff --git a/src/inference/src/dev/core_impl.hpp b/src/inference/src/dev/core_impl.hpp index 179b59cc671..4f8ab8e38dd 100644 --- a/src/inference/src/dev/core_impl.hpp +++ b/src/inference/src/dev/core_impl.hpp @@ -85,6 +85,8 @@ private: bool get_allow_auto_batch() const; + bool get_enable_mmap() const; + // Creating thread-safe copy of config including shared_ptr to ICacheManager // Passing empty or not-existing name will return global cache config CacheConfig get_cache_config_for_device(const ov::Plugin& plugin, ov::AnyMap& parsedConfig) const; @@ -94,6 +96,7 @@ private: CacheConfig _cacheConfig; std::map _cacheConfigPerDevice; bool _flag_allow_auto_batching = true; + bool _flag_enable_mmap = true; }; struct CacheContent { diff --git a/src/inference/src/dev/core_impl_ie.cpp b/src/inference/src/dev/core_impl_ie.cpp index 12641651797..1103fb274d0 100644 --- a/src/inference/src/dev/core_impl_ie.cpp +++ b/src/inference/src/dev/core_impl_ie.cpp @@ -49,7 +49,12 @@ InferenceEngine::RemoteContext::Ptr ov::CoreImpl::GetDefaultContext(const std::s InferenceEngine::CNNNetwork ov::CoreImpl::ReadNetwork(const std::string& modelPath, const std::string& binPath) const { OV_ITT_SCOPE(FIRST_INFERENCE, ov::itt::domains::IE_RT, "CoreImpl::ReadNetwork from file"); - return InferenceEngine::details::ReadNetwork(modelPath, binPath, extensions, ov_extensions, is_new_api()); + return InferenceEngine::details::ReadNetwork(modelPath, + binPath, + extensions, + ov_extensions, + is_new_api(), + coreConfig.get_enable_mmap()); } InferenceEngine::CNNNetwork ov::CoreImpl::ReadNetwork(const std::string& model, diff --git a/src/inference/src/ie_network_reader.cpp b/src/inference/src/ie_network_reader.cpp index 3a219f74382..09b39ccaf0d 100644 --- a/src/inference/src/ie_network_reader.cpp +++ b/src/inference/src/ie_network_reader.cpp @@ -418,7 +418,8 @@ CNNNetwork details::ReadNetwork(const std::string& modelPath, const std::string& binPath, const std::vector& exts, const std::vector& ov_exts, - bool newAPI) { + bool newAPI, + bool enable_mmap) { #ifdef ENABLE_IR_V7_READER // IR v7 obsolete code { @@ -457,7 +458,7 @@ CNNNetwork details::ReadNetwork(const std::string& modelPath, #endif params.emplace_back(weights_path); } - params.emplace_back(/*use_ir_frontend_map_allocator=*/true); + params.emplace_back(enable_mmap); FE = manager.load_by_model(params); if (FE) { diff --git a/src/inference/src/ie_network_reader.hpp b/src/inference/src/ie_network_reader.hpp index 9b2aec6a4a2..bdf3c5e7d8c 100644 --- a/src/inference/src/ie_network_reader.hpp +++ b/src/inference/src/ie_network_reader.hpp @@ -22,13 +22,15 @@ namespace details { * @param exts vector with extensions * @param ov_exts vector with OpenVINO extensions * @param newAPI Whether this function is called from OpenVINO 2.0 API + * @param enable_mmap boolean to enable/disable `mmap` use in Frontend * @return CNNNetwork */ CNNNetwork ReadNetwork(const std::string& modelPath, const std::string& binPath, const std::vector& exts, const std::vector& ov_exts, - bool newAPI); + bool newAPI, + bool enable_mmap); /** * @brief Reads IR xml and bin (with the same name) files * @param model string with IR diff --git a/src/tests/functional/plugin/shared/include/behavior/ov_plugin/core_integration.hpp b/src/tests/functional/plugin/shared/include/behavior/ov_plugin/core_integration.hpp index cb63a7929a2..ac89c46dd38 100644 --- a/src/tests/functional/plugin/shared/include/behavior/ov_plugin/core_integration.hpp +++ b/src/tests/functional/plugin/shared/include/behavior/ov_plugin/core_integration.hpp @@ -689,10 +689,22 @@ TEST(OVClassBasicTest, SetTBBForceTerminatePropertyCoreNoThrow) { bool value = true; OV_ASSERT_NO_THROW(ie.set_property(ov::force_tbb_terminate(false))); OV_ASSERT_NO_THROW(value = ie.get_property(ov::force_tbb_terminate.name()).as()); - EXPECT_EQ(value, false); + EXPECT_FALSE(value); OV_ASSERT_NO_THROW(ie.set_property(ov::force_tbb_terminate(true))); OV_ASSERT_NO_THROW(value = ie.get_property(ov::force_tbb_terminate.name()).as()); - EXPECT_EQ(value, true); + EXPECT_TRUE(value); +} + +TEST(OVClassBasicTest, SetEnableMmapPropertyCoreNoThrow) { + ov::Core ie; + + bool value = true; + OV_ASSERT_NO_THROW(ie.set_property(ov::enable_mmap(false))); + OV_ASSERT_NO_THROW(value = ie.get_property(ov::enable_mmap.name()).as()); + EXPECT_FALSE(value); + OV_ASSERT_NO_THROW(ie.set_property(ov::enable_mmap(true))); + OV_ASSERT_NO_THROW(value = ie.get_property(ov::enable_mmap.name()).as()); + EXPECT_TRUE(value); } TEST(OVClassBasicTest, GetUnsupportedPropertyCoreThrow) { diff --git a/src/tests/functional/plugin/shared/src/behavior/ov_plugin/properties_tests.cpp b/src/tests/functional/plugin/shared/src/behavior/ov_plugin/properties_tests.cpp index c8fc23815f2..2bf10e59174 100644 --- a/src/tests/functional/plugin/shared/src/behavior/ov_plugin/properties_tests.cpp +++ b/src/tests/functional/plugin/shared/src/behavior/ov_plugin/properties_tests.cpp @@ -338,6 +338,9 @@ std::vector OVPropertiesTestsWithComplieModelProps::getPropertiesVal res.push_back({{ov::PropertyName(ov::force_tbb_terminate.name(), ov::force_tbb_terminate.mutability), true}}); res.push_back({{ov::PropertyName(ov::force_tbb_terminate.name(), ov::force_tbb_terminate.mutability), false}}); + res.push_back({{ov::PropertyName(ov::enable_mmap.name(), ov::enable_mmap.mutability), true}}); + res.push_back({{ov::PropertyName(ov::enable_mmap.name(), ov::enable_mmap.mutability), false}}); + ov::streams::Num nums[] = {ov::streams::AUTO, ov::streams::NUMA}; for (auto &num : nums) { res.push_back({{ov::PropertyName(ov::streams::num.name(), ov::streams::num.mutability), num}});