From 24eeb41c1a6600802dc6fe9cec627a7faaa30347 Mon Sep 17 00:00:00 2001 From: Ting Cao Date: Thu, 14 Jul 2022 14:58:19 +0800 Subject: [PATCH 1/6] Add file mapping for windows platform. --- onnxruntime/core/platform/windows/env.cc | 92 ++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/onnxruntime/core/platform/windows/env.cc b/onnxruntime/core/platform/windows/env.cc index 4358ddc7c3e26..291eebd515d7d 100644 --- a/onnxruntime/core/platform/windows/env.cc +++ b/onnxruntime/core/platform/windows/env.cc @@ -40,6 +40,23 @@ namespace onnxruntime { namespace { +class UnmapFileParam { + public: + void* addr; + size_t len; +}; + +static void UnmapFile(void* param) noexcept { + UnmapFileParam* p = reinterpret_cast(param); + bool ret = UnmapViewOfFile(p->addr); + if (!ret) { + const auto error_code = GetLastError(); + LOGS_DEFAULT(ERROR) << "unmap view of file failed. error code: " << error_code + << " error msg: " << std::system_category().message(error_code); + } + delete p; +} + std::wstring Basename(const std::wstring& path) { auto basename_index = path.find_last_of(L"/\\") + 1; // results in 0 if no separator is found return path.substr(basename_index); @@ -320,8 +337,83 @@ class WindowsEnv : public Env { return Status::OK(); } + /** Status MapFileIntoMemory(_In_z_ const ORTCHAR_T*, FileOffsetType, size_t, MappedMemoryPtr&) const override { return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, "MapFileIntoMemory is not implemented on Windows."); + }*/ + + Status MapFileIntoMemory(_In_z_ const ORTCHAR_T* file_path, + FileOffsetType offset, + size_t length, + MappedMemoryPtr& mapped_memory) const override { + ORT_RETURN_IF_NOT(file_path, "file_path == nullptr"); + ORT_RETURN_IF_NOT(offset >= 0, "offset < 0"); + + if (length == 0) { + mapped_memory = MappedMemoryPtr{}; + return Status::OK(); + } + +#if WINVER >= _WIN32_WINNT_WIN8 + wil::unique_hfile file_handle{ + CreateFile2(file_path, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, NULL)}; +#else + wil::unique_hfile file_handle{ + CreateFileW(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)}; +#endif + if (file_handle.get() == INVALID_HANDLE_VALUE) { + const auto error_code = GetLastError(); + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, + "open file ", ToUTF8String(Basename(file_path)), + " fail, errcode = ", error_code, + " - ", std::system_category().message(error_code)); + } + +#if WINVER >= _WIN32_WINNT_WIN8 + wil::unique_hfile file_mapping_handle{ + CreateFileMapping2(file_handle.get(), + nullptr, + FILE_MAP_READ, + PAGE_READONLY, + SEC_COMMIT, + 0, + nullptr, + nullptr, + 0)}; +#else + wil::unique_hfile file_mapping_handle{ + CreateFileMappingW(file_handle.get(), + nullptr, + PAGE_READONLY, + 0, + 0, + nullptr)}; +#endif + if (file_mapping_handle.get() == INVALID_HANDLE_VALUE) { + const auto error_code = GetLastError(); + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, + "open file mapping ", ToUTF8String(Basename(file_path)), + " fail, errcode = ", error_code, + " - ", std::system_category().message(error_code)); + } + + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + static const long page_size = sysinfo.dwPageSize; + const FileOffsetType offset_to_page = offset % static_cast(page_size); + const size_t mapped_length = length + offset_to_page; + const FileOffsetType mapped_offset = offset - offset_to_page; + void* const mapped_base = MapViewOfFile(file_mapping_handle.get(), + FILE_MAP_READ, + 0, + mapped_offset, + mapped_length); + + mapped_memory = + MappedMemoryPtr{reinterpret_cast(mapped_base) + offset_to_page, + OrtCallbackInvoker{OrtCallback{UnmapFile, new UnmapFileParam{mapped_base, mapped_length}}}}; + + return Status::OK(); } bool FolderExists(const std::wstring& path) const override { From e6e0da56672f3851e236faef8b974d6e541acb40 Mon Sep 17 00:00:00 2001 From: Ting Cao Date: Sat, 16 Jul 2022 01:05:20 +0800 Subject: [PATCH 2/6] Add unit test for file mapping for windows. Also add an error message for mis-aligned offset --- onnxruntime/core/platform/windows/env.cc | 11 +++++ onnxruntime/test/platform/file_io_test.cc | 59 +++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/onnxruntime/core/platform/windows/env.cc b/onnxruntime/core/platform/windows/env.cc index 291eebd515d7d..fbe92d1b48014 100644 --- a/onnxruntime/core/platform/windows/env.cc +++ b/onnxruntime/core/platform/windows/env.cc @@ -400,9 +400,20 @@ class WindowsEnv : public Env { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); static const long page_size = sysinfo.dwPageSize; + static const long allocation_granularity = sysinfo.dwAllocationGranularity; const FileOffsetType offset_to_page = offset % static_cast(page_size); const size_t mapped_length = length + offset_to_page; const FileOffsetType mapped_offset = offset - offset_to_page; + if (mapped_offset % allocation_granularity != 0) { + const auto error_code = GetLastError(); + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, + "mapped offset must be a multiple of the allocation granularity", + " , mapped_offset = ", mapped_offset, + " , allocation_granularity = ", allocation_granularity, + " , errcode = ", error_code, + " - ", std::system_category().message(error_code)); + } + void* const mapped_base = MapViewOfFile(file_mapping_handle.get(), FILE_MAP_READ, 0, diff --git a/onnxruntime/test/platform/file_io_test.cc b/onnxruntime/test/platform/file_io_test.cc index e4670583f11b9..c148f6ed23b5f 100644 --- a/onnxruntime/test/platform/file_io_test.cc +++ b/onnxruntime/test/platform/file_io_test.cc @@ -10,6 +10,8 @@ #ifndef _WIN32 #include // for sysconf() and _SC_PAGESIZE +#else +#include #endif #include "gsl/gsl" @@ -61,7 +63,11 @@ std::vector GenerateData(size_t length, uint32_t seed = 0) { } void WriteDataToFile(gsl::span data, const PathString& path) { +#ifndef _WIN32 std::ofstream out{path, std::ios_base::out | std::ios_base::trunc}; +#else + std::ofstream out{path, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary}; +#endif out.write(data.data(), data.size()); } @@ -144,6 +150,59 @@ TEST(FileIoTest, MapFileIntoMemory) { ASSERT_FALSE(Env::Default().MapFileIntoMemory(tmp.path.c_str(), -1, 0, mapped_memory).IsOK()); } } +#else +TEST(FileIoTest, MapFileIntoMemory) { + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + static const auto page_size = sysinfo.dwPageSize; + static const auto allocation_granularity = sysinfo.dwAllocationGranularity; + ASSERT_GT(page_size, 0); + + TempFilePath tmp(ORT_TSTR("map_file_test_")); + const auto expected_data = GenerateData(page_size * 3 / 2); + WriteDataToFile(gsl::make_span(expected_data), tmp.path); + + const auto offsets_and_lengths = GenerateValidOffsetLengthPairs( + 0, expected_data.size(), page_size / 10); + + for (const auto& offset_and_length : offsets_and_lengths) { + const auto offset = offset_and_length.first; + const auto length = offset_and_length.second; + + // The offset must be a multiple of the allocation granularity + if (offset % allocation_granularity != 0) { + continue; + } + + Env::MappedMemoryPtr mapped_memory{}; + auto status = Env::Default().MapFileIntoMemory( + tmp.path.c_str(), offset, length, mapped_memory); + ASSERT_TRUE(status.IsOK()) + << "MapFileIntoMemory failed for offset " << offset << " and length " << length + << " with error: " << status.ErrorMessage(); + + auto mapped_span = gsl::make_span(mapped_memory.get(), length); + + auto expected_data_span = gsl::make_span(expected_data.data() + offset, length); + + ASSERT_EQ(mapped_span, expected_data_span); + } + + { + Env::MappedMemoryPtr mapped_memory{}; + + // invalid - offset is not a multiple of the allocation granularity + ASSERT_FALSE(Env::Default().MapFileIntoMemory( + tmp.path.c_str(), allocation_granularity * 3 / 2, page_size / 10, mapped_memory).IsOK()); + } + + { + Env::MappedMemoryPtr mapped_memory{}; + + // invalid - negative offset + ASSERT_FALSE(Env::Default().MapFileIntoMemory(tmp.path.c_str(), -1, 0, mapped_memory).IsOK()); + } +} #endif } // namespace test From ac7bfd683703c4edf2eeb1d3653268c2453a896b Mon Sep 17 00:00:00 2001 From: Ting Cao Date: Sat, 16 Jul 2022 01:05:20 +0800 Subject: [PATCH 3/6] Add unit test for file mapping for windows. Also add an error message for mis-aligned offset --- onnxruntime/core/platform/windows/env.cc | 15 +++++- onnxruntime/test/platform/file_io_test.cc | 59 +++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/onnxruntime/core/platform/windows/env.cc b/onnxruntime/core/platform/windows/env.cc index 291eebd515d7d..c220f2338a4aa 100644 --- a/onnxruntime/core/platform/windows/env.cc +++ b/onnxruntime/core/platform/windows/env.cc @@ -399,10 +399,21 @@ class WindowsEnv : public Env { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); - static const long page_size = sysinfo.dwPageSize; + static const DWORD page_size = sysinfo.dwPageSize; + static const DWORD allocation_granularity = sysinfo.dwAllocationGranularity; const FileOffsetType offset_to_page = offset % static_cast(page_size); - const size_t mapped_length = length + offset_to_page; + const DWORD mapped_length = length + offset_to_page; const FileOffsetType mapped_offset = offset - offset_to_page; + if (mapped_offset % allocation_granularity != 0) { + const auto error_code = GetLastError(); + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, + "mapped offset must be a multiple of the allocation granularity", + " , mapped_offset = ", mapped_offset, + " , allocation_granularity = ", allocation_granularity, + " , errcode = ", error_code, + " - ", std::system_category().message(error_code)); + } + void* const mapped_base = MapViewOfFile(file_mapping_handle.get(), FILE_MAP_READ, 0, diff --git a/onnxruntime/test/platform/file_io_test.cc b/onnxruntime/test/platform/file_io_test.cc index e4670583f11b9..c148f6ed23b5f 100644 --- a/onnxruntime/test/platform/file_io_test.cc +++ b/onnxruntime/test/platform/file_io_test.cc @@ -10,6 +10,8 @@ #ifndef _WIN32 #include // for sysconf() and _SC_PAGESIZE +#else +#include #endif #include "gsl/gsl" @@ -61,7 +63,11 @@ std::vector GenerateData(size_t length, uint32_t seed = 0) { } void WriteDataToFile(gsl::span data, const PathString& path) { +#ifndef _WIN32 std::ofstream out{path, std::ios_base::out | std::ios_base::trunc}; +#else + std::ofstream out{path, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary}; +#endif out.write(data.data(), data.size()); } @@ -144,6 +150,59 @@ TEST(FileIoTest, MapFileIntoMemory) { ASSERT_FALSE(Env::Default().MapFileIntoMemory(tmp.path.c_str(), -1, 0, mapped_memory).IsOK()); } } +#else +TEST(FileIoTest, MapFileIntoMemory) { + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + static const auto page_size = sysinfo.dwPageSize; + static const auto allocation_granularity = sysinfo.dwAllocationGranularity; + ASSERT_GT(page_size, 0); + + TempFilePath tmp(ORT_TSTR("map_file_test_")); + const auto expected_data = GenerateData(page_size * 3 / 2); + WriteDataToFile(gsl::make_span(expected_data), tmp.path); + + const auto offsets_and_lengths = GenerateValidOffsetLengthPairs( + 0, expected_data.size(), page_size / 10); + + for (const auto& offset_and_length : offsets_and_lengths) { + const auto offset = offset_and_length.first; + const auto length = offset_and_length.second; + + // The offset must be a multiple of the allocation granularity + if (offset % allocation_granularity != 0) { + continue; + } + + Env::MappedMemoryPtr mapped_memory{}; + auto status = Env::Default().MapFileIntoMemory( + tmp.path.c_str(), offset, length, mapped_memory); + ASSERT_TRUE(status.IsOK()) + << "MapFileIntoMemory failed for offset " << offset << " and length " << length + << " with error: " << status.ErrorMessage(); + + auto mapped_span = gsl::make_span(mapped_memory.get(), length); + + auto expected_data_span = gsl::make_span(expected_data.data() + offset, length); + + ASSERT_EQ(mapped_span, expected_data_span); + } + + { + Env::MappedMemoryPtr mapped_memory{}; + + // invalid - offset is not a multiple of the allocation granularity + ASSERT_FALSE(Env::Default().MapFileIntoMemory( + tmp.path.c_str(), allocation_granularity * 3 / 2, page_size / 10, mapped_memory).IsOK()); + } + + { + Env::MappedMemoryPtr mapped_memory{}; + + // invalid - negative offset + ASSERT_FALSE(Env::Default().MapFileIntoMemory(tmp.path.c_str(), -1, 0, mapped_memory).IsOK()); + } +} #endif } // namespace test From 877d18cb39ac148e1a4b63e10f722f90bbbd1a4d Mon Sep 17 00:00:00 2001 From: Ting Cao Date: Sat, 16 Jul 2022 23:47:42 +0800 Subject: [PATCH 4/6] Update data type to avoid warnings --- onnxruntime/core/platform/windows/env.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/core/platform/windows/env.cc b/onnxruntime/core/platform/windows/env.cc index 6a76a8b15a022..b0e9e21a1a180 100644 --- a/onnxruntime/core/platform/windows/env.cc +++ b/onnxruntime/core/platform/windows/env.cc @@ -403,7 +403,7 @@ class WindowsEnv : public Env { static const DWORD page_size = sysinfo.dwPageSize; static const DWORD allocation_granularity = sysinfo.dwAllocationGranularity; const FileOffsetType offset_to_page = offset % static_cast(page_size); - const DWORD mapped_length = length + offset_to_page; + const size_t mapped_length = length + offset_to_page; const FileOffsetType mapped_offset = offset - offset_to_page; if (mapped_offset % allocation_granularity != 0) { const auto error_code = GetLastError(); From 1d720d928478beedd31e981d1e633b701266a69f Mon Sep 17 00:00:00 2001 From: Ting Cao Date: Mon, 18 Jul 2022 00:43:20 +0800 Subject: [PATCH 5/6] Compitable data type to avoid warnings. Update CreatFileMapping2 condition for winml compiling. --- onnxruntime/core/platform/windows/env.cc | 4 ++-- onnxruntime/test/platform/file_io_test.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/onnxruntime/core/platform/windows/env.cc b/onnxruntime/core/platform/windows/env.cc index b0e9e21a1a180..b464a6f7810bc 100644 --- a/onnxruntime/core/platform/windows/env.cc +++ b/onnxruntime/core/platform/windows/env.cc @@ -369,7 +369,7 @@ class WindowsEnv : public Env { " - ", std::system_category().message(error_code)); } -#if WINVER >= _WIN32_WINNT_WIN8 +#if NTDDI_VERSION >= NTDDI_WIN10_RS5 wil::unique_hfile file_mapping_handle{ CreateFileMapping2(file_handle.get(), nullptr, @@ -418,7 +418,7 @@ class WindowsEnv : public Env { void* const mapped_base = MapViewOfFile(file_mapping_handle.get(), FILE_MAP_READ, 0, - mapped_offset, + static_cast(mapped_offset), mapped_length); mapped_memory = diff --git a/onnxruntime/test/platform/file_io_test.cc b/onnxruntime/test/platform/file_io_test.cc index c148f6ed23b5f..9dec13767ef90 100644 --- a/onnxruntime/test/platform/file_io_test.cc +++ b/onnxruntime/test/platform/file_io_test.cc @@ -156,7 +156,7 @@ TEST(FileIoTest, MapFileIntoMemory) { GetSystemInfo(&sysinfo); static const auto page_size = sysinfo.dwPageSize; static const auto allocation_granularity = sysinfo.dwAllocationGranularity; - ASSERT_GT(page_size, 0); + ASSERT_GT(page_size, static_cast(0)); TempFilePath tmp(ORT_TSTR("map_file_test_")); const auto expected_data = GenerateData(page_size * 3 / 2); From 0a858fe5ca224e2a2928316d75b02fdf37db7133 Mon Sep 17 00:00:00 2001 From: Ting Cao Date: Mon, 18 Jul 2022 13:31:21 +0800 Subject: [PATCH 6/6] Add type conversion to avoid warnings for X86 release build. --- onnxruntime/core/platform/windows/env.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/core/platform/windows/env.cc b/onnxruntime/core/platform/windows/env.cc index b464a6f7810bc..c18075cc7b4b9 100644 --- a/onnxruntime/core/platform/windows/env.cc +++ b/onnxruntime/core/platform/windows/env.cc @@ -403,7 +403,7 @@ class WindowsEnv : public Env { static const DWORD page_size = sysinfo.dwPageSize; static const DWORD allocation_granularity = sysinfo.dwAllocationGranularity; const FileOffsetType offset_to_page = offset % static_cast(page_size); - const size_t mapped_length = length + offset_to_page; + const size_t mapped_length = length + static_cast(offset_to_page); const FileOffsetType mapped_offset = offset - offset_to_page; if (mapped_offset % allocation_granularity != 0) { const auto error_code = GetLastError();