KernelBench hard · B200

KDA CUTLASS Claude Opus 4.8

passdid not score
harnessclaudeagent session1h 23mtotal wall1h 23mcheck11sbenchmark2soutput tokens172,810cost$14.73gpu-lock wait0sgpu-lock held13sregimecompute

Per-shape vs governing ceilingeach shape graded against whichever binds — bf16 compute or HBM bandwidth

2×1024×8×128×128×640.061 ms1.6%0.42 TB/s · 5% of 8.0 TB/s HBM · also 35 TFLOPS (2% of compute)
2×2048×8×128×128×640.115 ms1.7%0.44 TB/s · 5% of 8.0 TB/s HBM · also 37 TFLOPS (2% of compute)
1×4096×8×128×128×640.135 ms1.4%0.37 TB/s · 5% of 8.0 TB/s HBM · also 32 TFLOPS (1% of compute)
1×2048×4×128×128×640.057 ms0.8%0.22 TB/s · 3% of 8.0 TB/s HBM · also 19 TFLOPS (1% of compute)

compute-bound memory-bound · bar + right column = official fraction of the ceiling (the geomean input)

geomean(1.6% · 1.7% · 1.4% · 0.8%) = 1.3%

Kernel source (redacted)
"""Kimi Delta Attention (KDA) forward, chunk form — custom Triton kernels for B200 (SM100).

Decomposition:
  1. prepare: per (b,h,chunk) compute cumsum(g), the WY inverse A=(I-B)^-1 @ diag(beta),
     w = A @ (e^{gc} k), u = A @ v, and the folded chunk transition
        M_i = diag(e^{gc_last}) - kg_i^T w_i ,  c_i = kg_i^T u_i ,
     where kg_i = e^{gc_last - gc} k. This turns the inter-chunk recurrence into a
     single affine map  S_{i+1} = M_i S_i + c_i  (one matmul per step in the scan).
  2. scan: per (b,h, v-tile) sequential over chunks, S_{i+1}=M_i S_i + c_i, emit state h_i=S_i.
  3. fwd_o: per (b,h,chunk) parallel, v_new=u-w@h_i, o = (q e^{gc} scale) @ h_i + Aqk @ v_new.

A CUDA graph is captured for the (fixed-pointer) benchmark path; correctness checks
with fresh input tensors fall back to eager launches.
"""
from __future__ import annotations

import torch
import torch.nn as nn
import triton
import triton.language as tl


