Finding
On a real 44-module / 10,478-LOC API, Perry's per-module object cache works, but a one-file edit still takes 10.16–11.31 s because link/archive processing takes about 8.12 s even when every object is already cached.
This re-measures the link-cache idea discussed in #131 on a substantially larger real application. The old estimate there was about 85 ms and was reasonably deemed marginal. On this target it is no longer marginal.
Reproduction
Host: Apple arm64, macOS 26.5, Perry d1d9929663e6b582e3a743a96f56f9e9a4f93aba.
Target: gscmaster API snapshot, entry src/main.ts, 44 TS modules, 10,478 LOC, 9 direct npm dependencies / 146 installed packages in the supplied graph. Perry selected bundled native shims for the reachable external packages.
Perry was built with the required static wrappers:
CARGO_TARGET_DIR=/Users/amlug/cargo-targets/wsizeaudit \
cargo build --release -p perry -p perry-runtime-static -p perry-stdlib-static
All compiles used the resulting release directory as PERRY_RUNTIME_DIR, a dedicated PERRY_CACHE_DIR, and PERRY_CACHE_DEBUG_KEY=1 for cache evidence.
| Case |
N |
Best–worst wall |
Object result |
Max RSS range |
| unchanged rebuild |
5 |
0.28–0.29 s |
whole-build-cache hit; 44 object mtimes unchanged |
30.08–30.15 MB |
| edit one leaf module |
3 |
10.56–11.31 s |
43 reused, 1 stored each run |
297.9–302.0 MB |
edit db.ts (23 importers) |
3 |
10.16–10.65 s |
43 reused, 1 stored each run |
297.6–303.6 MB |
build cache disabled, all 44 objects hit, --no-link |
1 |
1.47 s |
44 reused |
225.1 MB |
same, but force link with PERRY_NO_LINK_CACHE=1 |
1 |
9.59 s |
44 reused |
297.1 MB |
The isolated link/archive increment is 9.59 - 1.47 = 8.12 s, or 84.7% of the forced all-hit compile. A normal one-file edit cannot use the final-binary build cache because one object changes, so it pays that stage every time.
The dependency fan-out did not invalidate importers: both leaf and 23-importer edits regenerated exactly one object. This is not an object-cache invalidation bug.
Expected direction
Please profile and cache or avoid repeated work in the post-object link/archive path for one-object edits. Possible implementations include caching prepared/strip-deduplicated native archives by exact input fingerprint, or an incremental link strategy. The measurement gives an upper-bound win of about 8.12 s per edited build on this target (roughly 10.6 s down toward 2.5 s if the stage were nearly eliminated).
Acceptance should preserve the current byte-for-byte runtime correctness checks and must not trade runtime instruction count or RSS for build speed.
Finding
On a real 44-module / 10,478-LOC API, Perry's per-module object cache works, but a one-file edit still takes 10.16–11.31 s because link/archive processing takes about 8.12 s even when every object is already cached.
This re-measures the link-cache idea discussed in #131 on a substantially larger real application. The old estimate there was about 85 ms and was reasonably deemed marginal. On this target it is no longer marginal.
Reproduction
Host: Apple arm64, macOS 26.5, Perry
d1d9929663e6b582e3a743a96f56f9e9a4f93aba.Target: gscmaster API snapshot, entry
src/main.ts, 44 TS modules, 10,478 LOC, 9 direct npm dependencies / 146 installed packages in the supplied graph. Perry selected bundled native shims for the reachable external packages.Perry was built with the required static wrappers:
All compiles used the resulting release directory as
PERRY_RUNTIME_DIR, a dedicatedPERRY_CACHE_DIR, andPERRY_CACHE_DEBUG_KEY=1for cache evidence.db.ts(23 importers)--no-linkPERRY_NO_LINK_CACHE=1The isolated link/archive increment is 9.59 - 1.47 = 8.12 s, or 84.7% of the forced all-hit compile. A normal one-file edit cannot use the final-binary build cache because one object changes, so it pays that stage every time.
The dependency fan-out did not invalidate importers: both leaf and 23-importer edits regenerated exactly one object. This is not an object-cache invalidation bug.
Expected direction
Please profile and cache or avoid repeated work in the post-object link/archive path for one-object edits. Possible implementations include caching prepared/strip-deduplicated native archives by exact input fingerprint, or an incremental link strategy. The measurement gives an upper-bound win of about 8.12 s per edited build on this target (roughly 10.6 s down toward 2.5 s if the stage were nearly eliminated).
Acceptance should preserve the current byte-for-byte runtime correctness checks and must not trade runtime instruction count or RSS for build speed.