KernelBench cuda · RTX PRO 6000

DeepSeek NSA Claude Fable 5

cleandid not score

manually audited: clean

Genuine block-centric CUDA NSA sparse attention via load_inline, tensor-core mma (mma.sync m16n8k16 bf16 + ldmatrix inline PTX). Five-stage pipeline: (1) kmean precompute collapses sub-diagonal block scoring from O(S^2 D) to O(S*nb*D) using the linearity of the mean (importance = scale * q . mean(k)); (2) warp-per-query select kernel adds the diagonal partial causal mean, does register-resident top-8 with the reference's tie-to-larger-index rule, unions the 64-token sliding window, and builds per-(bh,block) subscriber counts; (3) device cumsum CSR + scatter; (4) block-centric split-softmax attention (flash-decoding style, one CTA per key block, K/V staged to XOR-swizzled shared memory once, warps serve 16 subscribers via tensor cores) — inverting the query loop so each K/V block is read from L2 once instead of by every subscriber; (5) per-query logsumexp combine of <=10 partials. Exact split softmax, fp32 accumulation, fp32 (non-TF32) bmm for selection ordering. Rebench 0.2934 geomean matches the in-run number (0.2934) — no contention inflation. Low fraction is by design (dense-equivalent FLOPs formula vs a correct sparse kernel); per-shape fractions reach 0.86.

harnessor-fable (containerized, nvcr tensorrt-llm/release:1.2.1, live CUDA, GPU lock)agent session1h 37mtotal wall1h 37mcheck3sbenchmark1soutput tokensgpu-lock wait19mgpu-lock held10mregimecompute

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

1×16×2048×640.220 ms15.6%78 TFLOPS · 16% of 500 TF bf16 peak · also 0.08 TB/s (4% of HBM)
1×16×4127×640.390 ms35.8%179 TFLOPS · 36% of 500 TF bf16 peak · also 0.09 TB/s (5% of HBM)
1×8×8192×640.411 ms66.9%335 TFLOPS · 67% of 500 TF bf16 peak · also 0.08 TB/s (5% of HBM)
1×8×8191×1280.639 ms86.0%430 TFLOPS · 86% of 500 TF bf16 peak · also 0.10 TB/s (6% of HBM)
4×8×1024×640.203 ms8.5%42 TFLOPS · 8% of 500 TF bf16 peak · also 0.08 TB/s (5% of HBM)
2×8×3000×640.314 ms23.5%117 TFLOPS · 24% of 500 TF bf16 peak · also 0.08 TB/s (4% of HBM)

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

geomean(15.6% · 35.8% · 66.9% · 86.0% · 8.5% · 23.5%) = 29.3%

Kernel source (redacted)
"""DeepSeek NSA-style block-sparse attention — block-centric CUDA (SM120).

Semantics match reference.nsa_attend:
  per query t: block importance = mean of (q.k * scale) over causal keys in
  each 64-key block; top-8 blocks (ties -> larger block index, matching the
  Python tuple sort) unioned with the last-64-token sliding window; softmax
  attention over the selected indices only.

Selection uses the linear-mean reduction: for blocks entirely below t the
importance is scale * q . mean(k_block), so a precompute kernel collapses the
O(S^2 D) scoring pass to O(S * nb * D); only the diagonal block needs the
partial causal mean.

The attention itself is block-centric split-softmax (flash-decoding style).
A query-centric gather kernel is bound by L2 random-gather bandwidth
(~7.3 TB/s measured for this access pattern) because every K/V block is
re-fetched by each of its ~hundreds of subscriber queries. Inverting the loop
reads each block from L2 exactly once:
  1. kmean precompute
  2. select: per-query importance + top-8 + union(list) with the window;
     atomic per-(bh,block) subscriber counts
  3. CSR offsets (device cumsum) + scatter of subscriber entries
  4. block attention: one CTA per (bh, block); K/V staged to shared memory
     once; each warp serves one subscriber (masked scores over the block,
     exp, PV) and emits a partial (m, l, acc) — exact split softmax
  5. combine: per query, logsumexp-merge its <=10 partials and normalize
Shared-memory rows are padded to an odd word stride so both the transposed
score loads and the dim-owner PV loads are bank-conflict-free.
"""
from __future__ import annotations

import os

import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

os.environ.setdefault("TORCH_CUDA_ARCH_LIST", "12.0")

# Selection ordering must match the reference's fp32-precision dots; keep the
# importance bmm on the full-precision fp32 path, never TF32.
torch.backends.cuda.matmul.allow_tf32 = False

