KernelBench hard · RTX PRO 6000

W4A16 GEMM GLM-5.2

32.1%geomean peak fraction across shapes

manually audited: clean

Two-path W4A16 GEMM. M==1 decode uses a hand-written CUDA GEMV (load_inline): one warp per output column, vectorized 16-byte weight loads with prefetch, in-register int4 unpack + (w-z)*s dequant, warp shuffle-reduce. M>1 uses a Triton tl.dot GEMM with fused dequant. Genuine unpack+GEMM; no forbidden vendor calls, no caching/identity tricks.

harnesszai-claudeagent session4h 38mtotal wall4h 40mcheck41sbenchmark65soutput tokens196,049cost$27.92gpu-lock wait78sgpu-lock held28sregimememory

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

1×12288×40960.027 ms55.0%0.99 TB/s · 55% of 1.8 TB/s HBM · also 4 TFLOPS (1% of compute)
32×12288×40960.043 ms36.2%0.65 TB/s · 36% of 1.8 TB/s HBM · also 76 TFLOPS (15% of compute)
256×12288×40960.152 ms12.8%169 TFLOPS · 34% of 500 TF bf16 peak · also 0.23 TB/s (13% of HBM)
1×4096×40960.017 ms29.5%0.53 TB/s · 29% of 1.8 TB/s HBM · also 2 TFLOPS (0% of compute)
16×14336×40960.039 ms45.2%0.81 TB/s · 45% of 1.8 TB/s HBM · also 48 TFLOPS (10% of compute)

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

geomean(55.0% · 36.2% · 12.8% · 29.5% · 45.2%) = 32.1%

Kernel source (redacted)
"""W4A16 weight-only quantized GEMM (AWQ/GPTQ-style asymmetric int4).

Fused unpack + dequant + GEMM in Triton. Same Model/get_inputs/get_init_inputs
interface as reference.py.

Scheme:
  x:      (M, K)          bf16
  w_q:    (K//2, N)       uint8   low nibble = even-K row, high nibble = odd-K row
  scales: (K//128, N)     bf16
  zeros:  (K//128, N)     bf16
  out:    (M, N)          bf16

  w_bf[k,n] = (unpack(w_q)[k,n] - zeros[k//128,n]) * scales[k//128,n]
  out = x @ w_bf

Two kernel paths:
  - M == 1: split-K GEMV over a *transposed* weight (N, K//2) so each output's
    weight vector is contiguous in memory -> higher sustained bandwidth. When the
    N-tiling alone fills the GPU, no split-K and a single direct-store kernel.
    Otherwise split-K with fp32 partials + fused reduce/cast (fp32 end-to-end).
  - M  > 1: tl.dot GEMM with fused dequant (original (K//2, N) layout).
"""
from __future__ import annotations

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

GROUP_SIZE = 128
_NUM_SMS = 188  # RTX PRO 6000 Blackwell