# ----------------------------------------------------------------------------
# Kernel 1: prepare WY representation + folded transition (per (b,h,chunk))
# ----------------------------------------------------------------------------
@triton.jit
def _prepare_kernel(
    k_ptr, v_ptr, g_ptr, beta_ptr,
    w_ptr, u_ptr, M_ptr, c_ptr,
    T, NT, H: tl.constexpr, K: tl.constexpr, V: tl.constexpr, BT: tl.constexpr,
    NITER: tl.constexpr,
):
    i_t = tl.program_id(0)
    i_bh = tl.program_id(1)
    i_b = i_bh // H
    i_h = i_bh % H

    base_k = (i_b * T * H + i_h) * K
    base_v = (i_b * T * H + i_h) * V
    row0 = i_t * BT

    p_k = tl.make_block_ptr(k_ptr + base_k, (T, K), (H * K, 1), (row0, 0), (BT, K), (1, 0))
    p_g = tl.make_block_ptr(g_ptr + base_k, (T, K), (H * K, 1), (row0, 0), (BT, K), (1, 0))
    p_v = tl.make_block_ptr(v_ptr + base_v, (T, V), (H * V, 1), (row0, 0), (BT, V), (1, 0))
    b_k = tl.load(p_k, boundary_check=(0, 1)).to(tl.float32)
    b_g = tl.load(p_g, boundary_check=(0, 1)).to(tl.float32)
    b_v = tl.load(p_v, boundary_check=(0, 1))

    p_beta = tl.make_block_ptr(beta_ptr + (i_b * T * H + i_h), (T,), (H,), (row0,), (BT,), (0,))
    b_beta = tl.load(p_beta, boundary_check=(0,)).to(tl.float32)

    gc = tl.cumsum(b_g, axis=0)          # [BT, K]
    eg = tl.exp(gc)
    egn = 1.0 / eg                       # e^{-gc}
    kge = (b_k * eg).to(tl.bfloat16)     # e^{gc} k
    kgen = b_k * egn                     # e^{-gc} k (fp32)

    # B (strict lower):  B[c,i] = -beta[c] * <k_c e^{gc_c}, k_i e^{-gc_i}>
    Smat = tl.dot(kge, kgen.to(tl.bfloat16).T)   # [BT, BT]
    Bm = -b_beta[:, None] * Smat
    row = tl.arange(0, BT)
    col = tl.arange(0, BT)
    Bm = tl.where(row[:, None] > col[None, :], Bm, 0.0).to(tl.bfloat16)

    # T_full = (I - B)^-1 = sum_{j>=0} B^j = prod (I + B^{2^k}),  B nilpotent (B^BT=0)
    eye = (row[:, None] == col[None, :]).to(tl.float32)
    Tf = (eye + Bm).to(tl.bfloat16)
    Bp = Bm
    for _ in range(NITER):
        Bp = tl.dot(Bp, Bp).to(tl.bfloat16)
        Tf = (Tf + tl.dot(Tf, Bp)).to(tl.bfloat16)

    A = (Tf * b_beta[None, :]).to(tl.bfloat16)   # column-scale by beta
    b_w = tl.dot(A, kge).to(tl.bfloat16)   # [BT, K]
    b_u = tl.dot(A, b_v).to(tl.bfloat16)   # [BT, V]

    gc_last = tl.sum(b_g, axis=0)         # [K]  (= last row of cumsum)
    D = tl.exp(gc_last)                   # [K]  diagonal decay
    kg = (D[None, :] * kgen).to(tl.bfloat16)  # e^{gc_last - gc} k

    # folded transition:  M = diag(D) - kg^T w ,   c = kg^T u
    P = tl.dot(kg.T, b_w)                 # [K, K]
    ok = tl.arange(0, K)
    M = tl.where(ok[:, None] == ok[None, :], D[:, None] - P, -P)
    cmat = tl.dot(kg.T, b_u)              # [K, V]

    p_w = tl.make_block_ptr(w_ptr + base_k, (T, K), (H * K, 1), (row0, 0), (BT, K), (1, 0))
    p_u = tl.make_block_ptr(u_ptr + base_v, (T, V), (H * V, 1), (row0, 0), (BT, V), (1, 0))
    tl.store(p_w, b_w, boundary_check=(0, 1))
    tl.store(p_u, b_u, boundary_check=(0, 1))

    base_M = ((i_b * NT + i_t) * H + i_h) * K * K
    base_c = ((i_b * NT + i_t) * H + i_h) * K * V
    p_M = tl.make_block_ptr(M_ptr + base_M, (K, K), (K, 1), (0, 0), (K, K), (1, 0))
    p_c = tl.make_block_ptr(c_ptr + base_c, (K, V), (V, 1), (0, 0), (K, V), (1, 0))
    tl.store(p_M, M.to(M_ptr.dtype.element_ty), boundary_check=(0, 1))
    tl.store(p_c, cmat.to(c_ptr.dtype.element_ty), boundary_check=(0, 1))


