diff options
| author | Exverge <exverge@exverge.xyz> | 2026-09-23 13:52:29 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-09-23 13:52:29 +0200 |
| commit | 38df54edfe7b861d0a0a1ee305836049a39d42ef (patch) | |
| tree | ebd586cd501ee84feb6065393a62d80d15008390 /src/common | |
| parent | 3266c20e3f27a459449b77214182be3f0332e8f4 (diff) | |
[common/sparse_large_vector] decommit unused pages + fix first page in zeroed region (#4471)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
-------------------
Fixes a bug where the first page of a zeroed out region would not be properly zeroed, and now frees unused memory.
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4471
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/sparse_large_vector.cpp | 15 | ||||
| -rw-r--r-- | src/common/sparse_large_vector.h | 20 |
2 files changed, 32 insertions, 3 deletions
diff --git a/src/common/sparse_large_vector.cpp b/src/common/sparse_large_vector.cpp index ce6455a235..745575a880 100644 --- a/src/common/sparse_large_vector.cpp +++ b/src/common/sparse_large_vector.cpp @@ -96,6 +96,21 @@ bool CommitVectorPage(uintptr_t addr, bool write) noexcept { #ifndef MAP_NOCORE #define MAP_NOCORE 0 #endif +#ifndef MADV_FREE +#define MADV_FREE MADV_DONTNEED +#endif + +void DecommitVectorPage(uintptr_t base) noexcept { +#if defined(_WIN32) + VirtualFree(reinterpret_cast<LPVOID>(base), HostPageSize, MEM_DECOMMIT); +#elif defined(__linux__) + // Linux's MADV_DONTNEED zeros out pages for us + madvise(reinterpret_cast<void*>(base), HostPageSize, MADV_DONTNEED); +#else + madvise(reinterpret_cast<void*>(base), HostPageSize, MADV_FREE); + std::memset(reinterpret_cast<void*>(base), 0, HostPageSize); +#endif +} void* AllocateMemoryPages(std::size_t size) noexcept { if (auto page = HostPageSize; size % page != 0) { diff --git a/src/common/sparse_large_vector.h b/src/common/sparse_large_vector.h index dad3aea97e..86f0be7866 100644 --- a/src/common/sparse_large_vector.h +++ b/src/common/sparse_large_vector.h @@ -35,6 +35,7 @@ const u64 HostPageMask = ~(HostPageSize - 1); void* AllocateMemoryPages(std::size_t size) noexcept; void FreeMemoryPages(void* base, std::size_t size) noexcept; +void DecommitVectorPage(uintptr_t base) noexcept; /// A large page-aligned buffer that has optimized memory usage for zero-writes. template <typename T> @@ -114,7 +115,7 @@ public: const u64 end_page = AlignUp(base, HostPageSize); const u64 first_size = (std::min)(end_page, end) - base; - if (IsCommittedPage(start / sizeof(T))) { + if (IsCommittedPage(start)) { std::memset(reinterpret_cast<void*>(base), 0, first_size); } @@ -124,11 +125,16 @@ public: base = end_page; for (u64 page = base; page < end; page += HostPageSize) { - if (!IsCommittedPage((page - reinterpret_cast<u64>(base_ptr)) / sizeof(T))) { + auto index = (page - reinterpret_cast<u64>(base_ptr)) / sizeof(T); + if (!IsCommittedPage(index)) { continue; } - std::memset(reinterpret_cast<void*>(page), 0, (std::min)( HostPageSize, end - page)); + if (end - page >= HostPageSize) { + DecommitPage(index); + } else { + std::memset(reinterpret_cast<void*>(page), 0, end - page); + } } } @@ -183,6 +189,14 @@ private: committed_pages[page_index >> 6].fetch_or(1ULL << (page_index & 63), std::memory_order_release); } + constexpr void DecommitPage(std::size_t index) noexcept { + auto page_index = (index * sizeof(T)) >> HostPageBits; + auto page = reinterpret_cast<uintptr_t>(base_ptr + index) & HostPageMask; + + committed_pages[page_index >> 6].fetch_and(~(1ULL << (page_index & 63)), std::memory_order_release); + DecommitVectorPage(page); + } + std::size_t alloc_size{}; T* base_ptr{}; |