# ---------------------------------------------------------------------------
# CUDA decode GEMV (M==1): one warp per output, fully-parallel K-reduction
# (32 lanes each do K/32 of the dot product, then warp shuffle-reduce),
# vectorized 16-byte loads with next-iteration prefetch. Single kernel,
# no split-K reduction overhead.
# ---------------------------------------------------------------------------
_CUDA_GEMM_SRC = r'''
#include <cuda_bf16.h>
#include <cstdint>
#include <torch/extension.h>

// One warp per output. Each lane reads 16 bytes (uint4) per K-iteration,
// covering 32 K-elements; the warp covers 512 bytes = 1024 K = 8 groups/iter.
// d1 = 1-deep prefetch (high-occupancy large-N), d2 = 2-deep (low-occupancy small-N).

#define GEMV_BODY_PREFETCH1 \
    int niters = KH >> 9; \
    uint4 wn = *reinterpret_cast<const uint4*>(wrow + 16 * lane); \
    _Pragma("unroll 4") \
    for (int it = 0; it < niters; it++) { \
        uint4 wv = wn; \
        int b = it * 512; \
        if (it + 1 < niters) wn = *reinterpret_cast<const uint4*>(wrow + b + 512 + 16 * lane); \
        int g = b / 64 + (lane >> 2); \
        float s = __bfloat162float(sc[(size_t)g * N + n]); \
        float zf = __bfloat162float(zz[(size_t)g * N + n]); \
        int k0 = 2 * b + 32 * lane; \
        __nv_bfloat16 xb[32]; \
        *reinterpret_cast<uint4*>(xb)      = *reinterpret_cast<const uint4*>(x + k0); \
        *reinterpret_cast<uint4*>(xb + 8)  = *reinterpret_cast<const uint4*>(x + k0 + 8); \
        *reinterpret_cast<uint4*>(xb + 16) = *reinterpret_cast<const uint4*>(x + k0 + 16); \
        *reinterpret_cast<uint4*>(xb + 24) = *reinterpret_cast<const uint4*>(x + k0 + 24); \
        const uint32_t* wp = reinterpret_cast<const uint32_t*>(&wv); \
        _Pragma("unroll") \
        for (int q = 0; q < 4; q++) { uint32_t p = wp[q]; int base = 8 * q; \
            _Pragma("unroll") \
            for (int j = 0; j < 4; j++) { unsigned int bv = (p >> (8 * j)) & 0xFFu; \
                float xe = __bfloat162float(xb[base + 2 * j]); float xo = __bfloat162float(xb[base + 2 * j + 1]); \
                float wl = ((float)(bv & 0xFu) - zf) * s; float wh = ((float)((bv >> 4) & 0xFu) - zf) * s; \
                acc += xe * wl + xo * wh; } } }

#define GEMV_BODY_PREFETCH2 \
    int niters = KH >> 9; \
    uint4 w0 = *reinterpret_cast<const uint4*>(wrow + 0 + 16 * lane); \
    uint4 w1 = (niters > 1) ? *reinterpret_cast<const uint4*>(wrow + 512 + 16 * lane) : w0; \
    _Pragma("unroll 4") \
    for (int it = 0; it < niters; it++) { \
        uint4 wv = w0; w0 = w1; \
        if (it + 2 < niters) w1 = *reinterpret_cast<const uint4*>(wrow + (it + 2) * 512 + 16 * lane); \
        int b = it * 512; \
        int g = b / 64 + (lane >> 2); \
        float s = __bfloat162float(sc[(size_t)g * N + n]); \
        float zf = __bfloat162float(zz[(size_t)g * N + n]); \
        int k0 = 2 * b + 32 * lane; \
        __nv_bfloat16 xb[32]; \
        *reinterpret_cast<uint4*>(xb)      = *reinterpret_cast<const uint4*>(x + k0); \
        *reinterpret_cast<uint4*>(xb + 8)  = *reinterpret_cast<const uint4*>(x + k0 + 8); \
        *reinterpret_cast<uint4*>(xb + 16) = *reinterpret_cast<const uint4*>(x + k0 + 16); \
        *reinterpret_cast<uint4*>(xb + 24) = *reinterpret_cast<const uint4*>(x + k0 + 24); \
        const uint32_t* wp = reinterpret_cast<const uint32_t*>(&wv); \
        _Pragma("unroll") \
        for (int q = 0; q < 4; q++) { uint32_t p = wp[q]; int base = 8 * q; \
            _Pragma("unroll") \
            for (int j = 0; j < 4; j++) { unsigned int bv = (p >> (8 * j)) & 0xFFu; \
                float xe = __bfloat162float(xb[base + 2 * j]); float xo = __bfloat162float(xb[base + 2 * j + 1]); \
                float wl = ((float)(bv & 0xFu) - zf) * s; float wh = ((float)((bv >> 4) & 0xFu) - zf) * s; \
                acc += xe * wl + xo * wh; } } }

__global__ void w4a16_gemv_kernel_d1(
    const __nv_bfloat16* __restrict__ x, const uint8_t* __restrict__ wqt,
    const __nv_bfloat16* __restrict__ sc, const __nv_bfloat16* __restrict__ zz,
    __nv_bfloat16* __restrict__ y, int N, int K, int KH) {
    int wpb = blockDim.x >> 5;
    int warp = threadIdx.x >> 5;
    int lane = threadIdx.x & 31;
    int n = blockIdx.x * wpb + warp;
    if (n >= N) return;
    const uint8_t* wrow = wqt + (size_t)n * KH;
    float acc = 0.f;
    GEMV_BODY_PREFETCH1
    #pragma unroll
    for (int off = 16; off > 0; off >>= 1) acc += __shfl_xor_sync(0xffffffff, acc, off);
    if (lane == 0) y[n] = __float2bfloat16(acc);
}

__global__ void w4a16_gemv_kernel_d2(
    const __nv_bfloat16* __restrict__ x, const uint8_t* __restrict__ wqt,
    const __nv_bfloat16* __restrict__ sc, const __nv_bfloat16* __restrict__ zz,
    __nv_bfloat16* __restrict__ y, int N, int K, int KH) {
    int wpb = blockDim.x >> 5;
    int warp = threadIdx.x >> 5;
    int lane = threadIdx.x & 31;
    int n = blockIdx.x * wpb + warp;
    if (n >= N) return;
    const uint8_t* wrow = wqt + (size_t)n * KH;
    float acc = 0.f;
    GEMV_BODY_PREFETCH2
    #pragma unroll
    for (int off = 16; off > 0; off >>= 1) acc += __shfl_xor_sync(0xffffffff, acc, off);
    if (lane == 0) y[n] = __float2bfloat16(acc);
}

void launch_w4a16_gemv(torch::Tensor x, torch::Tensor wqt, torch::Tensor sc,
                       torch::Tensor zz, torch::Tensor out, int wpb, int depth) {
    int N = out.size(1);
    int K = x.size(1);
    int KH = K / 2;
    int block = wpb * 32;
    int grid_n = (N + wpb - 1) / wpb;
    if (depth <= 1)
        w4a16_gemv_kernel_d1<<<grid_n, block>>>(
            reinterpret_cast<const __nv_bfloat16*>(x.data_ptr()),
            reinterpret_cast<const uint8_t*>(wqt.data_ptr()),
            reinterpret_cast<const __nv_bfloat16*>(sc.data_ptr()),
            reinterpret_cast<const __nv_bfloat16*>(zz.data_ptr()),
            reinterpret_cast<__nv_bfloat16*>(out.data_ptr()), N, K, KH);
    else
        w4a16_gemv_kernel_d2<<<grid_n, block>>>(
            reinterpret_cast<const __nv_bfloat16*>(x.data_ptr()),
            reinterpret_cast<const uint8_t*>(wqt.data_ptr()),
            reinterpret_cast<const __nv_bfloat16*>(sc.data_ptr()),
            reinterpret_cast<const __nv_bfloat16*>(zz.data_ptr()),
            reinterpret_cast<__nv_bfloat16*>(out.data_ptr()), N, K, KH);
}
'''

