Summary
MmapAllocator assumes the OS page size is 4KB (AllocationTraits::kPageSize, a compile-time constant). On systems where the kernel's actual page size is larger, madvise() calls at sub-page granularity silently fail with EINVAL instead of throwing, which corrupts the allocator's internal page-count accounting (numMapped() can underflow to a huge value) rather than surfacing a clear error. This affects NVIDIA Grace / Grace-Hopper (GH200) systems, where 64KB pages are NVIDIA's documented recommended default (not a rare or misconfigured setup): https://docs.nvidia.com/dccpu/grace-perf-tuning-guide/os-settings.html — "The recommended default value for the page size is 64K."
Root cause
MmapAllocator::SizeClass::adviseAway() calls:
::madvise(run.data(), AllocationTraits::pageBytes(run.numPages()), MADV_DONTNEED)
madvise() requires the address to be aligned to the real OS page size and operates at that granularity. AllocationTraits::kPageSize is hardcoded to 4096 (velox/common/memory/Allocation.h) and used across ~80 call sites in ~27 files to track memory at 4KB-unit granularity — finer than the 64KB pages the kernel actually provides on Grace by default. madvise() on a sub-64KB region fails with EINVAL; the calling code logs the error but doesn't roll back its own accounting, so the allocator's mapped-page counters drift out of sync with reality.
Repro: on a Grace/GH200 host with the default 64KB page kernel (getconf PAGESIZE → 65536), any code path that calls MmapAllocator::SizeClass::adviseAway() (memory reclaim under pressure, MmapAllocator::unmap(), AsyncDataCache eviction, etc.) hits this. Concretely, MemoryAllocatorTest.unmap and several AsyncDataCacheTest/CacheInputTest cases fail or crash on such a host.
Not Velox-specific
This is a known, currently open, cross-project problem for anything assuming 4KB pages on Grace:
Current mitigation (workaround PR)
See #18619 (draft) for the test-skip workaround this issue tracks a real fix for.
#18618 makes MmapAllocator's constructor check isPageSizeSupported() and fail immediately with a clear, actionable error instead of silently corrupting state, and updates the affected tests to skip (not fail) with an explicit reason when this check doesn't hold. This does not fix the underlying limitation — it converts a silent correctness bug into a loud, honest one, and stops tests from red-flagging a host class that can't be supported without the change described below.
What a real fix looks like
Generalizing AllocationTraits::kPageSize from a compile-time 4096 constant to a value queried at runtime (sysconf(_SC_PAGESIZE)) touches the ~80 call sites above, most of which use it for compile-time-sized bitmap/size-class accounting. Doing this changes MmapAllocator's minimum allocation granularity to match the real page size — on a 64KB-page Grace host that's a 16x increase in the smallest allocatable unit, which has real memory-overhead implications for workloads with many small allocations. That's a deliberate design tradeoff, not a pure bug fix, and needs sign-off from whoever owns the memory-allocator subsystem before landing — hence tracking it here separately rather than folding it into the workaround PR.
Environment where this was found
- aarch64, NVIDIA GH200 (Grace Hopper), kernel
*-64k variant, getconf PAGESIZE = 65536.
Summary
MmapAllocatorassumes the OS page size is 4KB (AllocationTraits::kPageSize, a compile-time constant). On systems where the kernel's actual page size is larger,madvise()calls at sub-page granularity silently fail withEINVALinstead of throwing, which corrupts the allocator's internal page-count accounting (numMapped()can underflow to a huge value) rather than surfacing a clear error. This affects NVIDIA Grace / Grace-Hopper (GH200) systems, where 64KB pages are NVIDIA's documented recommended default (not a rare or misconfigured setup): https://docs.nvidia.com/dccpu/grace-perf-tuning-guide/os-settings.html — "The recommended default value for the page size is 64K."Root cause
MmapAllocator::SizeClass::adviseAway()calls:::madvise(run.data(), AllocationTraits::pageBytes(run.numPages()), MADV_DONTNEED)madvise()requires the address to be aligned to the real OS page size and operates at that granularity.AllocationTraits::kPageSizeis hardcoded to4096(velox/common/memory/Allocation.h) and used across ~80 call sites in ~27 files to track memory at 4KB-unit granularity — finer than the 64KB pages the kernel actually provides on Grace by default.madvise()on a sub-64KB region fails withEINVAL; the calling code logs the error but doesn't roll back its own accounting, so the allocator's mapped-page counters drift out of sync with reality.Repro: on a Grace/GH200 host with the default 64KB page kernel (
getconf PAGESIZE→65536), any code path that callsMmapAllocator::SizeClass::adviseAway()(memory reclaim under pressure,MmapAllocator::unmap(),AsyncDataCacheeviction, etc.) hits this. Concretely,MemoryAllocatorTest.unmapand severalAsyncDataCacheTest/CacheInputTestcases fail or crash on such a host.Not Velox-specific
This is a known, currently open, cross-project problem for anything assuming 4KB pages on Grace:
mmap()assumptions on Grace: opencode crashes on aarch64+64k systems (64KB page size) anomalyco/opencode#12474.Current mitigation (workaround PR)
See #18619 (draft) for the test-skip workaround this issue tracks a real fix for.
#18618 makes
MmapAllocator's constructor checkisPageSizeSupported()and fail immediately with a clear, actionable error instead of silently corrupting state, and updates the affected tests to skip (not fail) with an explicit reason when this check doesn't hold. This does not fix the underlying limitation — it converts a silent correctness bug into a loud, honest one, and stops tests from red-flagging a host class that can't be supported without the change described below.What a real fix looks like
Generalizing
AllocationTraits::kPageSizefrom a compile-time4096constant to a value queried at runtime (sysconf(_SC_PAGESIZE)) touches the ~80 call sites above, most of which use it for compile-time-sized bitmap/size-class accounting. Doing this changesMmapAllocator's minimum allocation granularity to match the real page size — on a 64KB-page Grace host that's a 16x increase in the smallest allocatable unit, which has real memory-overhead implications for workloads with many small allocations. That's a deliberate design tradeoff, not a pure bug fix, and needs sign-off from whoever owns the memory-allocator subsystem before landing — hence tracking it here separately rather than folding it into the workaround PR.Environment where this was found
*-64kvariant,getconf PAGESIZE= 65536.