KernelBench hard · RTX PRO 6000

TopK Bitonic Kimi K3 (256k)

6.40%geomean peak fraction across shapes

manually audited: clean

Genuine exact custom CUDA top-k over live fp32 inputs. The record does not come from CUDA graphs, stream capture, replay, cached outputs, or skipped work. It comes from a single fused kernel: each block scans a 2,048-element chunk with vectorized loads, forms exact register-resident top-k runs, and uses warp and shared-memory truncated bitonic merges; after publishing the chunk run, warp 0 climbs a pairwise global count-tree whose atomic tickets let the last-arriving blocks perform merge nodes in parallel. This replaces the prior serial final merge without adding another launch. Outputs are freshly allocated for every call and decoded as descending values plus source int64 indices. No forbidden PyTorch selection op, grader/tolerance tampering, stress bypass, or cross-run artifact consumption was found.

harnesskinetic-claudeagent session6h 58mtotal wall7h 1mcheck76sbenchmark88soutput tokens620,587cost$1018.95gpu-lock wait2h 40mgpu-lock held7mregimememory

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

1×131072×640.017 ms1.8%0.03 TB/s · 2% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)
64×8192×80.010 ms11.2%0.20 TB/s · 11% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)
32×16384×320.014 ms8.3%0.15 TB/s · 8% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)
16×12000×160.012 ms3.6%0.06 TB/s · 4% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)
128×4096×10.006 ms18.5%0.33 TB/s · 19% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)

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

geomean(1.8% · 11.2% · 8.3% · 3.6% · 18.5%) = 6.4%

Kernel source (redacted)
"""Fused top-k kernel: register run-merge selection, single launch.

Design notes (RTX PRO 6000 / sm_120):
  - u64 keys pack (order-preserving float bits map << 32) | element index, so
    descending u64 order == descending value order with unique index
    tie-break; selection is exact.
  - Selection uses TRUNCATING BITONIC RUN-MERGES in registers: a sorted run
    is spread 8-registers-per-lane across a lane group; merging two sibling
    runs is rev-cross shuffles + a bitonic clean, dropping the lower half
    once past k. A per-warp merge tree (no smem, no block barriers) reduces
    32 lane runs to one warp top-k run.
  - Phase 1: per block of 256 threads, scan a 2048-element chunk with
    vectorized loads, per-thread sort-8, warp merge tree, then a 3-level
    smem block merge -> chunk top-k candidates.
  - Phase 2: the last block per row (atomic ticket) merges the per-chunk
    candidate runs with the same primitive in macro-rounds + accumulator.
  - k == 1 has a dedicated argmax reduction path.
  - Counters self-clean; workspaces persist and are never returned.
"""
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline


def _emit_merge_fns():
    L = []
    L.append("template <int G> DEVINL void warp_grow(ull* r, int lane, uint mask);\n"
             "template <int G> DEVINL void warp_trunc(ull* r, int lane, uint mask, int sp, int km);\n")
    for G in (1, 2, 4, 8):
        L.append(f"template <> DEVINL void warp_grow<{G}>(ull* r, int lane, uint mask) {{")
        L.append(f"    ull o_[8];")
        L.append(f"    #pragma unroll")
        L.append(f"    for (int s = 0; s < 8; ++s) o_[s] = __shfl_xor_sync(mask, r[7 - s], {2*G-1});")
        L.append(f"    #pragma unroll")
        L.append(f"    for (int s = 0; s < 8; ++s) {{")
        L.append(f"        r[s] = ((lane & {G}) == 0) ? (r[s] > o_[s] ? r[s] : o_[s]) : (r[s] < o_[s] ? r[s] : o_[s]);")
        L.append(f"    }}")
        LL = 8 * G
        j = 16 * G // 2
        while j >= 1:
            if j >= 8:
                p = j // 8
                L.append(f"    {{ bool hi_ = ((lane & {p}) == 0);")
                L.append(f"    #pragma unroll")
                L.append(f"    for (int s = 0; s < 8; ++s) {{")
                L.append(f"        ull o_ = __shfl_xor_sync(mask, r[s], {p});")
                L.append(f"        r[s] = hi_ ? (r[s] > o_ ? r[s] : o_) : (r[s] < o_ ? r[s] : o_);")
                L.append(f"    }} }}")
            else:
                L.append(f"    #pragma unroll")
                L.append(f"    for (int s = 0; s < 8; ++s) if (!((s & {j}) != 0)) {{")
                L.append(f"        ull a_ = r[s], b_ = r[s | {j}];")
                L.append(f"        r[s] = a_ > b_ ? a_ : b_; r[s | {j}] = a_ > b_ ? b_ : a_;")
                L.append(f"    }}")
            j >>= 1
        L.append("}")
    for G in (1, 2, 4, 8):
        L.append(f"template <> DEVINL void warp_trunc<{G}>(ull* r, int lane, uint mask, int sp, int km) {{")
        L.append(f"    ull o_[8];")
        L.append(f"    #pragma unroll")
        L.append(f"    for (int s = 0; s < 8; ++s) o_[s] = __shfl_xor_sync(mask, r[7 - s], sp);")
        L.append(f"    #pragma unroll")
        L.append(f"    for (int s = 0; s < 8; ++s) {{")
        L.append(f"        if ((lane & km) == 0) r[s] = r[s] > o_[s] ? r[s] : o_[s];")
        L.append(f"    }}")
        LL = 8 * G
        j = LL // 2
        while j >= 8:
            p = j // 8
            L.append(f"    {{ bool hi_ = ((lane & {p}) == 0);")
            L.append(f"    #pragma unroll")
            L.append(f"    for (int s = 0; s < 8; ++s) {{")
            L.append(f"        ull o_ = __shfl_xor_sync(mask, r[s], {p});")
            L.append(f"        r[s] = hi_ ? (r[s] > o_ ? r[s] : o_) : (r[s] < o_ ? r[s] : o_);")
            L.append(f"    }} }}")
            j >>= 1
        while j >= 1:
            L.append(f"    #pragma unroll")
            L.append(f"    for (int s = 0; s < 8; ++s) if (!((s & {j}) != 0)) {{")
            L.append(f"        ull a_ = r[s], b_ = r[s | {j}];")
            L.append(f"        r[s] = a_ > b_ ? a_ : b_; r[s | {j}] = a_ > b_ ? b_ : a_;")
            L.append(f"    }}")
            j >>= 1
        L.append("}")
    return "\n".join(L)


_MERGE_FNS = _emit_merge_fns()

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

using ull = unsigned long long;
using uint = unsigned int;

#define DEVINL __device__ __forceinline__

// Order-preserving map float bits -> uint (total order; NaNs above +inf,
// -0.0 below +0.0). keyf inverts it.
DEVINL uint fkey(float f) {
    uint b = __float_as_uint(f);
    return (b & 0x80000000u) ? ~b : (b | 0x80000000u);
}
DEVINL float keyf(uint u) {
    uint b = (u & 0x80000000u) ? (u & 0x7fffffffu) : ~u;
    return __uint_as_float(b);
}
DEVINL ull mkkey(float f, uint idx) { return ((ull)fkey(f) << 32) | (ull)idx; }
DEVINL ull umax64(ull a, ull b) { return a > b ? a : b; }

#define CSD(i, j) do { ull a_ = r[i], b_ = r[j]; \
    r[i] = a_ > b_ ? a_ : b_; r[j] = a_ > b_ ? b_ : a_; } while (0)

__MERGE_FNS__

// per-thread 8-element sorting network (Batcher odd-even, descending)
DEVINL void sort8(ull* r) {
    CSD(0, 1);
    CSD(2, 3);
    CSD(0, 2);
    CSD(1, 3);
    CSD(1, 2);
    CSD(4, 5);
    CSD(6, 7);
    CSD(4, 6);
    CSD(5, 7);
    CSD(5, 6);
    CSD(0, 4);
    CSD(2, 6);
    CSD(2, 4);
    CSD(1, 5);
    CSD(3, 7);
    CSD(3, 5);
    CSD(1, 2);
    CSD(3, 4);
    CSD(5, 6);
}