_CUDA_CPP = ("void launch_w4a16_gemv(torch::Tensor x, torch::Tensor wqt, "
             "torch::Tensor sc, torch::Tensor zz, torch::Tensor out, int wpb, int depth);")


def _try_compile_cuda():
    try:
        from torch.utils.cpp_extension import load_inline
        return load_inline(
            name="w4a16_gemv_sm120",
            cpp_sources=_CUDA_CPP,
            cuda_sources=_CUDA_GEMM_SRC,
            functions=["launch_w4a16_gemv"],
            verbose=False,
        )
    except Exception:
        return None


_CUDA_MOD = _try_compile_cuda()


# ---------------------------------------------------------------------------
# Decode path: M == 1, split-K GEMV on transposed weight (N, K//2).
# ---------------------------------------------------------------------------
@triton.jit
def _w4a16_gemv_kernel(
    x_ptr, wqt_ptr, s_ptr, z_ptr, out_ptr,
    N, KH,                 # KH = K//2
    stride_sn, stride_sg, stride_out,
    SKB: tl.constexpr,     # split size in bytes (multiple of 64)
    BK: tl.constexpr, BN: tl.constexpr, GPT: tl.constexpr,   # BK = 64*GPT
    STORE_DIRECT: tl.constexpr,
):
    pid_n = tl.program_id(0)
    pid_k = tl.program_id(1)

    offs_n = pid_n * BN + tl.arange(0, BN)
    mn = offs_n < N
    kb_start = pid_k * SKB

    acc = tl.zeros((BN,), dtype=tl.float32)
    niters = SKB // BK
    for it in range(0, niters):
        kb = kb_start + it * BK
        gbase = kb // 64
        off_kb = kb + tl.arange(0, BK)
        w = tl.load(wqt_ptr + offs_n[:, None] * KH + off_kb[None, :],
                    mask=mn[:, None], other=0)                  # (BN, BK) uint8
        wlo = (w & 0xF).to(tl.bfloat16)
        whi = ((w >> 4) & 0xF).to(tl.bfloat16)
        # apply per-group scale/zero: (BN, GPT, 64) <- broadcast (BN, GPT)
        wlo = tl.reshape(wlo, (BN, GPT, 64))
        whi = tl.reshape(whi, (BN, GPT, 64))
        gg = gbase + tl.arange(0, GPT)
        s = tl.load(s_ptr + gg[:, None] * stride_sg + offs_n[None, :] * stride_sn,
                    mask=mn[None, :], other=0.0).to(tl.bfloat16)   # (GPT, BN)
        z = tl.load(z_ptr + gg[:, None] * stride_sg + offs_n[None, :] * stride_sn,
                    mask=mn[None, :], other=0.0).to(tl.bfloat16)
        s = tl.permute(s, (1, 0))                                   # (BN, GPT)
        z = tl.permute(z, (1, 0))
        wlo = (wlo - z[:, :, None]) * s[:, :, None]
        whi = (whi - z[:, :, None]) * s[:, :, None]
        wlo = tl.reshape(wlo, (BN, BK))
        whi = tl.reshape(whi, (BN, BK))
        xk = (2 * kb) + tl.arange(0, 2 * BK)
        xf = tl.load(x_ptr + xk)                                   # (2*BK,) bf16
        xr = tl.reshape(xf, (BK, 2))
        xe, xo = tl.split(xr)                                      # (BK,) each
        acc += tl.sum(xe[None, :].to(tl.float32) * wlo.to(tl.float32), axis=1)
        acc += tl.sum(xo[None, :].to(tl.float32) * whi.to(tl.float32), axis=1)

    if STORE_DIRECT:
        tl.store(out_ptr + offs_n, acc.to(tl.bfloat16), mask=mn)
    else:
        tl.store(out_ptr + pid_k * stride_out + offs_n, acc, mask=mn)