BLOCK_SIZE = 64
TOP_N_BLOCKS = 8
SLIDING_WINDOW = 64

_CUDA_SRC = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda_bf16.h>
#include <cuda_runtime.h>
#include <math_constants.h>

#define BS 64
#define TOPN 8
#define WIN 64
#define SEL_WARPS 16
#define MAX_BLOCKS 128   // supports S <= 8192
#define MAX_UNION 10     // <=8 selected below the window + <=2 window blocks

using bf16 = __nv_bfloat16;

struct F8 { float f[8]; };

__device__ __forceinline__ float oct_sum(float v) {
#pragma unroll
    for (int off = 4; off > 0; off >>= 1)
        v += __shfl_xor_sync(0xffffffffu, v, off);
    return v;
}

__device__ __forceinline__ float quad_sum(float v) {
    v += __shfl_xor_sync(0xffffffffu, v, 1);
    v += __shfl_xor_sync(0xffffffffu, v, 2);
    return v;
}

__device__ __forceinline__ float warp_sum(float v) {
#pragma unroll
    for (int off = 16; off > 0; off >>= 1)
        v += __shfl_xor_sync(0xffffffffu, v, off);
    return v;
}

__device__ __forceinline__ float warp_max(float v) {
#pragma unroll
    for (int off = 16; off > 0; off >>= 1)
        v = fmaxf(v, __shfl_xor_sync(0xffffffffu, v, off));
    return v;
}

__device__ __forceinline__ F8 load_bf16x8(const bf16* p) {
    uint4 raw = *reinterpret_cast<const uint4*>(p);
    F8 r;
    const unsigned w[4] = {raw.x, raw.y, raw.z, raw.w};
#pragma unroll
    for (int i = 0; i < 4; ++i) {
        __nv_bfloat162 ab = *reinterpret_cast<const __nv_bfloat162*>(&w[i]);
        r.f[2 * i] = __bfloat162float(ab.x);
        r.f[2 * i + 1] = __bfloat162float(ab.y);
    }
    return r;
}

__device__ __forceinline__ float2 unpack_bf2(unsigned w) {
    __nv_bfloat162 h = *reinterpret_cast<__nv_bfloat162*>(&w);
    return __bfloat1622float2(h);
}

// Per-block mean of K in fp32. Only consumed for blocks fully below the
// diagonal (always 64 keys); the trailing partial block's value is never
// read, so /64 is safe.
__global__ void kmean_kernel(const bf16* __restrict__ k, float* __restrict__ km,
                             int S, int nb, int D) {
    const int bi = blockIdx.x;
    const int bh = blockIdx.y;
    const int d = threadIdx.x;
    const int s0 = bi * BS;
    const int cnt = min(BS, S - s0);
    const bf16* kp = k + ((long)bh * S + s0) * D + d;
    float sum = 0.f;
    for (int j = 0; j < cnt; ++j) sum += __bfloat162float(kp[(long)j * D]);
    km[((long)bh * nb + bi) * D + d] = sum * (1.f / BS);
}

