From e95d0a825982874db2c1ebe4f997a495550dea37 Mon Sep 17 00:00:00 2001 From: Stephan Bauroth Date: Thu, 12 Nov 2026 14:15:24 +0100 Subject: [PATCH] build-bench-env.sh: let ff align jumbo allocations rbstress fails for ff on ubuntu after 4 seconds: ruby 3.2 asks for posix_memalign(32 KB, 32 MB) while it starts up, and ffmalloc answered EINVAL for every request above page alignment that reaches its jumbo path ("until that's fixed"). ruby reads the NULL as out of memory and aborts in ruby_setup, so both rbstress tests die before the benchmark begins. Fedora's ruby 4 makes no such request, which is why only ubuntu is red. Ask for the alignment in excess in the shared jumbo path and return an aligned address inside the pool. A pointer inside a jumbo pool is valid to free because free(), realloc() and malloc_usable_size() resolve the pool that contains the pointer, so this needs no bookkeeping and the three refusals in posix_memalign, memalign and aligned_alloc go away. --- .gitattributes | 4 +++ build-bench-env.sh | 3 ++ patches/ff.patch | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 patches/ff.patch diff --git a/.gitattributes b/.gitattributes index 7d3203f2..e5cfca38 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,7 @@ *.sln binary *.suo binary *.vcproj binary + +# ffmalloc.c is CRLF upstream, so a patch against it has to keep those +# endings to be able to apply +patches/ff.patch -text diff --git a/build-bench-env.sh b/build-bench-env.sh index 9b98cc4f..5ea815af 100755 --- a/build-bench-env.sh +++ b/build-bench-env.sh @@ -535,6 +535,9 @@ fi if test "$setup_ff" = "1"; then checkout ff $version_ff https://github.com/bwickman97/ffmalloc + set +e + patch -p1 -N -r- < ../../patches/ff.patch + set -e make -j $procs popd fi diff --git a/patches/ff.patch b/patches/ff.patch new file mode 100644 index 00000000..636bb8c6 --- /dev/null +++ b/patches/ff.patch @@ -0,0 +1,90 @@ +--- a/ffmalloc.c ++++ b/ffmalloc.c +@@ -2641,6 +2641,25 @@ + } + } + ++// Jumbo pools come straight from the OS and are only page aligned. Ask for ++// the alignment in excess and return an address aligned inside the pool: ++// free(), realloc() and malloc_usable_size() resolve a pointer to the pool ++// that contains it, so any address inside the pool is valid to free. ++static inline void* ffalign_jumbo(size_t alignment, size_t size) { ++ if(alignment > PAGE_SIZE) { ++ if(size + alignment < size) { ++ return NULL; ++ } ++ size += alignment; ++ } ++ void* ptr = ffmalloc_jumbo(size, arenas[0]); ++ if(ptr == NULL) { ++ return NULL; ++ } ++ return (void*)ALIGN_TO((uintptr_t)ptr, alignment); ++} ++ ++ + static inline void* ffmemalign_internal(size_t alignment, size_t size) { + #ifdef FF_PROFILE + FFAtomicIncrement(arenas[0]->profile.posixAlignCount); +@@ -2671,7 +2690,7 @@ + size = ALIGN_SIZE(size); + + if(size >= POOL_SIZE) { +- return ffmalloc_jumbo(size, arenas[0]); ++ return ffalign_jumbo(alignment, size); + } + else { + return ffmalloc_large(size, alignment, arenas[0]); +@@ -2698,14 +2717,6 @@ + return EINVAL; + } + +- // Current jumbo allocation code is missing alignment support but all +- // jumbo allocations will be at least page aligned. For now it is an +- // error to request more than page alignment for a jumbo allocation +- if(size + PAGE_SIZE >= POOL_SIZE && alignment > PAGE_SIZE) { +- *ptr = NULL; +- return EINVAL; +- } +- + *ptr = ffmemalign_internal(alignment, size); + if(*ptr == NULL) { + return ENOMEM; +@@ -2738,14 +2749,6 @@ + return ffmalloc(size); + } + +- // The jumbo allocation code doesn't support custom alignment right now +- // but any jumbo alignment will be page aligned. So, error out if the +- // request is bigger than page size otherwise carry on +- if(size + PAGE_SIZE >= POOL_SIZE && alignment > PAGE_SIZE) { +- errno = EINVAL; +- return NULL; +- } +- + return ffmemalign_internal(alignment, size); + } + +@@ -2773,21 +2776,13 @@ + return NULL; + } + +- // Missing alignment support in jumbo code so forbid greater than page +- // alignment for jumbo allocations until that's fixed. All jumbo +- // allocations will be page aligned anyways +- if(size + PAGE_SIZE >= POOL_SIZE && alignment > PAGE_SIZE) { +- errno = EINVAL; +- return NULL; +- } +- + #ifdef FF_PROFILE + FFAtomicIncrement(arenas[0]->profile.allocAlignCount); + FFAtomicAdd(arenas[0]->profile.totalBytesRequested, size); + #endif + + if (size >= POOL_SIZE) { +- return ffmalloc_jumbo(size, arenas[0]); ++ return ffalign_jumbo(alignment, size); + } + // Allocation can be serviced from the small bin only if both the size + // and the alignment fit into the small bin