@triton.jit
def _reduce_cast_kernel(p_ptr, y_ptr, N, NSPLIT, stride_pk, BN: tl.constexpr):
    pid = tl.program_id(0)
    offs = pid * BN + tl.arange(0, BN)
    mask = offs < N
    acc = tl.zeros((BN,), dtype=tl.float32)
    for i in range(0, NSPLIT):
        acc += tl.load(p_ptr + i * stride_pk + offs, mask=mask, other=0.0)
    tl.store(y_ptr + offs, acc.to(tl.bfloat16), mask=mask)


def _gemv_plan(N, K):
    KH = K // 2
    BN = 32
    n_groups = KH // 64
    nnt = triton.cdiv(N, BN)
    if N >= 8192:
        GPT, BK, nw, ns = 2, 128, 4, 3
    else:
        GPT, BK, nw, ns = 1, 64, 4, 4
    # split-K to ~6x SMs total blocks (caps occupancy-driven stalls).
    nspl = max(1, (6 * _NUM_SMS) // nnt)
    nspl = min(nspl, n_groups)
    while nspl > 1 and (KH // nspl) % BK != 0:
        nspl -= 1
    SKB = KH // nspl
    return dict(BN=BN, GPT=GPT, BK=BK, nw=nw, ns=ns, nspl=nspl, SKB=SKB, nnt=nnt)


def _gemv(x, wqt, scales, zeros, N, K, plan, partial):
    KH = K // 2
    y = torch.empty((1, N), dtype=torch.bfloat16, device=x.device)
    _w4a16_gemv_kernel[(plan["nnt"], plan["nspl"])](
        x, wqt, scales, zeros, partial,
        N, KH,
        scales.stride(1), scales.stride(0), partial.stride(0),
        SKB=plan["SKB"], BK=plan["BK"], BN=plan["BN"], GPT=plan["GPT"],
        STORE_DIRECT=False,
        num_warps=plan["nw"], num_stages=plan["ns"],
    )
    _reduce_cast_kernel[(triton.cdiv(N, plan["BN"]),)](
        partial, y, N, plan["nspl"], partial.stride(0),
        BN=plan["BN"], num_warps=4, num_stages=1,
    )
    return y


# ---------------------------------------------------------------------------
# Prefill path: M > 1, tl.dot GEMM with fused dequant (original layout).
# ---------------------------------------------------------------------------
@triton.jit
def _w4a16_gemm_kernel(
    x_ptr, wq_ptr, s_ptr, z_ptr, y_ptr,
    M, N, K,
    stride_xm, stride_xk,
    stride_wpk, stride_wn,
    stride_sg, stride_sn,
    stride_ym, stride_yn,
    BM: tl.constexpr, BN: tl.constexpr, BK: tl.constexpr,
    GROUP: tl.constexpr,
):
    pid_m = tl.program_id(0)
    pid_n = tl.program_id(1)

    offs_m = pid_m * BM + tl.arange(0, BM)
    offs_n = pid_n * BN + tl.arange(0, BN)
    offs_k = tl.arange(0, BK)

    mask_m = offs_m < M
    mask_n = offs_n < N

    acc = tl.zeros((BM, BN), dtype=tl.float32)
    n_kc = K // BK          # K-chunks of size BK (BK divides GROUP, so a quant
                            # group spans GROUP/BK chunks; scale indexed by k0//GROUP)
    BK_HALF: tl.constexpr = BK // 2

    for kc in range(0, n_kc):
        k0 = kc * BK
        g = k0 // GROUP
        x_ptrs = x_ptr + offs_m[:, None] * stride_xm + (k0 + offs_k)[None, :] * stride_xk
        x = tl.load(x_ptrs, mask=mask_m[:, None], other=0.0)
        x_r = tl.reshape(x, (BM, BK_HALF, 2))
        x_lo, x_hi = tl.split(x_r)

        pk_offs = (k0 // 2) + tl.arange(0, BK_HALF)
        w_ptrs = wq_ptr + pk_offs[:, None] * stride_wpk + offs_n[None, :] * stride_wn
        w_packed = tl.load(w_ptrs, mask=mask_n[None, :], other=0)
        w_lo = (w_packed & 0xF).to(tl.bfloat16)
        w_hi = ((w_packed >> 4) & 0xF).to(tl.bfloat16)

        s = tl.load(s_ptr + g * stride_sg + offs_n * stride_sn, mask=mask_n, other=0.0).to(tl.bfloat16)
        z = tl.load(z_ptr + g * stride_sg + offs_n * stride_sn, mask=mask_n, other=0.0).to(tl.bfloat16)
        w_lo = (w_lo - z[None, :]) * s[None, :]
        w_hi = (w_hi - z[None, :]) * s[None, :]

        acc = tl.dot(x_lo, w_lo, acc=acc, allow_tf32=False)
        acc = tl.dot(x_hi, w_hi, acc=acc, allow_tf32=False)

    y_ptrs = y_ptr + offs_m[:, None] * stride_ym + offs_n[None, :] * stride_yn
    tl.store(y_ptrs, acc.to(tl.bfloat16), mask=mask_m[:, None] & mask_n[None, :])


def _gemm(x, wq, scales, zeros, M, N, K, y=None):
    if y is None:
        y = torch.empty((M, N), dtype=torch.bfloat16, device=x.device)
    if M >= 128:
        BM, BN, nw, ns, BK = 64, 128, 8, 3, 128
    elif M >= 32:
        BM, BN, nw, ns, BK = 32, 128, 8, 5, 128
    else:
        BM, BN, nw, ns, BK = 16, 128, 8, 5, 128
    grid = (triton.cdiv(M, BM), triton.cdiv(N, BN))
    _w4a16_gemm_kernel[grid](
        x, wq, scales, zeros, y,
        M, N, K,
        x.stride(0), x.stride(1),
        wq.stride(0), wq.stride(1),
        scales.stride(0), scales.stride(1),
        y.stride(0), y.stride(1),
        BM=BM, BN=BN, BK=BK, GROUP=GROUP_SIZE,
        num_warps=nw, num_stages=ns,
    )
    return y


class Model(nn.Module):
    def __init__(self, M: int, N: int, K: int, group_size: int = GROUP_SIZE):
        super().__init__()
        self.M, self.N, self.K = M, N, K
        self.group_size = group_size
        self.register_buffer("w_q", torch.empty((K // 2, N), dtype=torch.uint8))
        self.register_buffer("scales", torch.empty((K // group_size, N), dtype=torch.bfloat16))
        self.register_buffer("zeros", torch.empty((K // group_size, N), dtype=torch.bfloat16))
        self._wqt = None
        self._partial = None
        self._plan = None
        self._yout = None
        self._gemm_out = None
        self._wpb = 4

    def _ensure_setup(self):
        if self._wqt is None:
            self._wqt = self.w_q.t().contiguous()
        if self._plan is None:
            self._plan = _gemv_plan(self.N, self.K)
            self._partial = torch.empty(
                (self._plan["nspl"], self.N), dtype=torch.float32, device=self.w_q.device)
            self._wpb = 4
            self._depth = 1 if self.N >= 8192 else 2
            self._yout = torch.empty((1, self.N), dtype=torch.bfloat16, device=self.w_q.device)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        if x.dtype != torch.bfloat16:
            x = x.to(torch.bfloat16)
        M = x.shape[0]
        if M == 1:
            self._ensure_setup()
            if _CUDA_MOD is not None:
                _CUDA_MOD.launch_w4a16_gemv(x, self._wqt, self.scales, self.zeros,
                                            self._yout, self._wpb, self._depth)
                return self._yout
            return _gemv(x, self._wqt, self.scales, self.zeros, self.N, self.K,
                         self._plan, self._partial)
        if self._gemm_out is None:
            self._gemm_out = torch.empty((self.M, self.N), dtype=torch.bfloat16, device=x.device)
        return _gemm(x, self.w_q, self.scales, self.zeros, M, self.N, self.K, self._gemm_out)


M = 1
N = 12288
K = 4096


def get_inputs():
    x = torch.randn(M, K, dtype=torch.bfloat16, device="cuda")
    return [x]


def get_init_inputs():
    return [M, N, K]

20260613_061443_zai-claude_glm-5.2_07_w4a16_gemm