Skip to content

Commit 7d8cb8b

Browse files
committed
fix(aspacem): raise amd64 managed address ceiling to 1 TiB
snmalloc-rs as a global allocator aborts under Callgrind because its startup mmap of a flat 256 GiB MAP_NORESERVE range returns EINVAL. On amd64-linux the address-space manager capped the managed range at 128 GiB, placing vStart (the client/Valgrind split) at ~64 GiB, so the largest floating client hole was ~62 GiB and any larger reservation was vetoed by VG_(am_get_advisory). Raise aspacem_maxAddr to 1 TiB (vStart ~512 GiB, ~512 GiB client hole), scoped to VGP_amd64_linux so other 64-bit ports keep 128 GiB (some arm64 kernels expose only a 39-bit user VA). No effect on Callgrind placement semantics; the fork ships only the 64-bit Callgrind tool. Refs COD-3073
1 parent ce9d871 commit 7d8cb8b

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

CODSPEED-CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,24 @@ valgrind --tool=callgrind \
113113
--obj-skip=/lib/x86_64-linux-gnu/libpthread.so.0 \
114114
./your_program
115115
```
116+
117+
## Changes
118+
119+
### Raise amd64 managed address-space ceiling to 1 TiB
120+
121+
**Change**: On `amd64-linux`, the address-space manager's ceiling (`aspacem_maxAddr`) is raised from 128 GiB to 1 TiB.
122+
123+
**Motivation**: Allocators that reserve a single large, lazily-backed (`MAP_NORESERVE`) address range at startup aborted under Valgrind. The concrete case is `snmalloc` (used via `snmalloc-rs` as a global allocator), which reserves a flat 256 GiB range on init:
124+
125+
```
126+
sys_mmap( NULL, 274877906944, PROT_READ|WRITE, MAP_PRIVATE|ANON|NORESERVE, -1, 0 ) --> EINVAL
127+
"Failed to initialise snmalloc." -> SIGABRT
128+
```
129+
130+
A real kernel grants this for free (virtual only). Valgrind's aspacem, however, only manages a bounded region and rejects a floating request that cannot fit. With the old 128 GiB ceiling, `vStart` (the client/Valgrind split) sat at ~64 GiB, so the largest contiguous client hole was ~62 GiB and any reservation above that returned `EINVAL`, forcing the CodSpeed wizard to fall back to walltime instead of simulation mode.
131+
132+
**How it works**: `aspacem_vStart` is the midpoint of `[minAddr, maxAddr]` and a one-page reservation is placed there at startup, so a floating client `mmap` (which searches upward from `cStart`) can obtain a contiguous hole of at most ~half the ceiling. A 1 TiB ceiling yields a ~512 GiB client hole, which accommodates the 256 GiB reservation with headroom. 1 TiB stays well within amd64's 47-bit (128 TiB) user address space.
133+
134+
**Scope**: The change is guarded by `defined(VGP_amd64_linux)`; other 64-bit Linux ports keep the 128 GiB ceiling (some arm64 kernels expose only a 39-bit / 512 GiB user VA, which a 1 TiB ceiling would exceed). The raised ceiling also moves the client's initial stack and Valgrind's own segments to higher addresses. This has no effect on Callgrind (no per-address shadow map); Memcheck would service the now-higher stack via its slower auxiliary map, but the CodSpeed build ships only the 64-bit Callgrind tool.
135+
136+
**Workaround (no fork change)**: Building `snmalloc-rs` with its `qemu` feature (`SNMALLOC_QEMU_WORKAROUND`) drops the reservation to 32 GiB, which fits the old 128 GiB layout.

coregrind/m_aspacemgr/aspacemgr-linux.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,7 +1862,17 @@ Addr VG_(am_startup) ( Addr sp_at_startup )
18621862
sp_at_startup );
18631863

18641864
# if VG_WORDSIZE == 8
1865+
# if defined(VGP_amd64_linux)
1866+
// Startup inserts a one-page reservation at vStart (the midpoint of
1867+
// [minAddr, maxAddr]), splitting the initial free space. A floating
1868+
// client mmap searches upward from cStart, so the largest contiguous
1869+
// hole it can get runs up to that split, i.e. ~half of maxAddr. 128G
1870+
// left only a ~64G client hole, rejecting multi-hundred-GB lazily-backed
1871+
// reservations. 1T gives a ~512G hole, well within amd64's 47-bit VA.
1872+
aspacem_maxAddr = (Addr)0x10000000000ULL - 1; // 1T
1873+
# else
18651874
aspacem_maxAddr = (Addr)0x2000000000ULL - 1; // 128G
1875+
# endif
18661876
# ifdef ENABLE_INNER
18671877
{ Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1;
18681878
if (aspacem_maxAddr > cse)

0 commit comments

Comments
 (0)