gqa(decode-4cases): Case 4 anchor in dedicated bench (5C.D)
First milestone of the decode 4-cases comparative study per GQA_full_deck.pptx slides 11-17. Case 4 (Cube-SP × PE-SP, the optimal case per slide 11) is structurally the existing _gqa_attention_decode_long at sub_w=4 (Increment 2's lrab-adapted center-root reduce). This commit wires it into a dedicated bench so the remaining cases land alongside. Changes: - New bench: src/kernbench/benches/milestone_gqa_decode_4cases.py Houses the 4 case panels under one milestone-gqa-decode-4cases entry (gated by GQA_DECODE_4CASES_RUN=1; output to 1H_milestone_output/gqa_decode_4cases/sweep.json). Cases 1-3 are TBD in subsequent sub-increments (5C.A/B/C). - New panel: single_kv_group_decode_gqa_cube_sp_pe_sp C=8, P=8, sub_w=4, T_q=1, S_kv=131_072, d_head=128, h_q=8, h_kv=1. - src/kernbench/benches/milestone_gqa_headline.py: _run_decode_panel extended with keyword-only sub_w/T_q/d_head/h_q/h_kv overrides (defaults preserve existing-panel behaviour). - tests/attention/test_milestone_gqa_decode_4cases.py: 4 new tests asserting registration, smoke completion, reduce-to-root at the lrab center cube (cube 6), and the predicted 189-ipcq Case-4 traffic pattern (168 intra-CUBE + 21 inter-CUBE lrab Phase 1+2). - tests/attention/test_milestone_gqa_headline.py: rename test_sweep_json_has_four_panels -> test_sweep_json_has_expected_panels and switch hardcoded 4 to len(PANELS) (the panel set grew to 5 with Increment 5's single_kv_group_prefill_gqa_c8_p8). Deviation noted: slide 13 prescribes AllReduce on (m,ℓ,O); our kernel does reduce-to-root (only the lrab center cube has the answer) per ADR-0060 §4. Treated as the kernbench Case-4 baseline. Verification: all 4 new tests pass; 90 regression tests pass; the previously-failing test_sweep_json_has_four_panels now passes under its renamed form. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
"""milestone-gqa-decode-4cases: comparative study of 4 decode sharding cases.
|
||||
|
||||
Per GQA_full_deck.pptx slides 11-17: 4 KV-cache sharding strategies on
|
||||
the LLaMA-3.1-70B single-KV-head group (8 cubes × 8 PEs):
|
||||
|
||||
Case 1 Cube-SP / PE-TP → KV split by S_kv across cubes; PEs TP on batch
|
||||
Case 2 Cube-Repl / PE-TP → full KV per cube; PEs TP on batch
|
||||
Case 3 Cube-Repl / PE-SP → full KV per cube; PEs SP on S_kv (intra-cube AR)
|
||||
Case 4 Cube-SP / PE-SP → KV split 64-way; 2-phase AR on (m,ℓ,O) ★ optimal
|
||||
|
||||
Each case is a separate panel. The bench drives all panels in one
|
||||
invocation and writes per-panel op_log_summary to sweep.json so the
|
||||
comparative analysis (latency, GEMM/MAC util, comm volume) can be
|
||||
generated from a single sweep.
|
||||
|
||||
Status (initial commit, 5C.D):
|
||||
- Case 4 panel implemented (uses _gqa_attention_decode_long with
|
||||
sub_w=4 — ADR-0060 §4.2 lrab-adapted center-root reduce; that is
|
||||
structurally Case 4 per slide 11 with the reduce-to-root variant
|
||||
of the AR pattern).
|
||||
- Cases 1-3 panels: TBD in subsequent sub-increments (5C.A/B/C).
|
||||
|
||||
Deviation from slide 13: slide prescribes AllReduce (every rank has
|
||||
the answer); the kernel does reduce-to-root (only the lrab center
|
||||
cube has it) per ADR-0060 §4. Treated as the kernbench Case-4 baseline.
|
||||
|
||||
Gated by ``GQA_DECODE_4CASES_RUN=1``.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from kernbench.benches.milestone_gqa_headline import (
|
||||
_ccl_cfg,
|
||||
_run_decode_panel,
|
||||
_summarize_op_log,
|
||||
)
|
||||
from kernbench.benches.registry import bench
|
||||
|
||||
_OUTPUT_DIR = (
|
||||
Path(__file__).resolve().parent
|
||||
/ "1H_milestone_output"
|
||||
/ "gqa_decode_4cases"
|
||||
)
|
||||
_SWEEP_JSON = _OUTPUT_DIR / "sweep.json"
|
||||
|
||||
|
||||
# ── Panel registry ───────────────────────────────────────────────────
|
||||
|
||||
|
||||
_PANELS = (
|
||||
"single_kv_group_decode_gqa_cube_sp_pe_sp", # Case 4
|
||||
# Cases 1-3 to be added by 5C.A/B/C
|
||||
)
|
||||
|
||||
# Each entry: (kind, panel-specific params for _run_decode_panel).
|
||||
# LLaMA-3.1-70B single-KV-head group target:
|
||||
# 1 KV head, h_q = 8 (G = 8 group), d_head = 128
|
||||
# 8 cubes (head-parallel group), 8 PEs/cube
|
||||
# S_kv = 128K (long-context decode), T_q = 1 (one new token per pass)
|
||||
_PANEL_DISPATCH: dict[str, tuple[str, dict]] = {
|
||||
"single_kv_group_decode_gqa_cube_sp_pe_sp": ("decode", {
|
||||
# Case 4: KV split 64-way (Cube-SP × PE-SP), 2-level reduce.
|
||||
# sub_w=4 ⇒ sub_h=2 ⇒ lrab center-root cube = (1,2) = cube 6.
|
||||
"C": 8, "P": 8, "sub_w": 4,
|
||||
"T_q": 1, "S_kv": 131_072,
|
||||
"d_head": 128, "h_q": 8, "h_kv": 1,
|
||||
}),
|
||||
}
|
||||
|
||||
|
||||
# ── Per-panel runner ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _make_bench_fn(panel: str):
|
||||
kind, params = _PANEL_DISPATCH[panel]
|
||||
|
||||
def _bench_fn(ctx):
|
||||
if kind == "decode":
|
||||
_run_decode_panel(ctx, panel=panel, **params)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
f"milestone-gqa-decode-4cases panel {panel!r} has "
|
||||
f"unsupported kind={kind!r}; only 'decode' is allowed."
|
||||
)
|
||||
return _bench_fn
|
||||
|
||||
|
||||
def _run_panel(panel: str, topology: str) -> dict:
|
||||
from kernbench.runtime_api.bench_runner import run_bench
|
||||
from kernbench.runtime_api.types import resolve_device
|
||||
from kernbench.sim_engine.engine import GraphEngine
|
||||
from kernbench.topology.builder import resolve_topology
|
||||
|
||||
topo = resolve_topology(topology)
|
||||
result = run_bench(
|
||||
topology=topo, bench_fn=_make_bench_fn(panel),
|
||||
device=resolve_device(None),
|
||||
engine_factory=lambda t, d: GraphEngine(
|
||||
getattr(t, "topology_obj", t), enable_data=True,
|
||||
),
|
||||
)
|
||||
if not result.completion.ok:
|
||||
raise RuntimeError(
|
||||
f"milestone-gqa-decode-4cases panel {panel!r} failed: "
|
||||
f"{result.completion}"
|
||||
)
|
||||
kind, params = _PANEL_DISPATCH[panel]
|
||||
return {
|
||||
"panel": panel,
|
||||
"kind": kind,
|
||||
**params,
|
||||
"op_log_summary": _summarize_op_log(result.engine.op_log),
|
||||
}
|
||||
|
||||
|
||||
# ── Bench entry ──────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@bench(
|
||||
name="milestone-gqa-decode-4cases",
|
||||
description=(
|
||||
"Comparative decode study of 4 KV-cache sharding cases on the "
|
||||
"LLaMA-3.1-70B single-KV-head group (8 cubes × 8 PEs)."
|
||||
),
|
||||
)
|
||||
def run(torch) -> None:
|
||||
"""Drive the registered decode case panels; write sweep.json.
|
||||
|
||||
Gated by GQA_DECODE_4CASES_RUN=1.
|
||||
"""
|
||||
_OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
if not os.environ.get("GQA_DECODE_4CASES_RUN"):
|
||||
raise RuntimeError(
|
||||
"milestone-gqa-decode-4cases needs GQA_DECODE_4CASES_RUN=1."
|
||||
)
|
||||
|
||||
topology = os.environ.get(
|
||||
"GQA_DECODE_4CASES_TOPOLOGY", "topology.yaml",
|
||||
)
|
||||
rows = [_run_panel(panel, topology) for panel in _PANELS]
|
||||
sweep = {
|
||||
"version": 1,
|
||||
"panels": list(_PANELS),
|
||||
"rows": rows,
|
||||
}
|
||||
_SWEEP_JSON.write_text(json.dumps(sweep, indent=2))
|
||||
print(
|
||||
f" milestone-gqa-decode-4cases: {len(rows)} rows -> {_SWEEP_JSON}"
|
||||
)
|
||||
@@ -143,24 +143,31 @@ def _run_prefill_panel(
|
||||
)
|
||||
|
||||
|
||||
def _run_decode_panel(ctx, *, panel: str, C: int, P: int, S_kv: int) -> None:
|
||||
def _run_decode_panel(
|
||||
ctx, *, panel: str, C: int, P: int, S_kv: int,
|
||||
sub_w: int = 0,
|
||||
T_q: int = _T_Q_DECODE,
|
||||
d_head: int = _D_HEAD,
|
||||
h_q: int = _H_Q_DECODE,
|
||||
h_kv: int = _H_KV_DECODE,
|
||||
) -> None:
|
||||
configure_sfr_intercube_multisip(ctx.engine, ctx.spec, _ccl_cfg())
|
||||
dp_full = DPPolicy(cube="replicate", pe="replicate",
|
||||
num_cubes=C, num_pes=P)
|
||||
dp_kv = DPPolicy(cube="row_wise" if C > 1 else "replicate",
|
||||
pe="row_wise", num_cubes=C, num_pes=P)
|
||||
q = ctx.zeros((_T_Q_DECODE, _H_Q_DECODE * _D_HEAD),
|
||||
q = ctx.zeros((T_q, h_q * d_head),
|
||||
dtype=_DTYPE, dp=dp_full, name=f"{panel}_q")
|
||||
k = ctx.zeros((S_kv, _H_KV_DECODE * _D_HEAD),
|
||||
k = ctx.zeros((S_kv, h_kv * d_head),
|
||||
dtype=_DTYPE, dp=dp_kv, name=f"{panel}_k")
|
||||
v = ctx.zeros((S_kv, _H_KV_DECODE * _D_HEAD),
|
||||
v = ctx.zeros((S_kv, h_kv * d_head),
|
||||
dtype=_DTYPE, dp=dp_kv, name=f"{panel}_v")
|
||||
o = ctx.empty((_T_Q_DECODE, _H_Q_DECODE * _D_HEAD),
|
||||
o = ctx.empty((T_q, h_q * d_head),
|
||||
dtype=_DTYPE, dp=dp_full, name=f"{panel}_o")
|
||||
ctx.launch(
|
||||
panel, gqa_attention_decode_long_kernel,
|
||||
q, k, v, o,
|
||||
_T_Q_DECODE, S_kv, _H_Q_DECODE, _H_KV_DECODE, _D_HEAD, C, P,
|
||||
T_q, S_kv, h_q, h_kv, d_head, C, P, sub_w,
|
||||
_auto_dim_remap=False,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user