add three gqa attention kernel variants for short context length
This commit is contained in:
@@ -64,7 +64,7 @@ def _count(op_log, name: str) -> int:
|
||||
def _run_prefill(*, kv_per_cube: int, C: int, T_q: int, S_kv: int,
|
||||
h_q: int = 8):
|
||||
"""Run the unified prefill kernel in the given mode."""
|
||||
from kernbench.benches._gqa_attention_prefill_short import (
|
||||
from kernbench.benches.gqa_helpers.short_ctx._gqa_attention_prefill_short import (
|
||||
_validate_config as _validate_prefill_config,
|
||||
gqa_attention_prefill_short_kernel,
|
||||
)
|
||||
@@ -182,7 +182,7 @@ def test_prefill_multitile_scaling(kv_per_cube, C):
|
||||
|
||||
def _run_decode(*, kv_per_cube: int, C: int, S_kv: int, h_q: int = 8):
|
||||
"""Run the unified decode kernel in the given mode."""
|
||||
from kernbench.benches._gqa_attention_decode_short import (
|
||||
from kernbench.benches.gqa_helpers.short_ctx._gqa_attention_decode_short import (
|
||||
_validate_config as _validate_decode_config,
|
||||
gqa_attention_decode_short_kernel,
|
||||
)
|
||||
@@ -387,7 +387,7 @@ def test_prefill_per_cube_dma_balanced(kv_per_cube, C):
|
||||
def _run_prefill_composite(*, kv_per_cube: int, C: int, T_q: int,
|
||||
S_kv: int, h_q: int = 8):
|
||||
"""Same helper as _run_prefill but for the composite-GEMM kernel."""
|
||||
from kernbench.benches._gqa_attention_prefill_short_composite import (
|
||||
from kernbench.benches.gqa_helpers.short_ctx._gqa_attention_prefill_short_composite import (
|
||||
_validate_config as _validate_prefill_cmp_config,
|
||||
gqa_attention_prefill_short_composite_kernel,
|
||||
)
|
||||
@@ -428,7 +428,7 @@ def _run_prefill_composite(*, kv_per_cube: int, C: int, T_q: int,
|
||||
def _run_decode_composite(*, kv_per_cube: int, C: int, S_kv: int,
|
||||
h_q: int = 8):
|
||||
"""Same helper as _run_decode but for the composite-GEMM kernel."""
|
||||
from kernbench.benches._gqa_attention_decode_short_composite import (
|
||||
from kernbench.benches.gqa_helpers.short_ctx._gqa_attention_decode_short_composite import (
|
||||
_validate_config as _validate_decode_cmp_config,
|
||||
gqa_attention_decode_short_composite_kernel,
|
||||
)
|
||||
@@ -467,9 +467,92 @@ def _run_decode_composite(*, kv_per_cube: int, C: int, S_kv: int,
|
||||
)
|
||||
|
||||
|
||||
def _run_prefill_composite_fused(*, kv_per_cube: int, C: int, T_q: int,
|
||||
S_kv: int, h_q: int = 8):
|
||||
"""Variant (3): GEMM-only composite + softmax_merge prologue fusion."""
|
||||
from kernbench.benches.gqa_helpers.short_ctx._gqa_attention_prefill_short_composite_fused import (
|
||||
_validate_config as _validate_prefill_fuse_config,
|
||||
gqa_attention_prefill_short_composite_fused_kernel,
|
||||
)
|
||||
_validate_prefill_fuse_config(kv_per_cube=kv_per_cube, T_q=T_q, P=P,
|
||||
C=C, h_q=h_q, h_kv=H_KV, S_kv=S_kv)
|
||||
n_tiles = S_kv // TILE_S_KV
|
||||
Q_ROWS = kv_per_cube * T_q
|
||||
Q_COLS = (h_q * D_HEAD) // kv_per_cube
|
||||
topo = resolve_topology(str(TOPOLOGY_DEFAULT))
|
||||
|
||||
def _bench_fn(ctx):
|
||||
configure_sfr_intercube_multisip(ctx.engine, ctx.spec, _ccl_cfg())
|
||||
dp_q = DPPolicy(cube="column_wise", pe="replicate", num_cubes=C, num_pes=P)
|
||||
dp_kv = DPPolicy(cube="row_wise", pe="replicate", num_cubes=C, num_pes=P)
|
||||
dp_o = DPPolicy(cube="column_wise", pe="replicate", num_cubes=C, num_pes=P)
|
||||
q = ctx.zeros((Q_ROWS, Q_COLS), dtype=DTYPE, dp=dp_q,
|
||||
name=f"q_pre_fuse_kv{kv_per_cube}")
|
||||
k = ctx.zeros((H_KV * n_tiles * D_HEAD, TILE_S_KV),
|
||||
dtype=DTYPE, dp=dp_kv, name=f"k_pre_fuse_kv{kv_per_cube}")
|
||||
v = ctx.zeros((H_KV * S_kv, D_HEAD),
|
||||
dtype=DTYPE, dp=dp_kv, name=f"v_pre_fuse_kv{kv_per_cube}")
|
||||
o = ctx.empty((Q_ROWS, Q_COLS), dtype=DTYPE, dp=dp_o,
|
||||
name=f"o_pre_fuse_kv{kv_per_cube}")
|
||||
ctx.launch(
|
||||
f"gqa_prefill_fuse_kv{kv_per_cube}",
|
||||
gqa_attention_prefill_short_composite_fused_kernel,
|
||||
q, k, v, o,
|
||||
T_q, S_kv, h_q, H_KV, D_HEAD, C, P, kv_per_cube,
|
||||
_auto_dim_remap=False,
|
||||
)
|
||||
|
||||
return run_bench(
|
||||
topology=topo, bench_fn=_bench_fn,
|
||||
device=resolve_device(None), engine_factory=_engine_factory,
|
||||
)
|
||||
|
||||
|
||||
def _run_decode_composite_fused(*, kv_per_cube: int, C: int, S_kv: int,
|
||||
h_q: int = 8):
|
||||
"""Variant (3): GEMM-only composite + softmax_merge prologue fusion."""
|
||||
from kernbench.benches.gqa_helpers.short_ctx._gqa_attention_decode_short_composite_fused import (
|
||||
_validate_config as _validate_decode_fuse_config,
|
||||
gqa_attention_decode_short_composite_fused_kernel,
|
||||
)
|
||||
T_q = 1
|
||||
_validate_decode_fuse_config(kv_per_cube=kv_per_cube, T_q=T_q, P=P,
|
||||
C=C, h_q=h_q, h_kv=H_KV, S_kv=S_kv)
|
||||
Q_ROWS = kv_per_cube * T_q
|
||||
Q_COLS = (h_q * D_HEAD) // kv_per_cube
|
||||
k_rows = (H_KV * S_kv * D_HEAD) // TILE_S_KV
|
||||
topo = resolve_topology(str(TOPOLOGY_DEFAULT))
|
||||
|
||||
def _bench_fn(ctx):
|
||||
configure_sfr_intercube_multisip(ctx.engine, ctx.spec, _ccl_cfg())
|
||||
dp_q = DPPolicy(cube="column_wise", pe="replicate", num_cubes=C, num_pes=P)
|
||||
dp_kv = DPPolicy(cube="row_wise", pe="row_wise", num_cubes=C, num_pes=P)
|
||||
dp_o = DPPolicy(cube="column_wise", pe="replicate", num_cubes=C, num_pes=P)
|
||||
q = ctx.zeros((Q_ROWS, Q_COLS), dtype=DTYPE, dp=dp_q,
|
||||
name=f"q_dec_fuse_kv{kv_per_cube}")
|
||||
k = ctx.zeros((k_rows, TILE_S_KV), dtype=DTYPE, dp=dp_kv,
|
||||
name=f"k_dec_fuse_kv{kv_per_cube}")
|
||||
v = ctx.zeros((H_KV * S_kv, D_HEAD), dtype=DTYPE, dp=dp_kv,
|
||||
name=f"v_dec_fuse_kv{kv_per_cube}")
|
||||
o = ctx.empty((Q_ROWS, Q_COLS), dtype=DTYPE, dp=dp_o,
|
||||
name=f"o_dec_fuse_kv{kv_per_cube}")
|
||||
ctx.launch(
|
||||
f"gqa_decode_fuse_kv{kv_per_cube}",
|
||||
gqa_attention_decode_short_composite_fused_kernel,
|
||||
q, k, v, o,
|
||||
T_q, S_kv, h_q, H_KV, D_HEAD, C, P, kv_per_cube,
|
||||
_auto_dim_remap=False,
|
||||
)
|
||||
|
||||
return run_bench(
|
||||
topology=topo, bench_fn=_bench_fn,
|
||||
device=resolve_device(None), engine_factory=_engine_factory,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kv_per_cube,C", MODES)
|
||||
def test_prefill_composite_smoke(kv_per_cube, C):
|
||||
"""Composite-GEMM prefill completes in all 4 modes."""
|
||||
"""Variant (2) GEMM-only composite prefill — all 4 modes."""
|
||||
r = _run_prefill_composite(kv_per_cube=kv_per_cube, C=C, T_q=8, S_kv=1024)
|
||||
assert r.completion.ok, (
|
||||
f"prefill-composite kv_per_cube={kv_per_cube}: {r.completion}"
|
||||
@@ -478,8 +561,48 @@ def test_prefill_composite_smoke(kv_per_cube, C):
|
||||
|
||||
@pytest.mark.parametrize("kv_per_cube,C", MODES)
|
||||
def test_decode_composite_smoke(kv_per_cube, C):
|
||||
"""Composite-GEMM decode completes in all 4 modes."""
|
||||
"""Variant (2) GEMM-only composite decode — all 4 modes."""
|
||||
r = _run_decode_composite(kv_per_cube=kv_per_cube, C=C, S_kv=8192)
|
||||
assert r.completion.ok, (
|
||||
f"decode-composite kv_per_cube={kv_per_cube}: {r.completion}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kv_per_cube,C", MODES)
|
||||
def test_decode_composite_fused_smoke(kv_per_cube, C):
|
||||
"""Variant (3) composite + softmax_merge fused decode — all 4 modes."""
|
||||
r = _run_decode_composite_fused(kv_per_cube=kv_per_cube, C=C, S_kv=8192)
|
||||
assert r.completion.ok, (
|
||||
f"decode-composite-fused kv_per_cube={kv_per_cube}: {r.completion}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kv_per_cube,C", MODES)
|
||||
def test_decode_composite_fused_multitile(kv_per_cube, C):
|
||||
"""Fused decode with n_tiles_per_pe == 2 in EVERY mode, so the tile-1+
|
||||
fused composite loop actually runs.
|
||||
|
||||
The smoke test at S_kv=8192 gives A1 (group_size=8) n_tiles_per_pe=1,
|
||||
which never enters the fused path. S_kv = group_size·2·TILE_S_KV forces
|
||||
2 tiles per PE for all modes (mirrors test_decode_multitile_per_pe)."""
|
||||
group_size = P // kv_per_cube
|
||||
S_kv = group_size * 2 * TILE_S_KV
|
||||
r = _run_decode_composite_fused(kv_per_cube=kv_per_cube, C=C, S_kv=S_kv)
|
||||
assert r.completion.ok, (
|
||||
f"decode-composite-fused-multitile kv={kv_per_cube} S_kv={S_kv}: "
|
||||
f"{r.completion}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kv_per_cube,C", MODES)
|
||||
def test_prefill_composite_fused_smoke(kv_per_cube, C):
|
||||
"""Variant (3) composite + softmax_merge fused prefill — all 4 modes.
|
||||
|
||||
S_kv=2048 (n_tiles=2) so the tile-1+ fused composite loop actually
|
||||
runs; S_kv=1024 gives n_tiles=1 and never enters the fused path.
|
||||
Multi-cube (A1/A2/A4) works now that recv'd K/V slots are pinned."""
|
||||
r = _run_prefill_composite_fused(kv_per_cube=kv_per_cube, C=C,
|
||||
T_q=8, S_kv=2048)
|
||||
assert r.completion.ok, (
|
||||
f"prefill-composite-fused kv_per_cube={kv_per_cube}: {r.completion}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user