// One warp per query: top-8 over precomputed sub-diagonal importances (from
// the fp32 bmm q @ kmean^T) plus the diagonal partial causal mean computed
// here; ties -> larger index; then the union with the sliding window. Emits
// the per-query union list (block index | selected-flag<<30) and bumps the
// per-(bh,block) subscriber count.
template <int D>
__global__ void __launch_bounds__(32 * SEL_WARPS) select_kernel(
        const bf16* __restrict__ q, const bf16* __restrict__ k,
        const float* __restrict__ imp_in,
        int* __restrict__ ulist, int* __restrict__ ucnt,
        int* __restrict__ bcount, int S, int nb) {
    constexpr int C = D / 64;
    const int warp = threadIdx.x >> 5;
    const int lane = threadIdx.x & 31;
    const int og = lane >> 2;  // quad id: 8 blocks (or keys) per iteration
    const int ol = lane & 3;   // quad lane: 16 dims per lane per 64-chunk
    const int t = blockIdx.x * SEL_WARPS + warp;
    const int bh = blockIdx.y;

    // Per-CTA histogram of subscriber counts; one global flush at the end
    // (per-query global atomics on the hot shared counters were ~3x the cost
    // of the whole rest of this kernel).
    __shared__ int scount[MAX_BLOCKS];
    if (threadIdx.x < MAX_BLOCKS) scount[threadIdx.x] = 0;
    __syncthreads();

    if (t < S) {
    const float scale = rsqrtf((float)D);
    const int tb = t >> 6;
    const int w0 = max(0, t - (WIN - 1));
    const int w0b = w0 >> 6;

    F8 qv[2 * C];
    const bf16* qp = q + ((long)bh * S + t) * D;
#pragma unroll
    for (int c = 0; c < C; ++c) {
        qv[2 * c] = load_bf16x8(qp + c * 64 + ol * 16);
        qv[2 * c + 1] = load_bf16x8(qp + c * 64 + ol * 16 + 8);
    }

    // Importances live in registers: lane L owns blocks {c*32 + L}. The
    // sub-diagonal rows come straight from the precomputed fp32 bmm.
    float impreg[MAX_BLOCKS / 32];
    const float* irow = imp_in + ((long)bh * S + t) * nb;
#pragma unroll
    for (int c = 0; c < MAX_BLOCKS / 32; ++c) {
        const int bi = c * 32 + lane;
        impreg[c] = (bi < tb) ? irow[bi] * scale : -CUDART_INF_F;
    }
    {   // diagonal block: partial causal mean over [tb*64, t]
        const int s0 = tb << 6;
        const int cnt = t - s0 + 1;
        const bf16* kb = k + ((long)bh * S + s0) * D;
        float ssum = 0.f;
        for (int j0 = 0; j0 < cnt; j0 += 8) {
            const int jj = j0 + og;
            float part = 0.f;
            if (jj < cnt) {
#pragma unroll
                for (int cc = 0; cc < C; ++cc) {
                    F8 ka = load_bf16x8(kb + (long)jj * D + cc * 64 + ol * 16);
                    F8 kc = load_bf16x8(kb + (long)jj * D + cc * 64 + ol * 16 + 8);
#pragma unroll
                    for (int i = 0; i < 8; ++i)
                        part += qv[2 * cc].f[i] * ka.f[i] +
                                qv[2 * cc + 1].f[i] * kc.f[i];
                }
            }
            ssum += quad_sum(part);
        }
        ssum += __shfl_xor_sync(0xffffffffu, ssum, 4);
        ssum += __shfl_xor_sync(0xffffffffu, ssum, 8);
        ssum += __shfl_xor_sync(0xffffffffu, ssum, 16);
        const float dval = ssum * scale / (float)cnt;
#pragma unroll
        for (int c = 0; c < MAX_BLOCKS / 32; ++c)
            if ((tb >> 5) == c && (tb & 31) == lane) impreg[c] = dval;
    }

    int sel[TOPN];
#pragma unroll
    for (int r = 0; r < TOPN; ++r) sel[r] = -1;
#pragma unroll
    for (int r = 0; r < TOPN; ++r) {
        float bv = -CUDART_INF_F;
        int bbi = -1;
#pragma unroll
        for (int c = 0; c < MAX_BLOCKS / 32; ++c) {
            const int bi = c * 32 + lane;
            const float vv = impreg[c];
            if (vv > bv || (vv == bv && bi > bbi)) { bv = vv; bbi = bi; }
        }
#pragma unroll
        for (int off = 16; off > 0; off >>= 1) {
            float ov = __shfl_xor_sync(0xffffffffu, bv, off);
            int obi = __shfl_xor_sync(0xffffffffu, bbi, off);
            if (ov > bv || (ov == bv && obi > bbi)) { bv = ov; bbi = obi; }
        }
        if (bbi < 0 || bv == -CUDART_INF_F) break;
        sel[r] = bbi;
#pragma unroll
        for (int c = 0; c < MAX_BLOCKS / 32; ++c)
            if (bbi == c * 32 + lane) impreg[c] = -CUDART_INF_F;
    }

    if (lane == 0) {
        const long gq = (long)bh * S + t;
        int list[MAX_UNION];
        int u = 0;
        for (int bi = w0b; bi <= tb; ++bi) {
            bool sh = false;
#pragma unroll
            for (int r = 0; r < TOPN; ++r) sh |= (sel[r] == bi);
            list[u++] = bi | (sh ? (1 << 30) : 0);
        }
#pragma unroll
        for (int r = 0; r < TOPN; ++r)
            if (sel[r] >= 0 && sel[r] < w0b) list[u++] = sel[r] | (1 << 30);
        ucnt[gq] = u;
        for (int i = 0; i < u; ++i) {
            ulist[gq * MAX_UNION + i] = list[i];
            atomicAdd(&scount[list[i] & 0xffff], 1);
        }
    }
    }  // t < S
    __syncthreads();
    if (threadIdx.x < MAX_BLOCKS) {
        const int c = threadIdx.x;
        const int v = scount[c];
        if (v && c < nb) atomicAdd(&bcount[bh * nb + c], v);
    }
}

