gqa(adr): ADR-0064/0065 second-pass review — 1024B rationale, FIFO as ordering source, robust formula-based tests, D5/D6 auto-bind alignment

ADR-0064 Revision 2 second-pass review fixes:
- D7 added 1024-byte cap rationale: explicitly framed as a *safe
  engineering limit* (intentionally above all known composites at ~322
  bytes, finite descriptor capacity placeholder), not a measured HW
  number. Default is the discipline; topology override for real HW.
- D7 segment ordering: strict FIFO is the *ordering source*; rw_handles
  is dependency metadata, not the ordering primitive. Explicit note for
  the future RW-aware reorder migration path.
- Tests rewritten around the formula (D1) instead of specific numbers:
  - Test #1 → "formula preservation" (parametrized across composites,
    asserts dispatch == FIXED + bytes × R, not anchor 43 ns).
  - Test #2 → robust "opt3 > 2 × opt2" qualitative gate; ≈ 4.0× is
    informative only, not the gate, so calibration changes don't break.
  - Test #9 → qualitative (opt2 < opt3 at all R), not a numeric ratio.
- Anchor description in D3 stays as *informative* (shows the model
  produces ≈ 43 ns at defaults), but is no longer a test gate.

ADR-0065 second-pass review:
- D5 step 5 aligned with D6.6 invariant: explicit conflict check before
  auto-binding (previously written as if auto-bind always happens).
  Mirrors D6.6 wording: error if both kernel explicit `a` and prologue
  primary_out are present.
- Test #7 made robust: `opt3 > 2 × opt2` gate (was ≈ 4.0×).
  Default-calibration model expectation (≈ 4.0×) recorded as informative
  reference, not the gate.

DDD-0065 follow-on robust thresholds:
- §1.4 success criteria: ratio condition rewritten as `opt3 > 2 × opt2`
  with model-expected ≈ 4.0× as informative.
- §9 P6 phase gate: `opt3 > 2 × opt2` (was 4.0× ± 15%).
- §10 dispatch ratio test: assert `opt3 > 2 × opt2`; record observed
  ratio for performance tracking but do not gate on it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-10 16:34:34 -07:00
