Files
kernbench2/src/kernbench/benches/milestone_1h_gqa.py
T
ywkang 24c705419e paper(gqa): two-regime "use of composite commands" — decode + compute-bound prefill
Complete the composite-command study across both attention regimes and
write up the result, resolving when the composite command helps latency.

Decode (memory-bound, T_q=1, M=8): the command form is latency-neutral —
the kernel is bound by KV streaming and the MAC array is near-idle, so the
composite's only benefit here is host-issue offload (O(n_tiles) -> O(1)
PE_CPU commands). Figure: gqa_decode_long_ctx_composite (latency flat,
command count saturates).

Prefill (compute-bound, large M=G*T_q tile-filling): add three command-form
variants of a single-rank FlashAttention prefill kernel
(_gqa_prefill_compute_bound: primitive / composite / composite_extended).
Here the composite's scheduler-internal per-tile DMA<->compute pipeline
keeps the MAC array fed while the primitive's blocking tl.dot starves it,
so composite wins on MAC utilization (68% flat -> 83%) and wall-clock
(19% faster at ctx=1024), with the margin growing with context (deeper
P.V reduction = more tiles to pipeline) — the compute-bound mirror of the
GEMM result in section 3. Figure: gqa_prefill_compute_bound (latency +
MAC util). Sweep wired as GQA_1H_SWEEPS=prefill_cb; tests cover structure,
e2e, and composite<primitive in the compute-bound regime.

The synthesis: composite has two benefits set by roofline position —
host-issue offload (always) and MAC-array feeding (compute-bound only).
Decode exercises the first, prefill both.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 17:04:26 -07:00

88 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""milestone-1h-gqa: umbrella GQA bench for the 1H code-sign milestone.
Single ``@bench`` entry that drives all GQA panels by delegating to
internal helpers under ``kernbench.benches.gqa_helpers``. Mirrors the
``milestone_1h_gemm`` umbrella pattern.
Currently exercises (long-context only — short-context panels are
future work):
- 4-cases prefill comparative study (gqa_helpers.long_ctx.gqa_prefill_long_ctx_4cases)
- 4-cases decode comparative study (gqa_helpers.long_ctx.gqa_decode_long_ctx_4cases)
- Case-6 composite-command study (gqa_helpers.long_ctx.gqa_decode_long_ctx_composite)
Each sub-sweep writes its own ``sweep_*.json`` into the shared output
dir ``benches/1H_milestone_output/gqa/gqa_long_ctx/``.
Selection via the env var ``GQA_1H_SWEEPS=prefill,decode`` (default
runs prefill+decode). The composite study is opt-in (it sweeps the
data-mode engine over several S_kv points): ``GQA_1H_SWEEPS=composite``.
Gated by ``GQA_1H_RUN=1`` to keep CI fast.
"""
from __future__ import annotations
import os
from kernbench.benches.gqa_helpers.long_ctx.gqa_decode_long_ctx_4cases import (
run_sweep as _run_decode_sweep,
)
from kernbench.benches.gqa_helpers.long_ctx.gqa_decode_long_ctx_composite import (
run_sweep as _run_composite_sweep,
)
from kernbench.benches.gqa_helpers.long_ctx.gqa_prefill_compute_bound import (
run_sweep as _run_prefill_cb_sweep,
)
from kernbench.benches.gqa_helpers.long_ctx.gqa_prefill_long_ctx_4cases import (
run_sweep as _run_prefill_sweep,
)
from kernbench.benches.registry import bench
from kernbench.policy.placement.dp import DPPolicy
@bench(
name="milestone-1h-gqa",
description=(
"Umbrella GQA milestone — drives long-context prefill + decode "
"4-cases sweeps on the LLaMA-3.1-70B single-KV-head group "
"(8 cubes × 8 PEs). Gated by GQA_1H_RUN=1."
),
)
def run(torch) -> None:
"""Drive selected GQA sub-sweeps; each writes its own sweep_*.json.
Env vars:
GQA_1H_RUN=1 (required gate)
GQA_1H_TOPOLOGY=topology.yaml (override topology path)
GQA_1H_SWEEPS=prefill,decode (default: both; comma-separated)
"""
if not os.environ.get("GQA_1H_RUN"):
raise RuntimeError("milestone-1h-gqa needs GQA_1H_RUN=1.")
topology = os.environ.get("GQA_1H_TOPOLOGY", "topology.yaml")
requested = os.environ.get("GQA_1H_SWEEPS", "prefill,decode")
sweeps = [s.strip() for s in requested.split(",") if s.strip()]
runners = {
"prefill": _run_prefill_sweep,
"decode": _run_decode_sweep,
"composite": _run_composite_sweep,
"prefill_cb": _run_prefill_cb_sweep,
}
unknown = [s for s in sweeps if s not in runners]
if unknown:
raise RuntimeError(
f"GQA_1H_SWEEPS contains unknown sweep(s) {unknown}; "
f"valid: {sorted(runners)}"
)
for s in sweeps:
runners[s](topology)
# Sentinel tensor (ADR-0045 D4 / ADR-0054 D2 carve-out) — the
# sub-sweeps each spin up their own GraphEngine via ``run_bench``,
# so this outer @bench needs to submit at least one request.
torch.zeros(
(1, 1), dtype="f16",
dp=DPPolicy(cube="row_wise", pe="replicate", num_cubes=1, num_pes=1),
name="milestone_1h_gqa_sentinel",
)