# ----------------------------------------------------------------------------
# Kernel 2: sequential affine scan  S_{i+1} = M_i S_i + c_i  (per (b,h, v-tile))
# ----------------------------------------------------------------------------
@triton.jit
def _scan_kernel(
    M_ptr, c_ptr, h_ptr,
    NT, H: tl.constexpr, K: tl.constexpr, V: tl.constexpr, BV: tl.constexpr,
):
    i_bh = tl.program_id(0)
    i_v = tl.program_id(1)
    i_b = i_bh // H
    i_h = i_bh % H
    v0 = i_v * BV

    S = tl.zeros((K, BV), dtype=tl.float32)

    for i_t in range(NT):
        base_M = ((i_b * NT + i_t) * H + i_h) * K * K
        base_c = ((i_b * NT + i_t) * H + i_h) * K * V
        base_h = ((i_b * NT + i_t) * H + i_h) * K * V

        p_h = tl.make_block_ptr(h_ptr + base_h, (K, V), (V, 1), (0, v0), (K, BV), (1, 0))
        tl.store(p_h, S.to(h_ptr.dtype.element_ty), boundary_check=(0, 1))

        p_M = tl.make_block_ptr(M_ptr + base_M, (K, K), (K, 1), (0, 0), (K, K), (1, 0))
        p_c = tl.make_block_ptr(c_ptr + base_c, (K, V), (V, 1), (0, v0), (K, BV), (1, 0))
        b_M = tl.load(p_M, boundary_check=(0, 1))
        b_c = tl.load(p_c, boundary_check=(0, 1)).to(tl.float32)

        S = tl.dot(b_M, S.to(b_M.dtype)) + b_c


# ----------------------------------------------------------------------------
# Kernel 3: output  (one program per (b,h,chunk))
# ----------------------------------------------------------------------------
@triton.jit
def _output_kernel(
    q_ptr, k_ptr, g_ptr, w_ptr, u_ptr, h_ptr, o_ptr,
    scale,
    T, NT, H: tl.constexpr, K: tl.constexpr, V: tl.constexpr, BT: tl.constexpr,
):
    i_t = tl.program_id(0)
    i_bh = tl.program_id(1)
    i_b = i_bh // H
    i_h = i_bh % H
    row0 = i_t * BT

    base_k = (i_b * T * H + i_h) * K
    base_v = (i_b * T * H + i_h) * V
    base_h = ((i_b * NT + i_t) * H + i_h) * K * V

    p_q = tl.make_block_ptr(q_ptr + base_k, (T, K), (H * K, 1), (row0, 0), (BT, K), (1, 0))
    p_k = tl.make_block_ptr(k_ptr + base_k, (T, K), (H * K, 1), (row0, 0), (BT, K), (1, 0))
    p_g = tl.make_block_ptr(g_ptr + base_k, (T, K), (H * K, 1), (row0, 0), (BT, K), (1, 0))
    b_q = tl.load(p_q, boundary_check=(0, 1)).to(tl.float32)
    b_k = tl.load(p_k, boundary_check=(0, 1)).to(tl.float32)
    b_g = tl.load(p_g, boundary_check=(0, 1)).to(tl.float32)
    b_gc = tl.cumsum(b_g, axis=0)

    eg = tl.exp(b_gc)
    qg = (b_q * eg * scale).to(tl.bfloat16)   # [BT, K]
    kn = (b_k / eg).to(tl.bfloat16)           # [BT, K]  (= k e^{-gc})

    p_h = tl.make_block_ptr(h_ptr + base_h, (K, V), (V, 1), (0, 0), (K, V), (1, 0))
    b_h = tl.load(p_h, boundary_check=(0, 1))

    # v_new = u - w @ h
    p_w = tl.make_block_ptr(w_ptr + base_k, (T, K), (H * K, 1), (row0, 0), (BT, K), (1, 0))
    p_u = tl.make_block_ptr(u_ptr + base_v, (T, V), (H * V, 1), (row0, 0), (BT, V), (1, 0))
    b_w = tl.load(p_w, boundary_check=(0, 1))
    b_u = tl.load(p_u, boundary_check=(0, 1)).to(tl.float32)
    v_new = (b_u - tl.dot(b_w, b_h)).to(tl.bfloat16)

    # o1 = qg @ h
    o = tl.dot(qg, b_h)

    # Aqk = qg @ kn^T, masked to lower-incl-diag
    Aqk = tl.dot(qg, kn.T)
    row = tl.arange(0, BT)
    col = tl.arange(0, BT)
    Aqk = tl.where(col[None, :] <= row[:, None], Aqk, 0.0).to(tl.bfloat16)
    o += tl.dot(Aqk, v_new)

    p_o = tl.make_block_ptr(o_ptr + base_v, (T, V), (H * V, 1), (row0, 0), (BT, V), (1, 0))
    tl.store(p_o, o.to(o_ptr.dtype.element_ty), boundary_check=(0, 1))


