src/os.c: avoid doomed alloc/free on 32-bit and SV39 systems

On 32-bit or SV39 systems, _mi_os_get_aligned_hint() in src/os.c is
ifdef'd to always return NULL. As a result, the OS prim allocation
routines using that hint will fail to obtain aligned memory. When that
happens, we free() the result, and overallocate.

But this is wasteful: we know that (with high probability) the first
attempt at an aligned allocation will fail. This commit modifies
mi_os_prim_alloc_aligned() to skip the doomed alloc and subsequent
free using the same ifdef condition that is used to disable the hint.
This commit is contained in:
Michael Orlitzky 2024-10-18 09:33:19 -04:00
parent 53440ad69a
commit 4f1a42022c

View file

@ -215,6 +215,10 @@ static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bo
// Primitive aligned allocation from the OS. // Primitive aligned allocation from the OS.
// This function guarantees the allocated memory is aligned. // This function guarantees the allocated memory is aligned.
static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** base, mi_stats_t* stats) { static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, void** base, mi_stats_t* stats) {
#if (MI_INTPTR_SIZE < 8) || (defined(MI_SV39_MMU) && MI_SV39_MMU != 0)
MI_UNUSED(allow_large); // not used on 32-bit/SV39 systems
#endif
mi_assert_internal(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0)); mi_assert_internal(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0));
mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0); mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0);
mi_assert_internal(is_large != NULL); mi_assert_internal(is_large != NULL);
@ -224,18 +228,33 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit
if (!(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0))) return NULL; if (!(alignment >= _mi_os_page_size() && ((alignment & (alignment - 1)) == 0))) return NULL;
size = _mi_align_up(size, _mi_os_page_size()); size = _mi_align_up(size, _mi_os_page_size());
// try first with a hint (this will be aligned directly on Win 10+ or BSD) void* p = NULL;
void* p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero, stats);
#if (MI_INTPTR_SIZE >= 8) && (!defined(MI_SV39_MMU) || MI_SV39_MMU == 0)
// Try first with a hint. This will be usually be aligned directly
// on Win 10+ or BSD, but if this is a 32-bit or SV39 system, we
// don't bother -- it's not going to work.
p = mi_os_prim_alloc(size, alignment, commit, allow_large, is_large, is_zero, stats);
if (p == NULL) return NULL; if (p == NULL) return NULL;
#endif
// aligned already? // aligned already?
if (((uintptr_t)p % alignment) == 0) { if (p && ((uintptr_t)p % alignment) == 0) {
*base = p; *base = p;
} }
else { else {
// if not aligned, free it, overallocate, and unmap around it // If p is not aligned, then either we tried and failed to obtain
// an aligned allocation, or we didn't try at all. Only one of
// these is a warning scenario.
#if (MI_INTPTR_SIZE >= 8) && (!defined(MI_SV39_MMU) || MI_SV39_MMU == 0)
// Skip the warning and the free() if we never attempted an aligned
// allocation in the first place.
_mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (size: 0x%zx bytes, address: %p, alignment: 0x%zx, commit: %d)\n", size, p, alignment, commit); _mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (size: 0x%zx bytes, address: %p, alignment: 0x%zx, commit: %d)\n", size, p, alignment, commit);
mi_os_prim_free(p, size, commit, stats); mi_os_prim_free(p, size, commit, stats);
#endif
// now overallocate
if (size >= (SIZE_MAX - alignment)) return NULL; // overflow if (size >= (SIZE_MAX - alignment)) return NULL; // overflow
const size_t over_size = size + alignment; const size_t over_size = size + alignment;