#313 exports-index wiring costs +59G instructions on fasl-replay boot — every micro-model says it should win
openFollow-up to #311's boot profile: the package-scan share. Result of the campaign: find-package DID get its cave#188 fence index (clean win, see below); the exports side (external-symbol-p) is deliberately left LINEAR because wiring it through the new entry-cache/name-index machinery reproducibly costs +59G instructions and no theory survived testing. The machinery itself (ag-pkg-exp-item / ag-pkg-exp-entry / ag-exp-names-*) is committed, probe-validated, and dormant — only the wiring is withheld.
Measurements (cpu_core instructions, asdf.funclfa auto-load boot, idle box, own matching fasl each):
- baseline 7766bcb: 244.0G (10.7s)
-
- find-package index ONLY: 215.8G (-28G, -12%) ← SHIPPED
-
- full exports wiring (entry cache + name buckets): 303.6G (+59G)
-
- entry-cache only (names stay linear): 303.5G — so the poison is in the ITEM/ENTRY-CACHE layer, not the name buckets
- machinery present but unwired: 244.5G — dormant code is free
- bare boot (no fasl): 174M instructions BOTH builds — the delta is 100% replay-side
Falsified theories, each with evidence:
- Removal churn (copy-list on unintern/unexport): counters showed 0 uninterns, 0 unexports across the whole replay.
- Item duplication: total items across buckets = 30 for 43 packages.
- CL package cons identity split breaking the (eq pkg CL) fast path: probed (:EQ-CL T) through use lists.
- GC roots not tracing the new defvars: fence survives 1GB of forced churn, index still resolves.
- Per-call overhead x call count: counters say external-symbol-p = 9.9M calls, find-package = 9.97M, find-symbol-in-pkg = 65K; microbench (2M hot iterations) shows the WIRED path at ~2.2K instructions/call total — the observed delta needs ~6K/call MORE than linear, which the microbench flatly contradicts.
Open leads:
- Attribution inside baked-image code is unreliable (map aliases: a hot region labeled AG-PKG-OWN-CELL-FIND at 23% "calls" functions it cannot call; static ELF symtab aliases the file-backed code mmap). Any further hunt should bench-profile (hot REPL loops + save-perf-map), never trust replay-profile labels for JIT/baked frames.
- Replay-context-dependent cost: same code, same call count, ~3x the instructions vs microbench context. Something about the replay session (patch-list interactions? crossing re-records? trap-routed baked call sites that the bench's REPL-compiled callers don't share?) multiplies the wired path's cost. The #311 full re-walk interacts with everything; re-test after #311 lands.
- Bench-profile bonus finding (SHIPPED): external-symbol-p's CL check ran (find-package "COMMON-LISP") per call — %pkg-canonical-name's two string= probes were ~31% of every call (STRING-CMP2 15.6 + %STRING-DESIGNATOR 12.6 + STRING= 3.1). Now memoized (cl-package-memo).
Also shipped from this campaign: %pkg-name-remove/%pkg-list-remove copy the tail on removal (fence indexes detect shrink by unreachability; call sites guarded so no-op removals never cons); %pkg-alist-remove (unintern) keeps the shared tail deliberately — copying uiop-sized intern tables per unintern is pure churn, and it preserves cave#266's long-standing (never-observed) staleness window.
Lever-(1) prototype result: the reloc resolver is NOT where the 10M find-package calls are
Prototyped the SBCL fop-table idea (resolve each distinct package-scoped symbol once per load, not per relocation site) as a load-wide (name,pkg)->base memo on ag-loader-pkgsym-base, and measured on the REAL asdf.funclfa load.
Mechanism works + correct: on a synthetic 400/800-pkgsym-site module, misses stay FLAT at 1 (O(distinct), not O(sites)); spike fasl round-trips; results correct.
But on real asdf it does NOT move the 148G needle — because ag-loader-pkgsym-base is only 8263 calls on the whole asdf load, while replay = ~148G instr (matches this issue's ~160G). So the ~10M find-package calls are NOT in the reloc resolver — they are in the symbol-interning / quote-pool / external-symbol-p machinery (interning every symbol in every quote reference; external-symbol-p calling find-package). The fop-table fix has to be applied THERE (intern each distinct symbol once per load + back-reference), not at the reloc layer.
Bonus real bug found + fixed (retained): name-keyed callees arrive at ag-loader-pkgsym-base with home-pkg = the STRING "NIL" (not the null object), slipping past the (null home-pkg) guard and driving a doomed find-package("NIL") at EVERY relocation site — O(sites) failed lookups. Added ag-home-pkg-absent-p to treat "NIL" as absent. Regression-clean (spike + pkgsym fasl pass). Small aggregate impact on asdf (only 8263 reloc calls) but it is pure waste elimination.
Note: asdf.funclfa is still cave#148-incomplete (RETURN-FROM-MISS during compile; ASDF pkg absent post-load), so this is a partial-but-148G-heavy replay.