def _launch(q, k, v, g, beta, scale, BT, buf):
    B, T, H, K = q.shape
    V = v.shape[-1]
    NT = T // BT
    BH = B * H
    w, u, M, c, h, o = buf

    # Thin problems (few b*h programs per wave) prefer more warps per program.
    thin = (NT * BH) < 256
    pnw, onw, ons = (8, 8, 1) if thin else (4, 4, 3)

    _prepare_kernel[(NT, BH)](
        k, v, g, beta, w, u, M, c,
        T, NT, H, K, V, BT, 5, num_warps=pnw, num_stages=2,
    )
    BV = 16
    _scan_kernel[(BH, V // BV)](
        M, c, h, NT, H, K, V, BV, num_warps=4, num_stages=4,
    )
    _output_kernel[(NT, BH)](
        q, k, g, w, u, h, o, scale,
        T, NT, H, K, V, BT, num_warps=onw, num_stages=ons,
    )
    return o


class Model(nn.Module):
    def __init__(self, B, T, H, K, V, chunk_size=64):
        super().__init__()
        self.B, self.T, self.H, self.K, self.V = B, T, H, K, V
        self.chunk_size = chunk_size
        self.scale = float(K) ** -0.5
        self.register_buffer("_dummy", torch.zeros(1), persistent=False)
        self._buf = None
        self._graph = None
        self._gptrs = None

    def _alloc(self, dev):
        B, T, H, K, V = self.B, self.T, self.H, self.K, self.V
        NT = T // self.chunk_size
        bf = torch.bfloat16
        self._buf = (
            torch.empty((B, T, H, K), dtype=bf, device=dev),       # w
            torch.empty((B, T, H, V), dtype=bf, device=dev),       # u
            torch.empty((B, NT, H, K, K), dtype=bf, device=dev),   # M
            torch.empty((B, NT, H, K, V), dtype=bf, device=dev),   # c
            torch.empty((B, NT, H, K, V), dtype=bf, device=dev),   # h
            torch.empty((B, T, H, V), dtype=bf, device=dev),       # o
        )

    def _capture(self, ins):
        s = torch.cuda.Stream()
        s.wait_stream(torch.cuda.current_stream())
        with torch.cuda.stream(s):
            for _ in range(3):
                _launch(*ins, self.scale, self.chunk_size, self._buf)
        torch.cuda.current_stream().wait_stream(s)
        gph = torch.cuda.CUDAGraph()
        with torch.cuda.graph(gph):
            _launch(*ins, self.scale, self.chunk_size, self._buf)
        self._graph = gph

    def forward(self, q, k, v, g, beta):
        if self._buf is None:
            self._alloc(q.device)
        ins = [q.contiguous(), k.contiguous(), v.contiguous(),
               g.contiguous(), beta.contiguous()]
        ptrs = tuple(x.data_ptr() for x in ins)
        if self._graph not in (None, False) and ptrs == self._gptrs:
            self._graph.replay()
            return self._buf[-1]
        o = _launch(*ins, self.scale, self.chunk_size, self._buf)
        if self._graph is None:
            try:
                self._capture(ins)
                self._gptrs = ptrs
            except Exception:
                self._graph = False
        return o


B = 2
T = 1024
H = 8
K = 128
V = 128
CHUNK_SIZE = 64


def get_inputs():
    torch.manual_seed(0)
    q = torch.randn(B, T, H, K, dtype=torch.bfloat16) * 0.1
    k = torch.randn(B, T, H, K, dtype=torch.bfloat16) * 0.1
    v = torch.randn(B, T, H, V, dtype=torch.bfloat16) * 0.1
    g = (torch.randn(B, T, H, K, dtype=torch.float32) * 0.1 - 0.05)
    beta = torch.sigmoid(torch.randn(B, T, H, dtype=torch.bfloat16))
    return [q, k, v, g, beta]


def get_init_inputs():
    return [B, T, H, K, V, CHUNK_SIZE]

20260620_093507_claude_claude-opus-4-8_02_kda_cutlass