// Merge two sorted-desc runs of 8G u64 each at A, B; keep desc top 8G in out.
// Executed by lanes 0..2G-1 of one warp (mask covers exactly those lanes).
__device__ void smem_merge_pair(const ull* __restrict__ A, const ull* __restrict__ B,
                                ull* __restrict__ out, int G, int lane, uint mask) {
    ull r[8];
    int gl = lane % (2 * G);
    bool upper = gl >= G;
    int p = upper ? gl - G : gl;
    const ull* base = upper ? B : A;
#pragma unroll
    for (int i = 0; i < 8; ++i) r[i] = base[p * 8 + i];
    if (G == 1)      warp_trunc<1>(r, lane, mask, 1, 1);
    else if (G == 2) warp_trunc<2>(r, lane, mask, 3, 2);
    else if (G == 4) warp_trunc<4>(r, lane, mask, 7, 4);
    else             warp_trunc<8>(r, lane, mask, 15, 8);
    if (!upper) {
#pragma unroll
        for (int i = 0; i < 8; ++i) out[p * 8 + i] = r[i];
    }
}

DEVINL int np2d(int x) {
    x--;
    x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16;
    return x + 1;
}

// M1: per-thread element count (pow2). E: elems scanned per thread.
template <int M1, int E>
__global__ void topk_kernel(const float* __restrict__ x,
                            ull* __restrict__ cand, int* __restrict__ cnt, int* __restrict__ cnt2,
                            float* __restrict__ outv, long long* __restrict__ outi,
                            int n, int k, int K2, int C, int CH) {
    const int T = 256;
    const int tid = threadIdx.x;
    const int bid = blockIdx.x;
    const int row = bid / C;
    const int cid = bid - row * C;
    const float* xrow = x + (long long)row * n;
    const int cstart = cid * CH;
    const int clen = min(CH, n - cstart);
    const int warp = tid >> 5;
    const int lane = tid & 31;
    const int RS = K2 < 8 ? 8 : K2;      // run length in merge machinery
    const int G = RS >> 3;               // lane group size in merge prims

    __shared__ ull wsm[640];
    __shared__ int s_flag;

    ull r[8];
    bool vec = (clen == CH) && ((n & 3) == 0);

    // ---------------- phase 1 -------------------------------------------
    if (M1 == 1) {
        // argmax path (k == 1)
        ull best = 0ull;
        if (vec) {
            const float4* xc = reinterpret_cast<const float4*>(xrow + cstart);
#pragma unroll
            for (int j = 0; j < E / 4; ++j) {
                float4 v = xc[j * T + tid];
                int base = cstart + j * 4 * T + tid * 4;
                best = umax64(best, mkkey(v.x, base + 0));
                best = umax64(best, mkkey(v.y, base + 1));
                best = umax64(best, mkkey(v.z, base + 2));
                best = umax64(best, mkkey(v.w, base + 3));
            }
        } else {
#pragma unroll
            for (int e = 0; e < E; ++e) {
                int local = e * T + tid;
                if (local < clen) best = umax64(best, mkkey(xrow[cstart + local], cstart + local));
            }
        }
#pragma unroll
        for (int s = 16; s >= 1; s >>= 1) {
            ull o = __shfl_xor_sync(0xffffffffu, best, s);
            best = umax64(best, o);
        }
        if (lane == 0) wsm[warp] = best;
        __syncthreads();
        if (tid < 32) {
            ull b = tid < 8 ? wsm[tid] : 0ull;
#pragma unroll
            for (int s = 4; s >= 1; s >>= 1) {
                ull o = __shfl_xor_sync(0xffffffffu, b, s);
                b = umax64(b, o);
            }
            if (tid == 0) wsm[512] = b;
        }
        __syncthreads();
        if (C == 1) {
            if (tid == 0) {
                ull u = wsm[512];
                outv[(long long)row * k] = keyf((uint)(u >> 32));
                outi[(long long)row * k] = (long long)(uint)(u & 0xffffffffu);
            }
            return;
        }
        if (tid == 0) cand[(long long)bid * k] = wsm[512];
        __threadfence();
        __syncthreads();
        if (tid == 0) { int old = atomicAdd(&cnt[row], 1); s_flag = (old == C - 1) ? 1 : 0; }
        __syncthreads();
        if (s_flag == 0) return;
        if (tid == 0) cnt[row] = 0;
        __threadfence();
        const ull* candrow = cand + (long long)row * C;
        if (tid < 32) {
            ull b = 0ull;
            for (int q = tid; q < C; q += 32) b = umax64(b, candrow[q]);
#pragma unroll
            for (int s = 16; s >= 1; s >>= 1) {
                ull o = __shfl_xor_sync(0xffffffffu, b, s);
                b = umax64(b, o);
            }
            if (tid == 0) {
                outv[(long long)row * k] = keyf((uint)(b >> 32));
                outi[(long long)row * k] = (long long)(uint)(b & 0xffffffffu);
            }
        }
        return;
    }

#pragma unroll
    for (int i = 0; i < 8; ++i) r[i] = 0ull;
    if (M1 == E) {
        if (vec) {
            const float4* xc = reinterpret_cast<const float4*>(xrow + cstart);
#pragma unroll
            for (int j = 0; j < E / 4; ++j) {
                float4 v = xc[j * T + tid];
                int base = cstart + j * 4 * T + tid * 4;
                r[4 * j + 0] = mkkey(v.x, base + 0);
                r[4 * j + 1] = mkkey(v.y, base + 1);
                r[4 * j + 2] = mkkey(v.z, base + 2);
                r[4 * j + 3] = mkkey(v.w, base + 3);
            }
        } else {
#pragma unroll
            for (int e = 0; e < E; ++e) {
                int local = e * T + tid;
                r[e] = (local < clen) ? mkkey(xrow[cstart + local], cstart + local) : 0ull;
            }
        }
    } else {
        // threshold filter keeps per-thread top-M1 in r[0..M1), rest zeros
        ull rmin = 0ull;
#pragma unroll
        for (int e = 0; e < E; ++e) {
            int local = e * T + tid;
            if (local < clen) {
                ull key = mkkey(xrow[cstart + local], cstart + local);
                if (key > rmin) {
                    int mp = 0;
#pragma unroll
                    for (int i = 1; i < M1; ++i) if (r[i] < r[mp]) mp = i;
                    r[mp] = key;
                    ull m = r[0];
#pragma unroll
                    for (int i = 1; i < M1; ++i) m = m < r[i] ? m : r[i];
                    rmin = m;
                }
            }
        }
    }
    sort8(r);

    // register merge tree: 32 lane-runs -> 1 warp run of RS (zeros padded)
    if (K2 <= 8) {
        warp_trunc<1>(r, lane, 0xffffffffu, 1, 1);
        warp_trunc<1>(r, lane, 0xffffffffu, 2, 2);
        warp_trunc<1>(r, lane, 0xffffffffu, 4, 4);
        warp_trunc<1>(r, lane, 0xffffffffu, 8, 8);
        warp_trunc<1>(r, lane, 0xffffffffu, 16, 16);
    } else if (K2 == 16) {
        warp_grow<1>(r, lane, 0xffffffffu);
        warp_trunc<2>(r, lane, 0xffffffffu, 3, 2);
        warp_trunc<2>(r, lane, 0xffffffffu, 5, 4);
        warp_trunc<2>(r, lane, 0xffffffffu, 9, 8);
        warp_trunc<2>(r, lane, 0xffffffffu, 17, 16);
    } else if (K2 == 32) {
        warp_grow<1>(r, lane, 0xffffffffu);
        warp_grow<2>(r, lane, 0xffffffffu);
        warp_trunc<4>(r, lane, 0xffffffffu, 7, 4);
        warp_trunc<4>(r, lane, 0xffffffffu, 11, 8);
        warp_trunc<4>(r, lane, 0xffffffffu, 19, 16);
    } else {  // K2 == 64
        warp_grow<1>(r, lane, 0xffffffffu);
        warp_grow<2>(r, lane, 0xffffffffu);
        warp_grow<4>(r, lane, 0xffffffffu);
        warp_trunc<8>(r, lane, 0xffffffffu, 15, 8);
        warp_trunc<8>(r, lane, 0xffffffffu, 23, 16);
    }

    // warp winners -> wsm (runs at stride RS)
#pragma unroll
    for (int i = 0; i < 8; ++i) {
        int v = lane * 8 + i;
        if (v < RS) wsm[warp * RS + v] = r[i];
    }
    __syncthreads();
    // block tree: 8 runs -> 1
    if (warp < 4) smem_merge_pair(wsm + (2 * warp) * RS, wsm + (2 * warp + 1) * RS,
                                  wsm + 256 + warp * RS, G, lane, (1u << (2 * G)) - 1);
    __syncthreads();
    if (warp < 2) smem_merge_pair(wsm + 256 + (2 * warp) * RS, wsm + 256 + (2 * warp + 1) * RS,
                                  wsm + 384 + warp * RS, G, lane, (1u << (2 * G)) - 1);
    __syncthreads();
    if (warp == 0) smem_merge_pair(wsm + 384, wsm + 384 + RS,
                                   wsm + 512, G, lane, (1u << (2 * G)) - 1);
    __syncthreads();

    if (C == 1) {
        for (int w = tid; w < k; w += T) {
            ull u = wsm[512 + w];
            outv[(long long)row * k + w] = keyf((uint)(u >> 32));
            outi[(long long)row * k + w] = (long long)(uint)(u & 0xffffffffu);
        }
        return;
    }
    {
        int SEC = C < 64 ? C : 64;
        long long coff = (long long)row * (C + SEC) * RS + (long long)cid * RS;
        for (int w = tid; w < RS; w += T) cand[coff + w] = wsm[512 + w];
    }

    __threadfence();

    // ---------------- phase 2 -------------------------------------------
    // Hierarchical count-tree cascade for ALL C > 1: phase-1 blocks climb
    // pairwise as their ticket rights allow (block-level pipelining, no
    // big single-block serial tree). Node counters self-clean.
    const int SEC = C < 64 ? C : 64;          // scratch runs per row
    const ull* candrow = cand + (long long)row * (C + SEC) * RS;
    const ull* scrrow = candrow + (long long)C * RS;
    ull* ACC = wsm + 576;
    {
        // Cascade runs on warp 0 only of every block (merge work is
        // warp-internal); other warps exit immediately after publication.
        if (warp != 0) return;
        __syncwarp();
        // level run offsets inside scrrow: base(0)=0; base(l) = sum of
        // ceil(C/2^i) for i<l. Node id for (lvl, pair) = lvl*64 + pair.
        int C_lvl = C;
        int wid = cid;
        int lvl = 0;
        int lbase = -C;                // run-offset of current level (level 0 = candrow)
        int lnext = 0;                 // run-offset of next level (in scrrow)
        bool i_am_root = false;
        while (true) {
            int pair = wid >> 1;
            int target = (2 * pair + 1 < C_lvl) ? 2 : 1;
            if (tid == 0) {
                s_flag = atomicAdd(&cnt2[row * (8 * 64) + lvl * 64 + pair], 1) + 1;
            }
            __syncwarp();
            if (s_flag < target) break;
            if (tid == 0) cnt2[row * (8 * 64) + lvl * 64 + pair] = 0;  // self-clean
            __threadfence();
            const ull* A = scrrow + ((long long)lbase + 2 * pair) * RS;
            ull* outp = const_cast<ull*>(scrrow) + ((long long)lnext + pair) * RS;
            if (target == 2) {
                smem_merge_pair(A, A + RS, outp, G, lane, (1u << (2 * G)) - 1);
            } else {
                for (int w = lane; w < RS; w += 32) outp[w] = A[w];
            }
            __syncwarp();
            wid = pair;
            int newC = (C_lvl + 1) >> 1;
            lvl++;
            lbase = lnext;
            lnext += newC;
            C_lvl = newC;
            if (C_lvl == 1) { i_am_root = true; break; }
        }
        if (i_am_root) {
            const ull* res = scrrow + (long long)lbase * RS;
            for (int w = lane; w < k; w += 32) {
                ull u = res[w];
                outv[(long long)row * k + w] = keyf((uint)(u >> 32));
                outi[(long long)row * k + w] = (long long)(uint)(u & 0xffffffffu);
            }
        }
    }
}

