From 878f64856f6a128103d6ec7f18c6442232f5ce9d Mon Sep 17 00:00:00 2001 From: Christophe Combelles Date: Sat, 16 May 2026 17:41:12 +0200 Subject: [PATCH 1/2] fix(docker): patch OpenBLAS pthread stack size for musl static build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Statically-linked Alpine/musl builds segfault inside MUMPS factorization on the first BLAS3 call from a worker thread (exit 139). musl's default pthread stack is 128 KB, vs glibc's 8 MB read from RLIMIT_STACK. OpenBLAS worker threads inherit that 128 KB and overflow on DYNAMIC_ARCH Fortran kernels that hold large auto-arrays — typically dgemm/dtrsm on dense frontal blocks during sparse LU factorization. Reproduces on a 16 GB VM running volca-with-frontend, on the first impact request hitting Agribalyse 3.2 (21510 activities). The crash is not memory-bound (RSS stays low, exit code 139 = SIGSEGV, not 137). Patch driver/others/blas_server.c to call pthread_attr_setstacksize at 8 MB before pthread_create. The change aligns musl's behaviour with glibc's effective default and is a no-op on glibc rebuilds. Two grep guards bracket the sed: if a future OpenBLAS release moves the pthread_attr_init anchor, the Docker build fails loudly instead of silently producing a binary that crashes in production. --- docker/Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index f7d6215..0d999f0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -88,6 +88,15 @@ RUN . /tmp/versions.env \ && curl -fsSL "https://github.com/OpenMathLib/OpenBLAS/releases/download/v${OPENBLAS_VERSION}/OpenBLAS-${OPENBLAS_VERSION}.tar.gz" \ | tar -xz -C /tmp \ && cd "/tmp/OpenBLAS-${OPENBLAS_VERSION}" \ + # musl's pthread default stack is 128 KB (vs glibc's 8 MB read from + # RLIMIT_STACK). OpenBLAS worker threads inherit it and overflow on + # DYNAMIC_ARCH Fortran kernels with large auto-arrays → SIGSEGV at the + # first BLAS3 call from MUMPS. Force an 8 MB stack on each worker. + # Guard: fail the build if the upstream anchor disappears so a silent + # OpenBLAS refactor can't reintroduce the crash. + && grep -q 'pthread_attr_init(&attr);' driver/others/blas_server.c \ + && sed -i 's|pthread_attr_init(&attr);|pthread_attr_init(\&attr); pthread_attr_setstacksize(\&attr, 8 << 20);|' driver/others/blas_server.c \ + && grep -q 'pthread_attr_setstacksize(&attr, 8 << 20);' driver/others/blas_server.c \ && make -j"$(nproc)" \ NO_SHARED=1 \ USE_THREAD=1 USE_OPENMP=0 \ From bf4ffd796eb16ba30a0e9fc609a41cc3f097ab5b Mon Sep 17 00:00:00 2001 From: Christophe Combelles Date: Sat, 16 May 2026 17:15:24 +0200 Subject: [PATCH 2/2] rts: return memory to OS faster after parsing spikes Two cheap RTS tweaks (cherry-picked from #59, minus the -M change): - Add -Fd1.0 (GHC 9.10+): decay free heap blocks back to the OS over ~1 idle period instead of the default 4.0, which keeps RSS pinned near peak for minutes after a parsing spike. - -I30 -> -I0.3 (GHC default): trigger idle-time major GC promptly. The previous 30 s deferral hid live-data drops and starved -Fd of free blocks to release. Keeping -M at 75 % of RAM for now: dropping to 50 % may be the right call eventually, but the OpenBLAS musl crash that motivated the change in #59 is fixed independently in the previous commit. Re-evaluate -M once we have RSS curves on the 8 GB target. --- docker/rts-flags.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docker/rts-flags.sh b/docker/rts-flags.sh index 7388a57..c4f1b7f 100755 --- a/docker/rts-flags.sh +++ b/docker/rts-flags.sh @@ -40,7 +40,13 @@ CHUNK_MB=$((NURSERY_MB / 32)) MAX_MB=$((RAM_MB * 3 / 4)) [ $MAX_MB -lt 2048 ] && MAX_MB=2048 -RTS_FLAGS="+RTS -N -M${MAX_MB}M -H${HEAP_MB}M -A${NURSERY_MB}M -n${CHUNK_MB}m -qg0 -c -F1.5 -I30 -RTS" +# -Fd1.0 (GHC 9.10+): return free heap blocks to the OS over ~1 idle period +# instead of holding them indefinitely after a parsing spike. Default decay +# (4.0) keeps RSS pinned near the peak for minutes. +# -I0.3 (GHC default): trigger idle-time major GC promptly. The previous +# -I30 deferred GC for 30 s, hiding live-data drops and starving -Fd of +# free blocks to release. +RTS_FLAGS="+RTS -N -M${MAX_MB}M -H${HEAP_MB}M -A${NURSERY_MB}M -n${CHUNK_MB}m -qg0 -c -F1.5 -Fd1.0 -I0.3 -RTS" echo "RTS_FLAGS=\"$RTS_FLAGS\""