fix: FreeBSD compile-program hang with large import closure (issue #78) #79

Merged
ober merged 2 commits from fix/issue-78-freebsd-compile-program-hang into master 2026-09-17 11:38:13 -04:00
Owner

Summary

Fixes #78 — jerbuild build hangs forever in [1/5] compile-program on FreeBSD amd64 (Chez 10.4.0 ta6fb).

Root cause

Chez 10.4.0 compile-program with a large import closure (194+ modules) enters an infinite loop on the ta6fb (FreeBSD amd64 x86_64) machine-type. The same sources complete in ~2 minutes on macOS tarm64osx.

Symptoms: child process at 99% CPU, RSS oscillates 4.5–5.5 GB, program.so stays 0 bytes. The freeze occurs in compile-program (and compile-file of the entry) regardless of optimize-level, cp0-effort-limit, or GC tuning. Individual library compilation (compile-file per-module) works correctly.

Diagnostic evidence:

  • DTrace stack sampling shows the process stuck in sweep_generation/copy/S_find_segments (GC churn) with intermittent mutator frames in process-impspecs and do-compile-file
  • The freeze reproduces on biggus (FreeBSD 15.1 amd64, 133 GB RAM)
  • Confirmed via DTrace GC-phase probes: gen-0 GCs complete in ~3ms every ~7ms (healthy GC — the mutator is the culprit)
  • Combination of 194 user libraries + bundle libraries triggers the bug; individual compile-file works
  • Pre-loading all .so files into the library table before compile-program does not prevent the freeze
  • optimize-level 0, cp0-effort-limit 0, collect-trip-bytes (expt 2 31), and (compile-imported-libraries #f) all still freeze

Fix

Add JERBOA_BINARY_FORCE_INPROCESS=1 env var. When set, the binary build uses the in-process compilation path (same as non-multicall builds) instead of spawning a fresh subprocess. The in-process path runs inside the existing jerbuild image, which already has the bundle stdlib libraries loaded. This means compile-program only processes the user library closure (smaller), bypassing the closure size threshold that triggers the FreeBSD Chez bug.

Usage:

JERBOA_BINARY_FORCE_INPROCESS=1 gmake binary

Verification

  • make binary builds and links successfully on macOS (arm64)
  • The env var defaults to unset, preserving existing behavior on all other platforms
  • FreeBSD amd64 users should set the env var and report results

Long-term

This is ultimately a Chez 10.4.0 ta6fb code-generation or import-resolution bug. A proper fix may require a Chez upgrade or a ta6fb-specific patch to the vendored Chez source. The env var workaround lets FreeBSD users build binaries today.

## Summary Fixes https://git.jerboa.sh/ober/jerboa/issues/78 — `jerbuild build` hangs forever in `[1/5] compile-program` on FreeBSD amd64 (Chez 10.4.0 ta6fb). ## Root cause Chez 10.4.0 `compile-program` with a large import closure (194+ modules) enters an infinite loop on the `ta6fb` (FreeBSD amd64 x86_64) machine-type. The same sources complete in ~2 minutes on macOS `tarm64osx`. Symptoms: child process at 99% CPU, RSS oscillates 4.5–5.5 GB, `program.so` stays 0 bytes. The freeze occurs in `compile-program` (and `compile-file` of the entry) regardless of `optimize-level`, `cp0-effort-limit`, or GC tuning. Individual library compilation (`compile-file` per-module) works correctly. Diagnostic evidence: - DTrace stack sampling shows the process stuck in `sweep_generation`/`copy`/`S_find_segments` (GC churn) with intermittent mutator frames in `process-impspecs` and `do-compile-file` - The freeze reproduces on `biggus` (FreeBSD 15.1 amd64, 133 GB RAM) - Confirmed via DTrace GC-phase probes: gen-0 GCs complete in ~3ms every ~7ms (healthy GC — the mutator is the culprit) - Combination of 194 user libraries + bundle libraries triggers the bug; individual `compile-file` works - Pre-loading all `.so` files into the library table before `compile-program` does not prevent the freeze - `optimize-level 0`, `cp0-effort-limit 0`, `collect-trip-bytes (expt 2 31)`, and `(compile-imported-libraries #f)` all still freeze ## Fix Add `JERBOA_BINARY_FORCE_INPROCESS=1` env var. When set, the binary build uses the in-process compilation path (same as non-multicall builds) instead of spawning a fresh subprocess. The in-process path runs inside the existing jerbuild image, which already has the bundle stdlib libraries loaded. This means `compile-program` only processes the user library closure (smaller), bypassing the closure size threshold that triggers the FreeBSD Chez bug. Usage: ```sh JERBOA_BINARY_FORCE_INPROCESS=1 gmake binary ``` ## Verification - `make binary` builds and links successfully on macOS (arm64) - The env var defaults to unset, preserving existing behavior on all other platforms - FreeBSD amd64 users should set the env var and report results ## Long-term This is ultimately a Chez 10.4.0 ta6fb code-generation or import-resolution bug. A proper fix may require a Chez upgrade or a ta6fb-specific patch to the vendored Chez source. The env var workaround lets FreeBSD users build binaries today.
fix: FreeBSD compile-program hang with large import closure (issue #78)
Some checks failed
version-policy / required (pull_request) Failing after 3m55s
required-ci / gerbil-compat (pull_request) Successful in 4m7s
freebsd-required / required (pull_request) Successful in 18m26s
required-ci / required (pull_request) Has been cancelled
dtrace / freebsd-usdt (pull_request) Has been cancelled
c29229fe38
On FreeBSD ta6fb, Chez 10.4.0 compile-program with a large import
closure (194+ modules) freezes forever with GC churn. The same sources
complete in ~2 min on macOS.

Fix: add JERBOA_BINARY_FORCE_INPROCESS=1 env var. When set, the binary
build uses the in-process compilation path even for multicall builds,
avoiding the fresh-subprocess code path that triggers the Chez bug.
fix: replace python3 version check with POSIX sh comparison
Some checks failed
freebsd-required / required (pull_request) Failing after 3m44s
dtrace / freebsd-usdt (pull_request) Failing after 3m44s
version-policy / required (pull_request) Failing after 3m45s
required-ci / gerbil-compat (pull_request) Successful in 3m59s
required-ci / required (pull_request) Successful in 19m13s
eb4b69770e
FreeBSD CI runners may not have python3, causing the version-policy
check to fail. Use a simple POSIX-sh numeric comparison instead.
ober force-pushed fix/issue-78-freebsd-compile-program-hang from eb4b69770e
Some checks failed
freebsd-required / required (pull_request) Failing after 3m44s
dtrace / freebsd-usdt (pull_request) Failing after 3m44s
version-policy / required (pull_request) Failing after 3m45s
required-ci / gerbil-compat (pull_request) Successful in 3m59s
required-ci / required (pull_request) Successful in 19m13s
to 6fabbceaf7
All checks were successful
required-ci / gerbil-compat (pull_request) Successful in 4m14s
version-policy / required (pull_request) Successful in 5m50s
freebsd-required / required (pull_request) Successful in 14m16s
dtrace / freebsd-usdt (pull_request) Successful in 16m35s
required-ci / required (pull_request) Successful in 18m3s
2026-09-17 11:34:54 -04:00
Compare
ober scheduled this pull request to auto merge when all checks succeed 2026-09-17 11:37:54 -04:00
ober merged commit 5151233334 into master 2026-09-17 11:38:13 -04:00
ober referenced this pull request from a commit 2026-09-17 11:38:13 -04:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ober/jerboa!79
No description provided.