// Thread per query: place its union entries into the per-(bh,block) CSR
// segments and remember each entry's slot for the combine pass.
__global__ void scatter_kernel(const int* __restrict__ ulist,
                               const int* __restrict__ ucnt,
                               int* __restrict__ cursor,
                               int* __restrict__ entries,
                               int* __restrict__ qpos, int S, int nb, long Q) {
    const long gq = (long)blockIdx.x * blockDim.x + threadIdx.x;
    if (gq >= Q) return;
    const int bh = (int)(gq / S);
    const int t = (int)(gq % S);
    const int u = ucnt[gq];
    for (int i = 0; i < u; ++i) {
        const int e = ulist[gq * MAX_UNION + i];
        const int bi = e & 0xffff;
        const unsigned flag = ((unsigned)e >> 30) & 1u;
        const int pos = atomicAdd(&cursor[bh * nb + bi], 1);
        entries[pos] = t | (int)(flag << 31);
        qpos[gq * MAX_UNION + i] = pos;
    }
}

// --- tensor-core plumbing (mma.m16n8k16 bf16 -> fp32, FA2-style layouts) ---
__device__ __forceinline__ void mma_bf16(float& d0, float& d1, float& d2,
                                         float& d3, unsigned a0, unsigned a1,
                                         unsigned a2, unsigned a3, unsigned b0,
                                         unsigned b1) {
    asm volatile(
        "mma.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32 "
        "{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%0,%1,%2,%3};\n"
        : "+f"(d0), "+f"(d1), "+f"(d2), "+f"(d3)
        : "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(b0), "r"(b1));
}

__device__ __forceinline__ void ldm_x4(unsigned& r0, unsigned& r1, unsigned& r2,
                                       unsigned& r3, const bf16* p) {
    const unsigned a = (unsigned)__cvta_generic_to_shared(p);
    asm volatile("ldmatrix.sync.aligned.m8n8.x4.shared.b16 {%0,%1,%2,%3}, [%4];\n"
                 : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3)
                 : "r"(a));
}

__device__ __forceinline__ void ldm_x2(unsigned& r0, unsigned& r1, const bf16* p) {
    const unsigned a = (unsigned)__cvta_generic_to_shared(p);
    asm volatile("ldmatrix.sync.aligned.m8n8.x2.shared.b16 {%0,%1}, [%2];\n"
                 : "=r"(r0), "=r"(r1)
                 : "r"(a));
}

__device__ __forceinline__ void ldm_x2_t(unsigned& r0, unsigned& r1,
                                         const bf16* p) {
    const unsigned a = (unsigned)__cvta_generic_to_shared(p);
    asm volatile(
        "ldmatrix.sync.aligned.m8n8.x2.trans.shared.b16 {%0,%1}, [%2];\n"
        : "=r"(r0), "=r"(r1)
        : "r"(a));
}

__device__ __forceinline__ unsigned pack_bf2(float x, float y) {
    __nv_bfloat162 h = __floats2bfloat162_rn(x, y);
    return *reinterpret_cast<unsigned*>(&h);
}

// XOR-swizzled shared tile address: rows of D bf16, 16-byte chunk c of row r
// lives at chunk (c ^ (r & 7)) so ldmatrix row-vector reads (8 rows, fixed c)
// hit 8 distinct bank groups. All accesses are 16B-chunk granular.
template <int CH>
__device__ __forceinline__ bf16* swz(bf16* base, int r, int c) {
    return base + (((r * CH) + (c ^ (r & 7))) << 3);
}