// ------------------------------ host side ---------------------------------
static torch::Tensor g_cand, g_cnt, g_cnt2;

template <int M1, int E>
static void launch(const float* xp, ull* candp, int* cntp, int* cnt2p, float* vp,
                   long long* ip, int B, int n, int k, int K2, int C, int CH,
                   cudaStream_t stream) {
    int RS = K2 < 8 ? 8 : K2;
    (void)RS;
    dim3 grid((unsigned)(B * (int64_t)C));
    topk_kernel<M1, E><<<grid, 256, 0, stream>>>(xp, candp, cntp, cnt2p, vp, ip,
                                                    n, k, K2, C, CH);
}

std::tuple<torch::Tensor, torch::Tensor> topk_run(const torch::Tensor& x,
                                                  int64_t k_) {
    TORCH_CHECK(x.is_cuda() && x.dim() == 2 && x.scalar_type() == at::kFloat, "bad x");
    auto xc = x.is_contiguous() ? x : x.contiguous();
    int64_t B = xc.size(0), n = xc.size(1);
    int k = (int)k_;
    TORCH_CHECK(k >= 1 && (int64_t)k <= n, "bad k");
    int K2 = 1; while (K2 < k) K2 <<= 1;
    TORCH_CHECK(K2 <= 64, "k too large for fast path");

    auto opts = xc.options();
    auto vals = at::empty({B, k}, opts);
    auto idxs = at::empty({B, k}, opts.dtype(at::kLong));

    static thread_local int64_t cb = -1, cn = -1, ck = -1;
    static thread_local int cE, cC, cM1;
    int64_t sig = (B << 32) ^ (n << 16) ^ k;
    bool hit = (sig == ((cb << 32) ^ (cn << 16) ^ ck));
    int E, CH, C, M1;
    if (hit) {
        E = cE; C = cC; M1 = cM1; CH = E * 256;
    } else {
        E = 8; CH = 2048;
        if (n <= 4096 && K2 == 1) { E = 16; CH = 4096; }
        C = (int)((n + CH - 1) / CH);
        M1 = CH / 256 < K2 ? CH / 256 : K2;  // min(E, K2)
        M1 = M1 < 2 ? M1 : (M1 > 8 ? 8 : M1);    // cap run at 8
        cb = B; cn = n; ck = k; cE = E; cC = C; cM1 = M1;
    }

    int RS_ = K2 < 8 ? 8 : K2;
    int SEC_ = C < 64 ? C : 64;
    int64_t need = (C > 1) ? (int64_t)B * (C + SEC_) * RS_ : 64;
    if (!g_cand.defined() || g_cand.numel() < need) {
        g_cand = at::empty({std::max<int64_t>(need, 1 << 20)}, opts.dtype(at::kLong));
    }
    if (!g_cnt.defined() || g_cnt.numel() < B) {
        g_cnt = at::zeros({std::max<int64_t>(B, 4096)}, opts.dtype(at::kInt));
    }
    if (!g_cnt2.defined()) {
        g_cnt2 = at::zeros({512 * 128}, opts.dtype(at::kInt));
    }

    const float* xp = xc.data_ptr<float>();
    ull* candp = reinterpret_cast<ull*>(g_cand.data_ptr<int64_t>());
    int* cntp = g_cnt.data_ptr<int>();
    int* cnt2p = g_cnt2.data_ptr<int>();
    float* vp = vals.data_ptr<float>();
    long long* ip = reinterpret_cast<long long*>(idxs.data_ptr<int64_t>());
    auto stream = at::cuda::getCurrentCUDAStream();

#define LAUNCH(M1_, E_) launch<M1_, E_>(xp, candp, cntp, cnt2p, vp, ip, (int)B, \
                                        (int)n, k, K2, C, CH, stream)
    switch (E * 100 + M1) {
        case 801:  LAUNCH(1, 8);  break;
        case 802:  LAUNCH(2, 8);  break;
        case 804:  LAUNCH(4, 8);  break;
        case 808:  LAUNCH(8, 8);  break;
        case 1601: LAUNCH(1, 16); break;
        case 1602: LAUNCH(2, 16); break;
        case 1604: LAUNCH(4, 16); break;
        default: TORCH_CHECK(false, "no kernel for config");
    }
#undef LAUNCH
    return {vals, idxs};
}
"""

CUDA_SRC = _CUDA_TEMPLATE.replace("__MERGE_FNS__", _MERGE_FNS)

CPP_SRC = "#include <torch/extension.h>\nstd::tuple<torch::Tensor, torch::Tensor> topk_run(const torch::Tensor& x, int64_t k_);"

_mod = load_inline(
    name="topk_bitonic_v5",
    cpp_sources=CPP_SRC,
    cuda_sources=CUDA_SRC,
    functions=["topk_run"],
    extra_cuda_cflags=["-O3"],
    verbose=False,
)


class Model(nn.Module):
    def __init__(self, batch: int, n: int, k: int):
        super().__init__()
        self.batch, self.n, self.k = batch, n, k
        self.register_buffer("_dummy", torch.zeros(1))
        self._fn = _mod.topk_run

    def forward(self, x: torch.Tensor):
        return self._fn(x, self.k)


batch = 64
n = 8192
k = 8


def get_inputs():
    x = torch.randn(batch, n, dtype=torch.float32)
    return [x]


def get_init_inputs():
    return [batch, n, k]

20260716_112628_kinetic-claude_kinetic-0715_05_topk_bitonic