gqa(decode-4cases): Case 1 — Cube-SP × PE-TP (inter-CUBE lrab only; PE-TP B=1 waste) (5C.A)
Adds the fourth and final 4-cases panel: KV split S_kv-wise across the 8 cubes (cube=row_wise, S_local = S_kv/C), replicated within each cube (pe=replicate). PE-TP at B=1 means only PE 0 of each cube has work; PEs 1-7 early-return (slide-11 PE-TP-at-B=1 waste). No intra-CUBE comm; inter-CUBE 8-way reduce reuses the lrab-adapted center-root pattern (root cube 6) — same structural cost as Case 4's inter-CUBE phase (21 ipcq_copy). 16 tests pass (4 per case). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,7 @@ TOPOLOGY_DEFAULT = Path(__file__).resolve().parents[2] / "topology.yaml"
|
||||
_CASE4_PANEL = "single_kv_group_decode_gqa_cube_sp_pe_sp"
|
||||
_CASE3_PANEL = "single_kv_group_decode_gqa_cube_repl_pe_sp"
|
||||
_CASE2_PANEL = "single_kv_group_decode_gqa_cube_repl_pe_tp"
|
||||
_CASE1_PANEL = "single_kv_group_decode_gqa_cube_sp_pe_tp"
|
||||
_CUBE_RE = re.compile(r"\bcube(\d+)\b")
|
||||
|
||||
|
||||
@@ -384,6 +385,126 @@ def test_case3_single_dma_write_at_cube_0():
|
||||
)
|
||||
|
||||
|
||||
# ── Case 1 (Cube-SP × PE-TP) ────────────────────────────────────────
|
||||
|
||||
|
||||
def _run_case1_smoke(*, S_kv: int):
|
||||
"""Drive the Case 1 decode panel via the case-specific runner.
|
||||
|
||||
Case 1 = Cube-SP × PE-TP. K, V split S_kv-wise across the 8 cubes
|
||||
(cube=row_wise), replicated within each cube (pe=replicate). PEs
|
||||
nominally split on the batch dim (PE-TP); at B=1 only PE 0 of
|
||||
each cube has work; PEs 1-7 idle. Inter-CUBE 8-way reduce via the
|
||||
lrab-adapted center-root pattern (root cube 6); no intra-CUBE comm.
|
||||
"""
|
||||
from kernbench.benches.milestone_gqa_decode_4cases import (
|
||||
_run_decode_panel_cube_sp_pe_tp,
|
||||
)
|
||||
topo = resolve_topology(str(TOPOLOGY_DEFAULT))
|
||||
|
||||
def _bench_fn(ctx):
|
||||
_run_decode_panel_cube_sp_pe_tp(
|
||||
ctx, panel=_CASE1_PANEL,
|
||||
C=8, P=8,
|
||||
T_q=1, S_kv=S_kv,
|
||||
d_head=128, h_q=8, h_kv=1,
|
||||
)
|
||||
|
||||
return run_bench(
|
||||
topology=topo, bench_fn=_bench_fn,
|
||||
device=resolve_device(None),
|
||||
engine_factory=_engine_factory,
|
||||
)
|
||||
|
||||
|
||||
# ── Case 1 — T1: panel registered ───────────────────────────────────
|
||||
|
||||
|
||||
def test_case1_panel_registered():
|
||||
"""The Case 1 panel must be in the bench's ``_PANELS`` +
|
||||
``_PANEL_DISPATCH`` with the expected single-KV-group dims.
|
||||
|
||||
Case 1: Cube-SP × PE-TP. K, V split across cubes; PEs TP on
|
||||
batch. At B=1 only PE 0 of each cube works (PE-TP waste).
|
||||
Inter-CUBE lrab AR; no intra-CUBE comm.
|
||||
"""
|
||||
from kernbench.benches.milestone_gqa_decode_4cases import (
|
||||
_PANEL_DISPATCH,
|
||||
_PANELS,
|
||||
)
|
||||
assert _CASE1_PANEL in _PANELS, (
|
||||
f"{_CASE1_PANEL!r} not in _PANELS; got {_PANELS}"
|
||||
)
|
||||
assert _CASE1_PANEL in _PANEL_DISPATCH
|
||||
kind, params = _PANEL_DISPATCH[_CASE1_PANEL]
|
||||
assert kind == "decode_cube_sp_pe_tp"
|
||||
assert params.get("C") == 8
|
||||
assert params.get("P") == 8
|
||||
assert params.get("T_q") == 1
|
||||
assert params.get("S_kv") == 131_072
|
||||
assert params.get("d_head") == 128
|
||||
assert params.get("h_q") == 8
|
||||
assert params.get("h_kv") == 1
|
||||
|
||||
|
||||
# ── Case 1 — T2: smoke runner completes ─────────────────────────────
|
||||
|
||||
|
||||
def test_case1_runner_smoke():
|
||||
"""Case 1 runner drives the new kernel to completion at smoke S_kv."""
|
||||
result = _run_case1_smoke(S_kv=8192)
|
||||
assert result.completion.ok, (
|
||||
f"Case 1 decode smoke at C=8 P=8 must complete; "
|
||||
f"got {result.completion}"
|
||||
)
|
||||
|
||||
|
||||
# ── Case 1 — T3: inter-CUBE lrab only (21 ipcq, no intra-CUBE) ──────
|
||||
|
||||
|
||||
def test_case1_inter_cube_lrab_only_ipcq():
|
||||
"""Case 1 reduce pattern: only PE 0 of each cube has work (PE-TP
|
||||
at B=1), so NO intra-CUBE AR. Inter-CUBE 8-way reduce uses the
|
||||
lrab-adapted center-root pattern (same structural cost as Case 4's
|
||||
inter-CUBE phase).
|
||||
|
||||
Inter-CUBE lrab (sub_w=4, sub_h=2):
|
||||
Phase 1 row reduce — 3 sends/row × 3 tensors × 2 rows = 18
|
||||
Phase 2 col reduce — cube 2 → S × 3 tensors = 3
|
||||
inter-CUBE total = 21
|
||||
|
||||
Intra-CUBE: 0 (PEs 1-7 idle, no partials to merge).
|
||||
|
||||
Grand total: 21.
|
||||
"""
|
||||
result = _run_case1_smoke(S_kv=8192)
|
||||
assert result.completion.ok
|
||||
n_copy = _count(result.engine.op_log, "ipcq_copy")
|
||||
assert n_copy == 21, (
|
||||
f"Case 1 expected 21 ipcq_copy (inter-CUBE lrab only, no intra-CUBE); "
|
||||
f"got {n_copy}"
|
||||
)
|
||||
|
||||
|
||||
# ── Case 1 — T4: root at lrab center cube 6 ─────────────────────────
|
||||
|
||||
|
||||
def test_case1_root_at_center_cube_6():
|
||||
"""Case 1 uses the same lrab-adapted center-root reduce as Case 4's
|
||||
inter-CUBE phase; the answer lands at the lrab center cube
|
||||
(sub_w=4, sub_h=2 → root_col=2, root_row=1 → root_cube=6).
|
||||
"""
|
||||
result = _run_case1_smoke(S_kv=8192)
|
||||
assert result.completion.ok
|
||||
cubes = _dma_write_cubes(result.engine.op_log)
|
||||
assert cubes, "expected at least one dma_write for the final O store"
|
||||
distinct = set(cubes)
|
||||
assert distinct == {6}, (
|
||||
f"Case 1 root must be the lrab center cube 6; "
|
||||
f"got cubes={sorted(distinct)}"
|
||||
)
|
||||
|
||||
|
||||
# ── Case 4 — T4 (existing, kept) ────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user