#331 A2 Stage C: co-located GOT (per-CO linkage slots) for O(symbols) load — the C .so model

open
Opened by atgreen

The A2 linkage table is O(sites) at load because slots are re-emitted at a load-time offset -> per-site disp32 re-resolution (KIND-9). To get the C .so property (O(symbols) load, call sites INERT), CO-locate each CO's slots inside its code range and bake the disp32; the fasl carries a KIND-10 slot-fill reloc and the loader fills only the O(names-in-CO) slot VALUES.

Codex-validated design (per-CO). 5-step plan:

  1. CO-local linkage state (save/reset/restore ag-linkage- in emit-ir-defun-to-co).
  2. Emit 8-byte slots AFTER the function body, inside [start,end).
  3. Bake the mov disp32s to those in-CO slots immediately (ag-resolve-linkage-patches).
  4. Record a KIND-10 reloc at each SLOT (width 8), not the call site.
  5. Loader KIND-10 arm: resolve NAME -> base, patch-u64-at the slot. Call sites untouched. => fixed-name/growing-site (N sites, 1 name, 1 CO) -> 1 loader patch, 0 site touches = flat.

Behind ag-linkage-coloc-p (default nil). Caveats: DWARF fn-length counts trailing slots (tolerable first cut); per-CO duplicates names shared across COs (O(sum names-in-CO), not global O(names)); new KIND-10 (not KIND-9 reuse). Related: #319, #330 (KIND-8 width).

Comments (2)

atgreen3993159461

Coloc measurement: works, but aimed at the wrong channel

Built the full co-located GOT (KIND-10) and measured a 400-(car x)-site module. Reloc histogram of the produced .funclfa:

  • 403 x KIND-7 (per-site name-keyed rel32 call re-resolve — ag-resolve-call-rel32, compiler.lisp:3104)
  • 1 x KIND-10 (the co-located cell-base slot — coloc DID collapse 400 base-loads -> 1 shared slot)
  • 1 x KIND-5 (a string)

Conclusion: coloc is correct and engages (COLOC-CO fires; 1 KIND-10 proves the 400->1 collapse on the cell-base channel). But the O(sites) load tax is KIND-7, a channel coloc never touched. (ag-quote-pkgsym-p CAR)=0, so CL-package calls ride the name-keyed rel32 path, whose loader arm (ag-loader-pkgsym-call-target, cold-loader.lisp:363) does a package-scoped intern + fn-cell read + patch per call site — re-resolving car 400 times. That is the ~14.6K instr/site.

The co-located GOT is the right cure but must be applied to the KIND-7 channel, not KIND-9. Reverted ag-linkage-coloc-p default -> nil (byte-identical build restored; spike fasl round-trips TT 4242 4242 TT). The 6-part coloc restructuring stays in-tree, dormant, as the vehicle for the KIND-7 retarget.

Real fix options: (a) route the name-keyed call through a co-located entry-slot (indirect call [rip+disp32], slot filled once per name); or (b) fix cave#316 so the baked-cell fallback uses the shared closure stub (no per-site KIND-7).

atgreen3993184778

Conclusion: the linkage/call channel is NOT the replay lever — stop here

Followed the KIND-7 thread to its root and cross-checked against the prior replay-profiling data (#313). Verdict: the entire linkage/call channel is <0.5% of real asdf replay cost. Neither coloc (KIND-9->KIND-10) nor a KIND-7 resolution cache is worth shipping.

Evidence chain:

  • Real alexandria/lists.lisp fasl: 1599 KIND-7 sites but only 28 distinct names (dominated by resident signallers: FUNCL-RAISE-NOT-LIST 677, AG-LINKAGE-BIND 441, LIST 334, FUNCL-RAISE-ARITY-ERROR 64). car itself is already O(names) via the cell-first arm — no KIND-7.
  • Measured toy replay: 400 sites add only 5.8M instructions over a 361M boot (~14.6K/site). Per-site cost is real but the channel is tiny.
  • #313 already measured the REAL workload: asdf.funclfa replay = 244G instr (10.7s), bare boot = 174M, so ~100% is replay-side, and it is package machinery (find-package 9.97M calls, external-symbol-p 9.9M calls). KIND-7 at asdf scale is ~0.5-0.7G = under 0.5%.

A load-time KIND-7 resolution cache is provably correct (ag-fn-add is the sole fn-table mutation point -> invalidate there) and I had it designed, but it optimizes noise. Not building it.

Recommendation: close the coloc/A2-Stage-C linkage-perf thread. The 'fractions of a second' vehicle is #314 (image data-core: 1.17s vs 10s, ~9x), blocked by the save-image-from-restored-session package-side-table corruption (nicknames empty, uses cross-wired). That is where the perf gains actually come from. Reverting the uncommitted coloc restructuring to restore clean committed state (54d992b) pending user confirmation.