aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorExverge <exverge@exverge.xyz>2026-09-23 13:52:29 +0200
committercrueter <crueter@eden-emu.dev>2026-09-23 13:52:29 +0200
commit38df54edfe7b861d0a0a1ee305836049a39d42ef (patch)
treeebd586cd501ee84feb6065393a62d80d15008390 /src/common
parent3266c20e3f27a459449b77214182be3f0332e8f4 (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.cpp15
-rw-r--r--src/common/sparse_large_vector.h20
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{};