parent a8d04750e6
commit 3647e2d8f5
5 changed files with 130 additions and 47 deletions
@@ -251,15 +251,34 @@ per D4). Oversized commands are deterministically **segmented** by the
- The segmentation algorithm is deterministic (greedy by op index in
emit order); it is part of the host emitter, not PE_SCHEDULER.
Why this is needed. Real hardware imposes hard limits — descriptor
**Why a cap is needed.** Real hardware imposes hard limits — descriptor
queue entry size, scheduler parser buffer, command SRAM, firmware
input. Without a cap, the `FIXED + bytes × R` model would reward
arbitrarily large fused composites beyond what hardware accepts (e.g.,
fusing 100 primitive ops into one composite, paying one `FIXED`).
A composite of (say) 100 ops at ~30 bytes each = ~3000 bytes >
1024 cap → segmented into 3 ≈ 3 × FIXED, restoring honest accounting.
Decode opt2's `#2` composite (10 ops, ~310 bytes) sits comfortably
**Why 1024 bytes specifically.** This is a **safe engineering limit**,
not a measured HW number — intentionally chosen to be well above all
currently known composites (decode opt2's `#2` at ~322 bytes is the
largest in the kernbench codebase) while still representing a *finite*
descriptor capacity that future recipes must respect. The number is
overridable per topology (D4); when a real HW reference appears, the
value should be recalibrated. The role of this default is to make the
cap *exist as a discipline*, not to fit a specific HW.
**Ordering of segments — driven by strict FIFO, not `rw_handles`.**
Segments are emitted into the PE_CPU → PE_SCHEDULER queue in their
emit order. Strict-FIFO dispatch (ADR-0065 D6.3) is the *ordering
source*: segments execute in the order they enter the queue. The
`rw_handles` block on each segment is **dependency metadata** for the
cross-composite hazard tracker — it does **not** by itself guarantee
inter-segment ordering. If a future scheduler relaxed FIFO (e.g., to
RW-aware reorder, ADR-0065 A4), the segmenter would need to either
(a) merge segments into a single CompositeCmd, or (b) introduce an
explicit completion-handle dependency chain. For Phase 1 this does
not arise: strict FIFO is in effect.
Decode opt2's `#2` composite (10 ops, ~322 bytes) sits comfortably
inside the 1024 cap — no segmentation for the GQA workload.
## Alternatives
@@ -331,13 +350,27 @@ calibration shows it matters.
## Test Requirements
1. **Anchor preservation.** A single-OpSpec composite for a DMA-staged
GEMM path (`logical_bytes ≈ 54`) dispatches in ≈43 ns at default
values (within ±2 ns).
2. **Structural ratio.** opt3 vs opt2 dispatch (per ADR-0065 §verification):
`opt3 / opt2 ≈ 4.0×` at default calibration.
Tests are written against the **formula** (D1), not against specific
numeric anchors, so they remain valid when calibration changes or when
OpSpec/CompositeCmd fields are added.
1. **Formula preservation.** For any `CompositeCmd` `c`, PE_CPU's
recorded dispatch overhead equals `FIXED_PER_CMD + c.logical_bytes
× R` (within ±1 cycle for floor/round-off). Parametrized over
several composites: a 1-OpSpec GEMM composite, a 5-op MATH chain,
and a 10-op recipe composite. Default-calibration numbers (anchor
≈43 ns for the 1-OpSpec composite) are informative reference, not
the test gate — the test gate is the formula equality.
2. **Qualitative ratio (robust).** opt3 per-tile PE_CPU dispatch
strictly exceeds opt2 per-tile dispatch by at least a 2× margin —
`opt3 > 2 × opt2`. The default-calibration model predicts ≈4×;
the gate is the loose 2× bound so the test does not break when
calibration is moved (e.g., when a HW reference replaces the
default). Informative numbers — see ADR-0065 §verification and
DDD-0065 §11 for the model expectation.
3. **Override path.** Topology yaml `pe_cost_model:` block changes the
per-PE dispatch cost; default is recovered when block is missing.
The formula identity from #1 must hold with the override values.
4. **`PeCpuOverheadCmd` bypass.** Manual `tl.cycles(n)` issues exactly `n`
cycles, not `n + dispatch_cycles(...)`.
5. **No double-count.** PE_DMA `drain_ns`, PE_GEMM/MATH `_compute_ns`
@@ -348,12 +381,14 @@ calibration shows it matters.
dispatch-cycle accounting for the same kernel.
8. **Composite size cap (D7).** A recipe that would emit `logical_bytes
> MAX_COMPOSITE_LOGICAL_BYTES` is segmented into N consecutive
`CompositeCmd`s; total dispatch = sum of segment dispatches; RW
ordering across segments preserved by strict FIFO.
9. **Sensitivity sweep.** At `R ∈ {0.25, 0.0625, 0.03125}` cycles/byte
(= 4 / 16 / 32 bytes/cycle), the conclusion *opt2 per-tile dispatch
< opt3 per-tile dispatch* must hold (ratio monotonically increases
as R decreases — FIXED dominates more).
`CompositeCmd`s; `sum(segment.logical_bytes) == original
logical_bytes`; total dispatch = sum of segment dispatches (FIXED
paid per segment); inter-segment ordering preserved by strict FIFO
(not by `rw_handles` alone).
9. **Sensitivity (qualitative).** At `R ∈ {0.25, 0.0625, 0.03125}`
cycles/byte, `opt3 > opt2` at *all* three points. Direction (ratio
monotonically increases as R decreases) is also asserted, but
absolute ratio values are *not* required.
## Migration