Commit Graph
3 Commits
Author SHA1 Message Date
27c3c55436 perf(resolution): darwin-honest memory budget — vm_stat-based availability unstrangles the resolver pool on macOS (#1388)
Post-R7b store-arc round 1, found by the dubbo warm-wall decomposition
(the cbm bar): resolution's loop-stage profile showed settle=3.0s — the
main thread idling on TWO resolver workers on an 11-core Mac. Pool sizing
logged `size=2 (budget=1068MB)`: memoryBudgetBytes() falls back to
os.freemem() when uncontained, and macOS keeps RAM deliberately full of
reclaimable cache, so freemem reads ~1GB on a mostly-idle 64GB machine.
The memory term then capped the pool at 2 where the CPU term allowed 6 —
the macOS sibling of §7a.1's os.cpus() cpuset-blindness (that round fixed
the CPU term; this fixes the memory term).

Fix: darwinMemoryAvailable() reads /usr/bin/vm_stat once per sizing call
and reports free + inactive + speculative + purgeable pages — what
Activity Monitor calls available, the same reclaimable-inclusive
convention the Linux branch already uses by crediting inactive_file back.
Parse failure → null → freemem fallback; Linux/cgroup and Windows paths
untouched.

Measured (dubbo 4,402 files, warm, caffeinated, n=3 each): pool now
self-sizes to 6 (budget 5.7-6.3GB) — wall 8.62-8.83s vs 9.67-10.87s
baseline, resolution phase 6.9→5.3s, loop settle 3.0→1.9s. Matches the
CODEGRAPH_RESOLVE_WORKERS=6 probe exactly (probe-before-build). Dumps
byte-identical pool-6 vs sequential (441,270 lines). Second consumer
unblocked: the cFnPtr LRU cache cap no longer spuriously degrades to 128
on Macs (its full-cache tier is worth ~60s at kernel scale).

Suite: resolver-pool-sizing gains a darwin-gated reclaimable-pages test +
an off-darwin null pin; full suite 2,689 green ×2 with
CODEGRAPH_KERNEL_EXPECT=1.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 20:11:31 -05:00
ca88d3bd15 fix(db,resolution): WAL file cap + cgroup cache credit + pool/parse sizing corrections from the instrumented kernel-scale runs (#1335)
Four §7a.1 instrumented-run findings, each measured:

1. File-size trigger + truncate-at-barrier: a fully-backfilled WAL still
   grows the FILE without bound — the writer only restarts at frame 0 when a
   commit finds zero reader marks, which the instrumented run showed never
   happens (file marched 361→721MB through two COMPLETE backfills; 22GB by
   phase end). backpressure() now also trips at 4× the soft cap on raw file
   size and TRUNCATEs at the parked barrier; the timer path truncates
   opportunistically after complete backfills. Dubbo peak: 251MB → 69MB at
   the same 16MB valve; dumps byte-identical under aggressive folding.

2. cgroup memory credit: memory.current counts reclaimable page cache — a
   post-parse container read 57MB of headroom on a 6GB box and silently
   disabled the pool. inactive_file is credited back (the docker-stats
   working-set convention); the same run now reads a sane 4.4GB budget.

3. Pool at 2 cores reversed: sequential resolution measured FASTER than
   pooled-6-on-2 at kernel scale (853s vs 1,150s), and synthesis is
   Amdahl-bound by cFnPtrEdges (306s of 358s) so pooling it bought nothing.
   cpuCap = min(ap−1, 6), no floor: ap=2 → sequential is the fast path.

4. Parse floor of 2: one parse worker at a 2-cpuset measured 34% slower
   (493s vs 369s) — main + store-worker don't fill the second core. Floor
   restores the baseline (373.5s measured).

Plus the observability §7a.1 burned three 25-minute cycles for: valve
armed/fire/timer-pass/heartbeat lines, checkpoint-worker error capture,
pool sizing decisions (incl. the disabled path), backpressure-hook
presence — all behind CODEGRAPH_SYNTH_TIMINGS / CODEGRAPH_WAL_VALVE_DEBUG.

Suite: 2,490 passed / 4 skipped (kernel required). Kernel-scale record
runs with this build follow in the migration plan §7a.1.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 08:56:26 -05:00
b8833fec57 feat(resolution): memory-aware, cgroup-honest worker-pool sizing + CODEGRAPH_RESOLVE_WORKERS (#1333)
Pool sizing used os.cpus().length, which enumerates the HOST's CPUs: inside
a 2-CPU cpuset it sized 6 resolver workers (the §7a.1 false-'sequential'
premise) and 8 parse workers, and at true 8-core concurrency six ~1GB
workers OOM-killed a 7GB container (oom_kill=5) mid-synthesis — sizing had
no memory term and no override knob.

resolvePoolSize (pure, matrix-tested): explicit CODEGRAPH_RESOLVE_WORKERS
override (0 disables, cap 16); CPU term max(2, min(availableParallelism-1,
6)) — cpuset-honest, floored at 2 so true 2-core boxes keep pooled
synthesis's ~2×; memory term floor(budget*0.7 / clamp(0.2*dbSize, 256MB,
1.5GB)) with budget = min(freemem, cgroup v2/v1 headroom). Parse pool's
core input switches to availableParallelism. Dev machines are unchanged
(still 6 workers); the 8c/7GB kernel-scale container now sizes 4.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 07:54:31 -05:00