// One CTA per (bh, key-block): stage K/V to shared once; each warp serves 16
// subscriber queries per round via tensor cores. Score S = Q(16xD) @ K^T,
// masked/softmaxed in C fragments, P repacked in-register as the A operand of
// PV = P(16x64) @ V(64xD). Emits exact split-softmax partials per subscriber.
template <int D>
__global__ void __launch_bounds__(128) block_attn_kernel(
        const bf16* __restrict__ q, const bf16* __restrict__ k,
        const bf16* __restrict__ v,
        const int* __restrict__ offsets, const int* __restrict__ entries,
        float2* __restrict__ ml, bf16* __restrict__ oacc, int S, int nb) {
    constexpr int CH = D / 8;    // 16B chunks per row
    constexpr int NT = D / 8;    // 8-dim output tiles
    const int cta = blockIdx.x;
    const int bh = cta / nb;
    const int bi = cta - bh * nb;
    const int s0 = bi * BS;
    const int i0 = offsets[cta];
    const int i1 = offsets[cta + 1];
    // Subscriber lists are skewed (early blocks collect ~3.5x the mean), so
    // split each list across gridDim.y chunk-CTAs.
    const int istart = i0 + (int)blockIdx.y * (4 * 16);
    if (istart >= i1) return;
    const int istride = (int)gridDim.y * (4 * 16);

    __shared__ bf16 ks[BS * D];
    __shared__ bf16 vs[BS * D];
    __shared__ bf16 qt[4][16 * D];

    const int tid = threadIdx.x;
    const int nrows = min(BS, S - s0);
    {
        const bf16* kbase = k + ((long)bh * S + s0) * D;
        const bf16* vbase = v + ((long)bh * S + s0) * D;
        for (int i = tid; i < BS * CH; i += 128) {
            const int r = i / CH;
            const int c = i - r * CH;
            uint4 kw = make_uint4(0u, 0u, 0u, 0u), vw = kw;
            if (r < nrows) {
                kw = *reinterpret_cast<const uint4*>(kbase + (long)r * D + c * 8);
                vw = *reinterpret_cast<const uint4*>(vbase + (long)r * D + c * 8);
            }
            *reinterpret_cast<uint4*>(swz<CH>(ks, r, c)) = kw;
            *reinterpret_cast<uint4*>(swz<CH>(vs, r, c)) = vw;
        }
    }
    __syncthreads();

    const int warp = tid >> 5;
    const int lane = tid & 31;
    const float scale = rsqrtf((float)D);
    const int r0 = lane >> 2;          // C-fragment rows r0 and r0+8
    const int qq = lane & 3;           // in-row quad position

    for (int base = istart + warp * 16; base < i1; base += istride) {
        const int nsub = min(16, i1 - base);
        int t_ = 0, lo_ = 1, hi_ = 0;
        if (lane < nsub) {
            const unsigned e = (unsigned)entries[base + lane];
            t_ = (int)(e & 0x7fffffffu);
            const bool selhit = (e >> 31) != 0u;
            lo_ = selhit ? 0 : max(0, (t_ - (WIN - 1)) - s0);
            hi_ = min(BS - 1, t_ - s0);
        }
        // stage the 16 q rows (swizzled, zero the tail slots)
        for (int i = lane; i < 16 * CH; i += 32) {
            const int ss = i / CH;
            const int c = i - ss * CH;
            const int tt = __shfl_sync(0xffffffffu, t_, ss);
            uint4 w = make_uint4(0u, 0u, 0u, 0u);
            if (ss < nsub)
                w = *reinterpret_cast<const uint4*>(
                    q + ((long)bh * S + tt) * D + c * 8);
            *reinterpret_cast<uint4*>(swz<CH>(qt[warp], ss, c)) = w;
        }
        __syncwarp();
        const int lo0 = __shfl_sync(0xffffffffu, lo_, r0);
        const int hi0 = __shfl_sync(0xffffffffu, hi_, r0);
        const int lo1 = __shfl_sync(0xffffffffu, lo_, r0 + 8);
        const int hi1 = __shfl_sync(0xffffffffu, hi_, r0 + 8);

        // scores: 8 key-tiles of 16x8, accumulated over D/16 k-steps
        float sc[8][4];
#pragma unroll
        for (int nt = 0; nt < 8; ++nt)
            sc[nt][0] = sc[nt][1] = sc[nt][2] = sc[nt][3] = 0.f;
#pragma unroll
        for (int kk = 0; kk < D / 16; ++kk) {
            unsigned a0, a1, a2, a3;
            {   // A tiles: [rows0-7,klo][rows8-15,klo][rows0-7,khi][rows8-15,khi]
                const int tile = lane >> 3;
                const int ar = (lane & 7) + (tile & 1) * 8;
                const int ac = kk * 2 + (tile >> 1);
                ldm_x4(a0, a1, a2, a3, swz<CH>(qt[warp], ar, ac));
            }
            const int bl = lane & 15;
            const int brc = kk * 2 + (bl >> 3);
#pragma unroll
            for (int nt = 0; nt < 8; ++nt) {
                unsigned b0, b1;
                ldm_x2(b0, b1, swz<CH>(ks, nt * 8 + (bl & 7), brc));
                mma_bf16(sc[nt][0], sc[nt][1], sc[nt][2], sc[nt][3],
                         a0, a1, a2, a3, b0, b1);
            }
        }

        // mask + row max
        float m0 = -CUDART_INF_F, m1 = -CUDART_INF_F;
#pragma unroll
        for (int nt = 0; nt < 8; ++nt) {
            const int j0 = nt * 8 + 2 * qq;
            const int j1 = j0 + 1;
            sc[nt][0] = (j0 >= lo0 && j0 <= hi0) ? sc[nt][0] * scale : -CUDART_INF_F;
            sc[nt][1] = (j1 >= lo0 && j1 <= hi0) ? sc[nt][1] * scale : -CUDART_INF_F;
            sc[nt][2] = (j0 >= lo1 && j0 <= hi1) ? sc[nt][2] * scale : -CUDART_INF_F;
            sc[nt][3] = (j1 >= lo1 && j1 <= hi1) ? sc[nt][3] * scale : -CUDART_INF_F;
            m0 = fmaxf(m0, fmaxf(sc[nt][0], sc[nt][1]));
            m1 = fmaxf(m1, fmaxf(sc[nt][2], sc[nt][3]));
        }
        m0 = fmaxf(m0, __shfl_xor_sync(0xffffffffu, m0, 1));
        m0 = fmaxf(m0, __shfl_xor_sync(0xffffffffu, m0, 2));
        m1 = fmaxf(m1, __shfl_xor_sync(0xffffffffu, m1, 1));
        m1 = fmaxf(m1, __shfl_xor_sync(0xffffffffu, m1, 2));
        const float mu0 = fmaxf(m0, -1e30f);   // empty rows: exp -> 0, not NaN
        const float mu1 = fmaxf(m1, -1e30f);
        float l0 = 0.f, l1 = 0.f;
#pragma unroll
        for (int nt = 0; nt < 8; ++nt) {
            sc[nt][0] = __expf(sc[nt][0] - mu0);
            sc[nt][1] = __expf(sc[nt][1] - mu0);
            sc[nt][2] = __expf(sc[nt][2] - mu1);
            sc[nt][3] = __expf(sc[nt][3] - mu1);
            l0 += sc[nt][0] + sc[nt][1];
            l1 += sc[nt][2] + sc[nt][3];
        }
        l0 += __shfl_xor_sync(0xffffffffu, l0, 1);
        l0 += __shfl_xor_sync(0xffffffffu, l0, 2);
        l1 += __shfl_xor_sync(0xffffffffu, l1, 1);
        l1 += __shfl_xor_sync(0xffffffffu, l1, 2);

        // PV: A = P (C fragments repacked to bf16), B = V via trans ldmatrix
        float o[NT][4];
#pragma unroll
        for (int nt = 0; nt < NT; ++nt)
            o[nt][0] = o[nt][1] = o[nt][2] = o[nt][3] = 0.f;
#pragma unroll
        for (int kk = 0; kk < 4; ++kk) {
            const unsigned pa0 = pack_bf2(sc[2 * kk][0], sc[2 * kk][1]);
            const unsigned pa1 = pack_bf2(sc[2 * kk][2], sc[2 * kk][3]);
            const unsigned pa2 = pack_bf2(sc[2 * kk + 1][0], sc[2 * kk + 1][1]);
            const unsigned pa3 = pack_bf2(sc[2 * kk + 1][2], sc[2 * kk + 1][3]);
            const int vr = kk * 16 + (lane & 15);   // 16 key rows per step
#pragma unroll
            for (int nt = 0; nt < NT; ++nt) {
                unsigned b0, b1;
                ldm_x2_t(b0, b1, swz<CH>(vs, vr, nt));
                mma_bf16(o[nt][0], o[nt][1], o[nt][2], o[nt][3],
                         pa0, pa1, pa2, pa3, b0, b1);
            }
        }

        if (qq == 0) {
            if (r0 < nsub) ml[base + r0] = make_float2(m0, l0);
            if (r0 + 8 < nsub) ml[base + r0 + 8] = make_float2(m1, l1);
        }
        if (r0 < nsub) {
            bf16* oa = oacc + (long)(base + r0) * D;
#pragma unroll
            for (int nt = 0; nt < NT; ++nt)
                *reinterpret_cast<unsigned*>(oa + nt * 8 + 2 * qq) =
                    pack_bf2(o[nt][0], o[nt][1]);
        }
        if (r0 + 8 < nsub) {
            bf16* oa = oacc + (long)(base + r0 + 8) * D;
#pragma unroll
            for (int nt = 0; nt < NT; ++nt)
                *reinterpret_cast<unsigned*>(oa + nt * 8 + 2 * qq) =
                    pack_bf2(o[nt][2], o[nt][3]);
        }
        __syncwarp();
    }
}

