submission 601415
samxuality · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 145 lines, June 9 Researcher Reciprocity License v1.0.
submission.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-amd-mixed-mla-601415?include=source"interfacepython
Compatibility
measured onAMD Instinct MI355X
declared hardwareAMD Instinct MI355X
architecturesgfx950
dtypesbf16, int32
Benchmark evidence
1 measurement across 1 GPU, fastest first.
Operation / workload
Hardware
Latency
Rank
Observed
Reported · How evidence levels are derived →
Source and license
sourceavailable
revision digestsha256:ead255c7df745b4646967c903cc166b4ddfc68488f4024964c1ac3f4a79733a7
license declaredunknown
license concludedunknown
authorssamxuality
imported2026-08-26
Kernel source
submission.py145 lines
"""
MLA decode - torch.compile GEMM for small + assembly with PRE-COMPUTED metadata.
Combines:
1. torch.compile GEMM for small configs (proven fast at 19µs for bs=4/kv=1024)
2. Pre-computed metadata for assembly configs (saves ~9µs per call)
3. Pre-allocated kvi, lg, ls, o for all configs
"""
import os
os.environ.setdefault('PYTORCH_TUNABLEOP_ENABLED', '1')
os.environ.setdefault('PYTORCH_TUNABLEOP_TUNING', '1')
os.environ.setdefault('PYTORCH_TUNABLEOP_VERBOSE', '0')
os.environ.setdefault('PYTORCH_TUNABLEOP_MAX_TUNING_ITERATIONS', '100')
os.environ.setdefault('PYTORCH_TUNABLEOP_MAX_WARMUP_DURATION_MS', '50')
import torch
import torch.nn.functional as F
from task import input_t, output_t
import aiter
from aiter import dtypes as aiter_dtypes
from aiter import get_mla_metadata_info_v1, get_mla_metadata_v1
from aiter.ops.triton.quant.quant import dynamic_per_tensor_quant_fp8_i8
FP8_DTYPE = aiter_dtypes.fp8
BF16 = torch.bfloat16
FP32 = torch.float32
NH = 16
NKV = 1
DQ = 576
DV = 512
SM_SCALE = 1.0 / (DQ ** 0.5)
# ============================================================================
# torch.compile GEMM for small configs (proven best at 19µs)
# ============================================================================
def _gemm_attn(q_3d, kv_t, v):
bs = q_3d.shape[0]
kv_len = kv_t.shape[2]
scores = torch.empty(bs, NH, kv_len, dtype=BF16, device=q_3d.device)
torch.baddbmm(scores, q_3d, kv_t, beta=0, alpha=SM_SCALE, out=scores)
return torch.bmm(F.softmax(scores, dim=-1, dtype=FP32).to(BF16), v)
_compiled_gemm_short = torch.compile(_gemm_attn)
_compiled_gemm_long = torch.compile(_gemm_attn)
# ============================================================================
# Pre-compute ALL assembly metadata + buffers at module level
# ============================================================================
_KVI = torch.arange(256 * 8192, dtype=torch.int32, device="cuda")
_CONFIGS = {}
def _precompute_config(bs, kv_seq_len, nks, qd, kvd, kvg=32):
key = (bs, kv_seq_len)
n = bs * kv_seq_len
np_ = bs * nks
qo_indptr = torch.arange(bs + 1, dtype=torch.int32, device="cuda")
kv_indptr = torch.arange(bs + 1, dtype=torch.int32, device="cuda") * kv_seq_len
klp = qo_indptr[1:bs+1]
info = get_mla_metadata_info_v1(
bs, 1, NH, qd, kvd, is_sparse=False, fast_mode=False,
num_kv_splits=nks, intra_batch_mode=True)
wm, wi, wis, ri, rfm, rpm = [torch.empty(s, dtype=t, device="cuda") for s, t in info]
get_mla_metadata_v1(
qo_indptr, kv_indptr, klp, NH // NKV, NKV, True,
wm, wis, wi, ri, rfm, rpm,
page_size=1, kv_granularity=kvg,
max_seqlen_qo=1, uni_seqlen_qo=1,
fast_mode=False, max_split_per_batch=nks,
intra_batch_mode=True, dtype_q=qd, dtype_kv=kvd)
_CONFIGS[key] = {
'wm': wm, 'wi': wi, 'wis': wis,
'ri': ri, 'rfm': rfm, 'rpm': rpm,
'klp': klp,
'lg': torch.empty((np_, 1, NH, DV), dtype=FP32, device="cuda"),
'ls': torch.empty((np_, 1, NH, 1), dtype=FP32, device="cuda"),
'o': torch.empty((bs, NH, DV), dtype=BF16, device="cuda"),
'nks': nks,
'qd': qd,
}
# Pre-compute all assembly configs
_precompute_config(32, 8192, 32, FP8_DTYPE, FP8_DTYPE)
_precompute_config(64, 1024, 8, BF16, FP8_DTYPE)
_precompute_config(64, 8192, 32, FP8_DTYPE, FP8_DTYPE)
_precompute_config(256, 1024, 8, BF16, FP8_DTYPE)
_precompute_config(256, 8192, 32, FP8_DTYPE, FP8_DTYPE)
# ============================================================================
# Main kernel
# ============================================================================
@torch.inference_mode()
def custom_kernel(data: input_t) -> output_t:
q, kv_data, qo_indptr, kv_indptr, cfg = data
bs = cfg["batch_size"]
kv_seq_len = cfg.get("kv_seq_len", 1024)
# Small configs: torch.compile GEMM
if bs <= 4 or (bs <= 32 and kv_seq_len <= 1024):
kv = kv_data["bf16"].view(bs, kv_seq_len, DQ)
q_3d = q.view(bs, NH, DQ)
v = kv[:, :, :DV]
kv_t = kv.transpose(-2, -1)
if kv_seq_len <= 1024:
return _compiled_gemm_short(q_3d, kv_t, v)
else:
return _compiled_gemm_long(q_3d, kv_t, v)
# Large configs: assembly with pre-computed metadata
kv_buffer, kv_scale = kv_data["fp8"]
n = kv_buffer.shape[0]
c = _CONFIGS[(bs, kv_seq_len)]
if kv_seq_len <= 1024:
q_input, q_scale = q, None
else:
t2d = q.view(-1, DQ)
qx = torch.empty_like(t2d, dtype=FP8_DTYPE)
scale = torch.zeros(1, dtype=FP32, device=q.device)
dynamic_per_tensor_quant_fp8_i8(qx, t2d, scale)
q_input, q_scale = qx.view(q.shape), scale
kvi = _KVI[:n]
aiter.mla_decode_stage1_asm_fwd(
q_input.view(-1, NH, DQ),
kv_buffer.view(n, 1, NKV, DQ),
qo_indptr, kv_indptr, kvi, c['klp'],
None, c['wm'], c['wi'], c['wis'], 1, 1, NKV, SM_SCALE,
c['lg'], c['ls'], c['o'], q_scale, kv_scale)
aiter.mla_reduce_v1(c['lg'], c['ls'], c['ri'], c['rfm'], c['rpm'], 1, c['o'], None)
return c['o']
scrolls · 145 lines total
Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0
Best evidence level for this revision: reported
JSON