From 7e64e416b5cf5b592ec3abe79544b0af98341001 Mon Sep 17 00:00:00 2001 From: Xuejun Zhai Date: Sat, 18 May 2024 02:13:56 +0800 Subject: [PATCH] Force default locale for cache model write/read (#24431) ### Details: - Check the value of setlocale for export/import, if different with "C" will set to "C" and record the original value, after export/import done will reset to the original. - *Fix the error caused by pugixml library with The setlocale function installs the specified system locale or its portion as the new C locale. different C may return unexpected results with setlocal()* ### Tickets: - https://github.com/openvinotoolkit/openvino/issues/24370 --------- Signed-off-by: Zhai, Xuejun Co-authored-by: Chen Peter Co-authored-by: River Li --- src/inference/src/cache_manager.hpp | 24 +++++++ src/inference/tests/functional/local_test.cpp | 66 ++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/inference/src/cache_manager.hpp b/src/inference/src/cache_manager.hpp index f0811c601cf0ca..1fe42e8b654479 100644 --- a/src/inference/src/cache_manager.hpp +++ b/src/inference/src/cache_manager.hpp @@ -18,6 +18,25 @@ namespace ov { +/** + * @brief This class limits the locale env to a special value in sub-scope + * + */ +class ScopedLocale { +public: + ScopedLocale(int category, std::string newLocale) : m_category(category) { + m_oldLocale = setlocale(category, nullptr); + setlocale(m_category, newLocale.c_str()); + } + ~ScopedLocale() { + setlocale(m_category, m_oldLocale.c_str()); + } + +private: + int m_category; + std::string m_oldLocale; +}; + /** * @brief This class represents private interface for Cache Manager * @@ -99,11 +118,16 @@ class FileStorageCacheManager final : public ICacheManager { private: void write_cache_entry(const std::string& id, StreamWriter writer) override { + // Fix the bug caused by pugixml, which may return unexpected results if the locale is different from "C". + ScopedLocale plocal_C(LC_ALL, "C"); + std::ofstream stream(getBlobFile(id), std::ios_base::binary | std::ofstream::out); writer(stream); } void read_cache_entry(const std::string& id, StreamReader reader) override { + // Fix the bug caused by pugixml, which may return unexpected results if the locale is different from "C". + ScopedLocale plocal_C(LC_ALL, "C"); auto blobFileName = getBlobFile(id); if (ov::util::file_exists(blobFileName)) { std::ifstream stream(blobFileName, std::ios_base::binary); diff --git a/src/inference/tests/functional/local_test.cpp b/src/inference/tests/functional/local_test.cpp index 6502255fc1e3a5..dafd87dc457370 100644 --- a/src/inference/tests/functional/local_test.cpp +++ b/src/inference/tests/functional/local_test.cpp @@ -4,6 +4,9 @@ #include +#include "common_test_utils/file_utils.hpp" +#include "common_test_utils/ov_tensor_utils.hpp" +#include "common_test_utils/subgraph_builders/split_multi_conv_concat.hpp" #include "openvino/op/roi_align.hpp" #include "openvino/op/util/rnn_cell_base.hpp" #include "openvino/runtime/core.hpp" @@ -285,4 +288,65 @@ TEST_F(LocaleTests, DISABLED_WithUSLocaleCPP) { testBody(); std::locale::global(prev); } -#endif // defined(ENABLE_OV_IR_FRONTEND) + +class LocaleTestsWithCacheDir : public ::testing::Test { + std::string originalLocale; + std::string cache_dir = "test_cache"; + std::shared_ptr model; + +public: +protected: + void SetUp() override { + originalLocale = setlocale(LC_ALL, nullptr); + model = ov::test::utils::make_split_multi_conv_concat(); + } + void TearDown() override { + setlocale(LC_ALL, originalLocale.c_str()); + if (!cache_dir.empty()) { + ov::test::utils::removeDir(cache_dir); + } + } + void testBody() const { + std::map, ov::Tensor> inputs; + for (const auto& input : model->inputs()) { + auto tensor = ov::test::utils::create_and_fill_tensor_normal_distribution(input.get_element_type(), + input.get_shape(), + 0.0f, + 0.2f, + 7235346); + inputs.insert({input, tensor}); + } + + ov::Core core; + ov::AnyMap properties = {ov::hint::inference_precision(ov::element::f32), ov::cache_dir(cache_dir)}; + + auto getOutputBlob = [&]() { + auto compiled_model = core.compile_model(model, "CPU", properties); + auto req = compiled_model.create_infer_request(); + for (const auto& input : inputs) { + req.set_tensor(input.first, input.second); + } + auto output_tensor = ov::Tensor(model->output().get_element_type(), model->output().get_shape()); + req.set_output_tensor(output_tensor); + req.infer(); + return output_tensor; + }; + + auto output_from_model_read = getOutputBlob(); + auto output_from_model_cached = getOutputBlob(); + + ov::test::utils::compare(output_from_model_read, output_from_model_cached); + ov::test::utils::removeFilesWithExt(cache_dir, "blob"); + } +}; + +TEST_F(LocaleTestsWithCacheDir, WithRULocale) { + setlocale(LC_ALL, "ru_RU.UTF-8"); + testBody(); +} + +TEST_F(LocaleTestsWithCacheDir, WithUSLocale) { + setlocale(LC_ALL, "en_US.UTF-8"); + testBody(); +} +#endif // defined(ENABLE_OV_IR_FRONTEND) \ No newline at end of file