// One warp per query: logsumexp-combine its partials, normalize, store bf16.
template <int D>
__global__ void __launch_bounds__(256) combine_kernel(
        const int* __restrict__ ucnt, const int* __restrict__ qpos,
        const float2* __restrict__ ml, const bf16* __restrict__ oacc,
        bf16* __restrict__ o, long Q) {
    const int warp = threadIdx.x >> 5;
    const int lane = threadIdx.x & 31;
    const long gq = (long)blockIdx.x * 8 + warp;
    if (gq >= Q) return;

    const int u = ucnt[gq];
    int pos[MAX_UNION];
    float2 mls[MAX_UNION];
    float m = -CUDART_INF_F;
    for (int i = 0; i < u; ++i) {
        pos[i] = qpos[gq * MAX_UNION + i];
        mls[i] = ml[pos[i]];
        m = fmaxf(m, mls[i].x);
    }
    float L = 0.f;
    float a0 = 0.f, a1 = 0.f, a2 = 0.f, a3 = 0.f;
    for (int i = 0; i < u; ++i) {
        const float c = __expf(mls[i].x - m);
        L += c * mls[i].y;
        const bf16* oa = oacc + (long)pos[i] * D;
        float2 f = unpack_bf2(*reinterpret_cast<const unsigned*>(oa + 2 * lane));
        a0 += c * f.x; a1 += c * f.y;
        if (D == 128) {
            f = unpack_bf2(*reinterpret_cast<const unsigned*>(oa + 2 * lane + 64));
            a2 += c * f.x; a3 += c * f.y;
        }
    }
    const float inv = 1.f / L;
    bf16* op = o + gq * D;
    __nv_bfloat162 h0;
    h0.x = __float2bfloat16(a0 * inv);
    h0.y = __float2bfloat16(a1 * inv);
    *reinterpret_cast<__nv_bfloat162*>(op + 2 * lane) = h0;
    if (D == 128) {
        __nv_bfloat162 h1;
        h1.x = __float2bfloat16(a2 * inv);
        h1.y = __float2bfloat16(a3 * inv);
        *reinterpret_cast<__nv_bfloat162*>(op + 2 * lane + 64) = h1;
    }
}

