From 65878567f2de5856d7ea9d0b3f328a40a81cfd62 Mon Sep 17 00:00:00 2001 From: "daniel.korn" Date: Sat, 31 Oct 2026 18:20:15 +0100 Subject: [PATCH 1/2] perf: set malloc top pad to 16 MB instead of the trim threshold Like M_TRIM_THRESHOLD, an explicit M_TOP_PAD disables glibc's dynamic mmap threshold, and it grows the heap in 16 MB steps instead of 128 KB, saving brk() calls and page faults with many threads. Planet (PMTiles, 32 threads): -3.6% wall, -5.3% sys, +0.26 GB anon peak. Germany: -5% wall, page faults 6.1M -> 3.5M (-42%), +60 MB RSS. --- src/tilemaker.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tilemaker.cpp b/src/tilemaker.cpp index 7a7ae1e5..82405140 100644 --- a/src/tilemaker.cpp +++ b/src/tilemaker.cpp @@ -97,11 +97,14 @@ int main(const int argc, const char* argv[]) { #ifdef __GLIBC__ // glibc raises its mmap threshold dynamically (up to 32/64 MB) once a large // mmapped chunk is freed; multi-MB buffers then land in per-thread arenas - // that are never trimmed, inflating peak RSS. Setting the trim threshold - // explicitly also disables that dynamic adjustment (the mmap threshold - // stays at its 128 KB default), unless the user tunes malloc via the environment. - if (!getenv("MALLOC_TRIM_THRESHOLD_") && !getenv("MALLOC_MMAP_THRESHOLD_") && !getenv("GLIBC_TUNABLES")) { - mallopt(M_TRIM_THRESHOLD, 4 << 20); + // that are never trimmed, inflating peak RSS. Setting the top pad explicitly + // also disables that dynamic adjustment (the mmap threshold stays at its + // 128 KB default). The 16 MB pad makes the heap grow and shrink in large + // steps: with many threads allocating, the default 128 KB steps cost many + // brk() calls and page faults (planet: -3.6% wall time, +0.26 GB peak memory). + // Users who tune malloc via the environment keep their settings. + if (!getenv("MALLOC_TRIM_THRESHOLD_") && !getenv("MALLOC_MMAP_THRESHOLD_") && !getenv("MALLOC_TOP_PAD_") && !getenv("GLIBC_TUNABLES")) { + mallopt(M_TOP_PAD, 16 << 20); } #endif From 32d9bd991c8ef83487c0488eff4ec206002be472 Mon Sep 17 00:00:00 2001 From: "daniel.korn" Date: Mon, 2 Nov 2026 09:22:05 +0100 Subject: [PATCH 2/2] perf: also set the mmap threshold to 8 MB Setting any malloc parameter freezes glibc's mmap threshold at 128 KB, so every larger buffer is a fresh mmap with zeroed pages. Boost's is_valid grows such vectors over and over for a huge polygon: the Tongass National Forest relation (1.9M points) took 3x as long as before #939. Tongass relation 677 -> 232 s; planet -2.6% wall for +0.85 GB peak heap; planet on 4 CPUs / 16 GB unchanged within noise, same heap peak. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/tilemaker.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tilemaker.cpp b/src/tilemaker.cpp index 82405140..c737981e 100644 --- a/src/tilemaker.cpp +++ b/src/tilemaker.cpp @@ -97,14 +97,19 @@ int main(const int argc, const char* argv[]) { #ifdef __GLIBC__ // glibc raises its mmap threshold dynamically (up to 32/64 MB) once a large // mmapped chunk is freed; multi-MB buffers then land in per-thread arenas - // that are never trimmed, inflating peak RSS. Setting the top pad explicitly - // also disables that dynamic adjustment (the mmap threshold stays at its - // 128 KB default). The 16 MB pad makes the heap grow and shrink in large - // steps: with many threads allocating, the default 128 KB steps cost many - // brk() calls and page faults (planet: -3.6% wall time, +0.26 GB peak memory). + // that are never trimmed, inflating peak RSS. Setting malloc parameters + // explicitly turns that dynamic adjustment off, so both are set here: + // - a 16 MB top pad makes the heap grow and shrink in large steps; with many + // threads allocating, the default 128 KB steps cost many brk() calls and + // page faults + // - a fixed 8 MB mmap threshold: otherwise it would stay at 128 KB, and every + // larger buffer would be a fresh mmap with zeroed pages. Boost's validity + // check on a huge polygon grows such buffers over and over (one relation + // with 1.9M points took 3x as long). // Users who tune malloc via the environment keep their settings. if (!getenv("MALLOC_TRIM_THRESHOLD_") && !getenv("MALLOC_MMAP_THRESHOLD_") && !getenv("MALLOC_TOP_PAD_") && !getenv("GLIBC_TUNABLES")) { mallopt(M_TOP_PAD, 16 << 20); + mallopt(M_MMAP_THRESHOLD, 8 << 20); } #endif