From 591b04958532332c9993698df21ffb5e7cfd27b8 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Wed, 8 Jul 2020 16:17:33 +0100 Subject: [PATCH] Implement PAL backoff (#227) The POSIX PAL and in some configurations the Windows PAL overallocate address space. If address space has become exhausted then this can lead to issues, where the PAL fails, even though there is enough aligned address space to satisfy the underlying request. This commit tries increasingly smaller overallocation sizes in an attempt to succeed in more cases. --- src/pal/pal_posix.h | 29 ++++++++++++++++++----------- src/pal/pal_windows.h | 19 ++++++++++++------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/pal/pal_posix.h b/src/pal/pal_posix.h index bab9835..03d39cc 100644 --- a/src/pal/pal_posix.h +++ b/src/pal/pal_posix.h @@ -209,23 +209,30 @@ namespace snmalloc */ std::pair reserve_at_least(size_t size) noexcept { + SNMALLOC_ASSERT(size == bits::next_pow2(size)); + // Magic number for over-allocating chosen by the Pal // These should be further refined based on experiments. constexpr size_t min_size = bits::is64() ? bits::one_at_bit(32) : bits::one_at_bit(28); - auto size_request = bits::max(size, min_size); - void* p = mmap( - nullptr, - size_request, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | DefaultMMAPFlags::flags, - AnonFD::fd, - 0); - if (p == MAP_FAILED) - OS::error("Out of memory"); + for (size_t size_request = bits::max(size, min_size); + size_request >= size; + size_request = size_request / 2) + { + void* p = mmap( + nullptr, + size_request, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | DefaultMMAPFlags::flags, + AnonFD::fd, + 0); - return {p, size_request}; + if (p != MAP_FAILED) + return {p, size_request}; + } + + OS::error("Out of memory"); } }; } // namespace snmalloc diff --git a/src/pal/pal_windows.h b/src/pal/pal_windows.h index 08e8c17..b4cec09 100644 --- a/src/pal/pal_windows.h +++ b/src/pal/pal_windows.h @@ -218,19 +218,24 @@ namespace snmalloc # else std::pair reserve_at_least(size_t size) noexcept { + SNMALLOC_ASSERT(size == bits::next_pow2(size)); + // Magic number for over-allocating chosen by the Pal // These should be further refined based on experiments. constexpr size_t min_size = bits::is64() ? bits::one_at_bit(32) : bits::one_at_bit(28); - auto size_request = bits::max(size, min_size); - - DWORD flags = MEM_RESERVE; - void* ret = VirtualAlloc(nullptr, size_request, flags, PAGE_READWRITE); - if (ret == nullptr) + for (size_t size_request = bits::max(size, min_size); + size_request >= size; + size_request = size_request / 2) { - error("Failed to allocate memory\n"); + void* ret = + VirtualAlloc(nullptr, size_request, MEM_RESERVE, PAGE_READWRITE); + if (ret != nullptr) + { + return std::pair(ret, size_request); + } } - return std::pair(ret, size_request); + error("Failed to allocate memory\n"); } # endif };