torch::Tensor nsa_forward(torch::Tensor q, torch::Tensor k, torch::Tensor v) {
    TORCH_CHECK(q.is_cuda() && k.is_cuda() && v.is_cuda(), "cuda tensors required");
    TORCH_CHECK(q.scalar_type() == torch::kBFloat16, "bf16 required");
    TORCH_CHECK(q.dim() == 4, "q must be (B,H,S,D)");
    auto qc = q.contiguous(), kc = k.contiguous(), vc = v.contiguous();
    const int B = qc.size(0), H = qc.size(1), S = qc.size(2), D = qc.size(3);
    TORCH_CHECK(D == 64 || D == 128, "D must be 64 or 128");
    const int nb = (S + BS - 1) / BS;
    TORCH_CHECK(nb <= MAX_BLOCKS, "S must be <= 8192");
    const int BH = B * H;
    const long Q = (long)BH * S;

    auto fopt = qc.options().dtype(torch::kFloat32);
    auto iopt = qc.options().dtype(torch::kInt32);
    auto km = torch::empty({BH, nb, D}, fopt);
    auto out = torch::empty_like(qc);
    auto ulist = torch::empty({Q * MAX_UNION}, iopt);
    auto ucnt = torch::empty({Q}, iopt);
    auto bcount = torch::zeros({BH * nb}, iopt);
    auto entries = torch::empty({Q * MAX_UNION}, iopt);
    auto qpos = torch::empty({Q * MAX_UNION}, iopt);
    auto ml = torch::empty({Q * MAX_UNION, 2}, fopt);
    auto oacc = torch::empty({Q * MAX_UNION, D}, qc.options());
    auto stream = at::cuda::getCurrentCUDAStream();

    const bf16* qp = reinterpret_cast<const bf16*>(qc.data_ptr());
    const bf16* kp = reinterpret_cast<const bf16*>(kc.data_ptr());
    const bf16* vp = reinterpret_cast<const bf16*>(vc.data_ptr());

    kmean_kernel<<<dim3(nb, BH), D, 0, stream>>>(kp, km.data_ptr<float>(), S, nb, D);

    // Sub-diagonal importances as one fp32 batched GEMM: (BH,S,D)@(BH,D,nb).
    // fp32 (not TF32) so selection ordering keeps full dot precision.
    auto imp = at::bmm(qc.view({BH, S, D}).to(torch::kFloat), km.transpose(1, 2));

    dim3 sgrid((S + SEL_WARPS - 1) / SEL_WARPS, BH);
    if (D == 64) {
        select_kernel<64><<<sgrid, 32 * SEL_WARPS, 0, stream>>>(
            qp, kp, imp.data_ptr<float>(), ulist.data_ptr<int>(),
            ucnt.data_ptr<int>(), bcount.data_ptr<int>(), S, nb);
    } else {
        select_kernel<128><<<sgrid, 32 * SEL_WARPS, 0, stream>>>(
            qp, kp, imp.data_ptr<float>(), ulist.data_ptr<int>(),
            ucnt.data_ptr<int>(), bcount.data_ptr<int>(), S, nb);
    }

    auto offsets = torch::zeros({BH * nb + 1}, iopt);
    offsets.narrow(0, 1, BH * nb).copy_(torch::cumsum(bcount, 0));
    auto cursor = offsets.narrow(0, 0, BH * nb).clone();

    const int sthreads = 256;
    scatter_kernel<<<(unsigned)((Q + sthreads - 1) / sthreads), sthreads, 0, stream>>>(
        ulist.data_ptr<int>(), ucnt.data_ptr<int>(), cursor.data_ptr<int>(),
        entries.data_ptr<int>(), qpos.data_ptr<int>(), S, nb, Q);

    const unsigned cgrid = (unsigned)((Q + 7) / 8);
    if (D == 64) {
        block_attn_kernel<64><<<dim3(BH * nb, 8), 128, 0, stream>>>(
            qp, kp, vp, offsets.data_ptr<int>(), entries.data_ptr<int>(),
            reinterpret_cast<float2*>(ml.data_ptr<float>()),
            reinterpret_cast<bf16*>(oacc.data_ptr()), S, nb);
        combine_kernel<64><<<cgrid, 256, 0, stream>>>(
            ucnt.data_ptr<int>(), qpos.data_ptr<int>(),
            reinterpret_cast<const float2*>(ml.data_ptr<float>()),
            reinterpret_cast<bf16*>(oacc.data_ptr()), reinterpret_cast<bf16*>(out.data_ptr()), Q);
    } else {
        block_attn_kernel<128><<<dim3(BH * nb, 8), 128, 0, stream>>>(
            qp, kp, vp, offsets.data_ptr<int>(), entries.data_ptr<int>(),
            reinterpret_cast<float2*>(ml.data_ptr<float>()),
            reinterpret_cast<bf16*>(oacc.data_ptr()), S, nb);
        combine_kernel<128><<<cgrid, 256, 0, stream>>>(
            ucnt.data_ptr<int>(), qpos.data_ptr<int>(),
            reinterpret_cast<const float2*>(ml.data_ptr<float>()),
            reinterpret_cast<bf16*>(oacc.data_ptr()), reinterpret_cast<bf16*>(out.data_ptr()), Q);
    }
    return out;
}
"""

_CPP_SRC = "torch::Tensor nsa_forward(torch::Tensor q, torch::Tensor k, torch::Tensor v);"

_ext = load_inline(
    name="nsa_cuda_sm120_v9b",
    cpp_sources=_CPP_SRC,
    cuda_sources=_CUDA_SRC,
    functions=["nsa_forward"],
    extra_cuda_cflags=["-O3", "--use_fast_math"],
    verbose=False,
)


class Model(nn.Module):
    def __init__(self, B: int, H: int, S: int, D: int):
        super().__init__()
        self.B, self.H, self.S, self.D = B, H, S, D
        self.register_buffer("_dummy", torch.zeros(1, dtype=torch.bfloat16))

    def forward(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
        return _ext.nsa_forward(q, k, v)

20260719_083030_or-fable_anthropic_claude-fable-5_02_deepseek_nsa