#313 exports-index wiring costs +59G instructions on fasl-replay boot — every micro-model says it should win

open
Opened by atgreen

Follow-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):

Falsified theories, each with evidence:

  1. Removal churn (copy-list on unintern/unexport): counters showed 0 uninterns, 0 unexports across the whole replay.
  2. Item duplication: total items across buckets = 30 for 43 packages.
  3. CL package cons identity split breaking the (eq pkg CL) fast path: probed (:EQ-CL T) through use lists.
  4. GC roots not tracing the new defvars: fence survives 1GB of forced churn, index still resolves.
  5. 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:

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.

Comments (1)

atgreen3993188047

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.