KernelBench hard · RTX PRO 6000
TopK Bitonic Claude Opus 4.8
3.35%geomean peak fraction across shapes
manually audited: clean
Honest hand-written CUDA hybrid via load_inline, selected by k: warp/block argmax for k=1, register top-k + pairwise tree-merge for small k, packed-uint64 bitonic sort for large k, plus a (disabled) cooperative single-launch path. No caching, no data_ptr identity tricks, no graph — fresh outputs computed every call into preallocated scratch. The 0.0335 sits in the known launch-overhead ceiling band for this 0.5-2MB-input problem (a metric artifact, not weakness).
harnessclaudeagent session2h 13mtotal wall2h 17mcheck26sbenchmark2soutput tokens211,802cost$20.45gpu-lock wait4mgpu-lock held23sregimememory
Per-shape vs governing ceilingeach shape graded against whichever binds — fp32 compute or HBM bandwidth
1×131072×640.033 ms0.9%0.02 TB/s · 1% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)
64×8192×80.024 ms4.9%0.09 TB/s · 5% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)
32×16384×320.032 ms3.7%0.07 TB/s · 4% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)
16×12000×160.023 ms1.9%0.03 TB/s · 2% of 1.8 TB/s HBM · also 0 TFLOPS (0% of compute)
128×4096×10.008 ms13.8%0.25 TB/s · 14% 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(0.9% · 4.9% · 3.7% · 1.9% · 13.8%) = 3.3%
Kernel source (redacted)
"""Custom top-k kernel for RTX PRO 6000 (SM120 Blackwell).
Tiny inputs (0.5-2MB) => latency bound, ~8us read floor. Hybrid by k:
k==1 : block argmax reduction.
k<=16: per-thread register top-k (threshold-gated) + pairwise tree-merge.
k>=32: load chunk to shared, bitonic sort descending, keep top-k
(register arrays of size k spill to local mem for large k).
Rows split across blocks (phase1); phase2 merges per-block partials.
"""
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
_CUDA = r'''
#include <torch/extension.h>
#include <cuda_runtime.h>
#include <cooperative_groups.h>
#include <math_constants.h>
#include <c10/cuda/CUDAStream.h>
#include <ATen/cuda/CUDAContext.h>
#include <vector>
// ===================== register top-k (small k) =====================
template<int K>
__device__ __forceinline__ void insert(float* rv, int* ri, float v, int idx) {
if (v <= rv[K-1]) return;
#pragma unroll
for (int i = K-1; i > 0; --i) {
if (rv[i-1] < v) { rv[i] = rv[i-1]; ri[i] = ri[i-1]; }
else { rv[i] = v; ri[i] = idx; return; }
}
rv[0] = v; ri[0] = idx;
}
template<int K>
__global__ void regmerge(const float* __restrict__ src, const int* __restrict__ srcidx,
float* __restrict__ pv, int* __restrict__ pi,
float* __restrict__ outv, long* __restrict__ outi,
int nrow, int bpr, int final_direct) {
extern __shared__ char smem[];
float* sv = (float*)smem;
int* si = (int*)(sv + blockDim.x * K);
const int tid = threadIdx.x;
const int row = blockIdx.y;
const int b = blockIdx.x;
const int BD = blockDim.x;
int chunk = (nrow + bpr - 1) / bpr;
long start = (long)b * chunk;
long end = start + chunk; if (end > nrow) end = nrow;
float rv[K]; int ri[K];
#pragma unroll
for (int i = 0; i < K; ++i) { rv[i] = -CUDART_INF_F; ri[i] = 0; }
const float* rx = src + (long)row * nrow;
if (srcidx == nullptr) {
for (long i = start + tid; i < end; i += BD) insert<K>(rv, ri, rx[i], (int)i);
} else {
const int* rxi = srcidx + (long)row * nrow;
for (long i = start + tid; i < end; i += BD) insert<K>(rv, ri, rx[i], rxi[i]);
}
#pragma unroll
for (int i = 0; i < K; ++i) { sv[tid*K + i] = rv[i]; si[tid*K + i] = ri[i]; }
__syncthreads();
for (int stride = BD >> 1; stride > 0; stride >>= 1) {
if (tid < stride) {
int a = tid * K, bb = (tid + stride) * K;
float tv[K]; int ti[K];
int ia = 0, ib = 0;
#pragma unroll
for (int o = 0; o < K; ++o) {
float av = sv[a+ia], bv = sv[bb+ib];
if (av >= bv) { tv[o] = av; ti[o] = si[a+ia]; ia++; }
else { tv[o] = bv; ti[o] = si[bb+ib]; ib++; }
}
#pragma unroll
for (int o = 0; o < K; ++o) { sv[a+o] = tv[o]; si[a+o] = ti[o]; }
}
__syncthreads();
}
if (final_direct) {
for (int i = tid; i < K; i += BD) { outv[(long)row*K + i] = sv[i]; outi[(long)row*K + i] = (long)si[i]; }
} else {
for (int i = tid; i < K; i += BD) { long o = ((long)row*bpr + b)*K + i; pv[o] = sv[i]; pi[o] = si[i]; }
}
}
// ===== register top-k + scalar double-buffer tree-merge (large k, no spill) =====
template<int K>
__global__ void regmerge_db(const float* __restrict__ src, const int* __restrict__ srcidx,
float* __restrict__ pv, int* __restrict__ pi,
float* __restrict__ outv, long* __restrict__ outi,
int nrow, int bpr, int final_direct) {
extern __shared__ char smem[];
const int BD = blockDim.x;
float* av = (float*)smem;
int* ai = (int*)(av + BD*K);
float* bv = (float*)(ai + BD*K);
int* bi = (int*)(bv + BD*K);
const int tid = threadIdx.x;
const int row = blockIdx.y, b = blockIdx.x;
int chunk = (nrow + bpr - 1) / bpr;
long start = (long)b*chunk, end = start+chunk; if (end>nrow) end=nrow;
float rv[K]; int ri[K];
#pragma unroll
for (int i=0;i<K;++i){ rv[i]=-CUDART_INF_F; ri[i]=0; }
const float* rx = src + (long)row*nrow;
if (srcidx==nullptr) { for(long i=start+tid;i<end;i+=BD) insert<K>(rv,ri,rx[i],(int)i); }
else { const int* rxi=srcidx+(long)row*nrow; for(long i=start+tid;i<end;i+=BD) insert<K>(rv,ri,rx[i],rxi[i]); }
#pragma unroll
for (int i=0;i<K;++i){ av[tid*K+i]=rv[i]; ai[tid*K+i]=ri[i]; }
__syncthreads();
float* sv=av; int* si=ai; float* dv=bv; int* di=bi;
for (int nL=BD; nL>1; nL>>=1) {
int half=nL>>1;
if (tid<half) {
int a=2*tid*K, bb=(2*tid+1)*K, d=tid*K, ia=0, ib=0;
#pragma unroll
for (int o=0;o<K;++o){
float x=sv[a+ia], y=sv[bb+ib];
if (x>=y){ dv[d+o]=x; di[d+o]=si[a+ia]; ia++; }
else { dv[d+o]=y; di[d+o]=si[bb+ib]; ib++; }
}
}
__syncthreads();
float* t1=sv; sv=dv; dv=t1; int* t2=si; si=di; di=t2;
}
if (final_direct) { for(int i=tid;i<K;i+=BD){ outv[(long)row*K+i]=sv[i]; outi[(long)row*K+i]=(long)si[i]; } }
else { for(int i=tid;i<K;i+=BD){ long o=((long)row*bpr+b)*K+i; pv[o]=sv[i]; pi[o]=si[i]; } }
}
// ===================== bitonic (large k), packed uint64 keys =====================
// Map float to order-preserving uint32, then pack key = (ord<<32)|idx so a single
// uint64 descending sort orders by value (ties by idx, arbitrary -> fine).
__device__ __forceinline__ unsigned f2ord(float f) {
unsigned b = __float_as_uint(f);
return (b & 0x80000000u) ? ~b : (b | 0x80000000u);
}
__device__ __forceinline__ float ord2f(unsigned o) {
unsigned b = (o & 0x80000000u) ? (o & 0x7fffffffu) : ~o;
return __uint_as_float(b);
}
__device__ __forceinline__ unsigned long long pack(float v, int idx) {
return ((unsigned long long)f2ord(v) << 32) | (unsigned)idx;
}
#define NEG_KEY ((unsigned long long)0) // f2ord(-inf)=0 packs to smallest
__device__ __forceinline__ void bitonic_desc(unsigned long long* s, int N) {
for (int k = 2; k <= N; k <<= 1) {
for (int j = k >> 1; j > 0; j >>= 1) {
for (int i = threadIdx.x; i < N; i += blockDim.x) {
int ixj = i ^ j;
if (ixj > i) {
bool up = ((i & k) == 0);
unsigned long long a = s[i], b = s[ixj];
bool sw = up ? (a < b) : (a > b);
if (sw) { s[i]=b; s[ixj]=a; }
}
}
__syncthreads();
}
}
}
__global__ void bitonic_kernel(const float* __restrict__ src, const int* __restrict__ srcidx,
float* __restrict__ pv, int* __restrict__ pi,
float* __restrict__ outv, long* __restrict__ outi,
int nrow, int k, int CHUNK, int bpr, int final_direct) {
extern __shared__ char smem[];
unsigned long long* s = (unsigned long long*)smem;
const int row = blockIdx.y, b = blockIdx.x;
long start = (long)b * CHUNK;
const float* rx = src + (long)row * nrow;
if (srcidx == nullptr) {
for (int i = threadIdx.x; i < CHUNK; i += blockDim.x) {
long gi = start + i;
s[i] = (gi < nrow) ? pack(rx[gi], (int)gi) : NEG_KEY;
}
} else {
const int* rxi = srcidx + (long)row * nrow;
for (int i = threadIdx.x; i < CHUNK; i += blockDim.x) {
long gi = start + i;
s[i] = (gi < nrow) ? pack(rx[gi], rxi[gi]) : NEG_KEY;
}
}
__syncthreads();
bitonic_desc(s, CHUNK);
if (final_direct) {
for (int i = threadIdx.x; i < k; i += blockDim.x) { outv[(long)row*k+i]=ord2f((unsigned)(s[i]>>32)); outi[(long)row*k+i]=(long)(unsigned)s[i]; }
} else {
for (int i = threadIdx.x; i < k; i += blockDim.x) { long o=((long)row*bpr+b)*k+i; pv[o]=ord2f((unsigned)(s[i]>>32)); pi[o]=(int)(unsigned)s[i]; }
}
}
// ===================== cooperative single-launch (single row, large k) =====
namespace cg = cooperative_groups;
__device__ __forceinline__ int dpow2(int v){ int p=1; while(p<v) p<<=1; return p; }
// One launch: phase A (each block sorts its chunk -> top k) then grid-sync'd
// reduce passes, all in-kernel. SHP = shared capacity (ull). Row = blockIdx.y.
__global__ void coop_topk(const float* __restrict__ x, int n, int k, int RC,
unsigned long long* __restrict__ bufA,
unsigned long long* __restrict__ bufB,
float* __restrict__ outv, long* __restrict__ outi) {
cg::grid_group grid = cg::this_grid();
extern __shared__ unsigned long long sm[];
const int G = gridDim.x;
const int row = blockIdx.y;
const int t = threadIdx.x, BD = blockDim.x;
unsigned long long* A = bufA + (long)row * G * k;
unsigned long long* B = bufB + (long)row * G * k;
const float* rx = x + (long)row * n;
// phase A
int chunk = (n + G - 1) / G;
int CP = dpow2(chunk);
long start = (long)blockIdx.x * chunk;
for (int i = t; i < CP; i += BD) {
long gi = start + i;
sm[i] = (i < chunk && gi < n) ? pack(rx[gi], (int)gi) : 0ULL;
}
__syncthreads();
bitonic_desc(sm, CP);
for (int i = t; i < k; i += BD) A[(long)blockIdx.x * k + i] = sm[i];
grid.sync();
// reduce passes
int m = G * k;
unsigned long long* cur = A; unsigned long long* alt = B;
while (m > k) {
int groups = (m + RC - 1) / RC;
int cchunk = (m + groups - 1) / groups;
int CP2 = dpow2(cchunk);
if (blockIdx.x < groups) {
long st = (long)blockIdx.x * cchunk;
for (int i = t; i < CP2; i += BD) {
long gi = st + i;
sm[i] = (i < cchunk && gi < m) ? cur[gi] : 0ULL;
}
__syncthreads();
bitonic_desc(sm, CP2);
for (int i = t; i < k; i += BD) alt[(long)blockIdx.x * k + i] = sm[i];
}
grid.sync();
m = groups * k;
unsigned long long* tmp = cur; cur = alt; alt = tmp;
}
if (blockIdx.x == 0) {
for (int i = t; i < k; i += BD) {
outv[(long)row*k + i] = ord2f((unsigned)(cur[i] >> 32));
outi[(long)row*k + i] = (long)(unsigned)cur[i];
}
}
}
// ===================== argmax (k=1) =====================
__global__ void argmax1(const float* __restrict__ x, float* __restrict__ pv,
int* __restrict__ pi, int n, int chunk, int bpr) {
__shared__ float sv[1024]; __shared__ int si[1024];
const int row = blockIdx.y, b = blockIdx.x, t = threadIdx.x;
long start = (long)b*chunk, end = start+chunk; if (end>n) end=n;
const float* rx = x + (long)row*n;
float best=-CUDART_INF_F; int bidx=0;
for (long i=start+t; i<end; i+=blockDim.x){ float v=rx[i]; if(v>best){best=v;bidx=(int)i;} }
sv[t]=best; si[t]=bidx; __syncthreads();
for(int s=blockDim.x>>1;s>0;s>>=1){ if(t<s && sv[t+s]>sv[t]){sv[t]=sv[t+s];si[t]=si[t+s];} __syncthreads(); }
if(t==0){ long o=(long)row*bpr+b; pv[o]=sv[0]; pi[o]=si[0]; }
}
// one block per row, full reduction, write int64 directly
__global__ void argmax_single(const float* __restrict__ x, float* __restrict__ outv,
long* __restrict__ outi, int n) {
__shared__ float sv[1024]; __shared__ int si[1024];
const int row = blockIdx.x, t = threadIdx.x;
const float* rx = x + (long)row*n;
float best=-CUDART_INF_F; int bidx=0;
for (long i=t; i<n; i+=blockDim.x){ float v=rx[i]; if(v>best){best=v;bidx=(int)i;} }
sv[t]=best; si[t]=bidx; __syncthreads();
for(int s=blockDim.x>>1;s>0;s>>=1){ if(t<s && sv[t+s]>sv[t]){sv[t]=sv[t+s];si[t]=si[t+s];} __syncthreads(); }
if(t==0){ outv[row]=sv[0]; outi[row]=(long)si[0]; }
}
__global__ void argmax2(const float* __restrict__ pv, const int* __restrict__ pi,
float* __restrict__ outv, long* __restrict__ outi, int bpr) {
__shared__ float sv[1024]; __shared__ int si[1024];
const int row=blockIdx.x, t=threadIdx.x;
const float* bv=pv+(long)row*bpr; const int* bi=pi+(long)row*bpr;
float best=-CUDART_INF_F; int bidx=0;
for(int i=t;i<bpr;i+=blockDim.x){ if(bv[i]>best){best=bv[i];bidx=bi[i];} }
sv[t]=best; si[t]=bidx; __syncthreads();
for(int s=blockDim.x>>1;s>0;s>>=1){ if(t<s && sv[t+s]>sv[t]){sv[t]=sv[t+s];si[t]=si[t+s];} __syncthreads(); }
if(t==0){ outv[row]=sv[0]; outi[row]=(long)si[0]; }
}
static bool attr_set = false;
static int g_numSM = -1;
// Cooperative single-launch top-k for a single row (batch==1), large k.
// Returns 0 on success, nonzero (cuda error) so caller can fall back.
int topk_coop(torch::Tensor x, int k, int RC, torch::Tensor outv, torch::Tensor outi,
torch::Tensor bufA, torch::Tensor bufB) {
int batch = x.size(0);
int n = x.size(1);
auto stream = at::cuda::getCurrentCUDAStream();
if (g_numSM < 0) {
cudaDeviceGetAttribute(&g_numSM, cudaDevAttrMultiProcessorCount, 0);
}
const int BD = 256;
auto np2 = [](int v){ int p=1; while(p<v) p<<=1; return p; };
int target = (n + 255) / 256;
int SHP = RC > 512 ? RC : 512;
int maxbpsm = 1;
cudaOccupancyMaxActiveBlocksPerMultiprocessor(&maxbpsm, coop_topk, BD, (size_t)SHP*8);
int maxG = maxbpsm * g_numSM / batch;
int G = target < maxG ? target : maxG;
if (G < 1) G = 1;
int chunkA = (n + G - 1) / G;
int CP = np2(chunkA);
SHP = CP > RC ? CP : RC;
cudaFuncSetAttribute(coop_topk, cudaFuncAttributeMaxDynamicSharedMemorySize, (size_t)SHP*8);
cudaOccupancyMaxActiveBlocksPerMultiprocessor(&maxbpsm, coop_topk, BD, (size_t)SHP*8);
maxG = maxbpsm * g_numSM / batch;
if (G > maxG) { G = maxG; if (G < 1) G = 1; chunkA = (n + G - 1) / G; CP = np2(chunkA); SHP = CP > RC ? CP : RC; cudaFuncSetAttribute(coop_topk, cudaFuncAttributeMaxDynamicSharedMemorySize, (size_t)SHP*8); }
const float* X = x.data_ptr<float>();
float* OV = outv.data_ptr<float>(); long* OI = outi.data_ptr<long>();
unsigned long long* A = (unsigned long long*)bufA.data_ptr<long>();
unsigned long long* B = (unsigned long long*)bufB.data_ptr<long>();
void* kargs[] = { (void*)&X, (void*)&n, (void*)&k, (void*)&RC, (void*)&A, (void*)&B, (void*)&OV, (void*)&OI };
dim3 grid(G, batch);
dim3 block(BD);
cudaError_t err = cudaLaunchCooperativeKernel((void*)coop_topk, grid, block, kargs, (size_t)SHP*8, stream);
return (int)err;
}
void topk_cuda(torch::Tensor x, int k, int bpr, int BD, int BD2, int CHUNK, int CHUNK2,
torch::Tensor outv, torch::Tensor outi,
torch::Tensor sAv, torch::Tensor sAi, torch::Tensor sBv, torch::Tensor sBi) {
int batch = x.size(0);
int n = x.size(1);
auto stream = at::cuda::getCurrentCUDAStream();
float* OV = outv.data_ptr<float>(); long* OI = outi.data_ptr<long>();
float* Av = sAv.data_ptr<float>(); int* Ai = sAi.data_ptr<int>();
float* Bv = sBv.data_ptr<float>(); int* Bi = sBi.data_ptr<int>();
const float* X = x.data_ptr<float>();
if (k == 1) {
if (bpr == 1) {
argmax_single<<<batch,1024,0,stream>>>(X, OV, OI, n);
return;
}
int chunk = (n + bpr - 1) / bpr;
dim3 grid(bpr, batch);
argmax1<<<grid,1024,0,stream>>>(X, Av, Ai, n, chunk, bpr);
argmax2<<<batch,1024,0,stream>>>(Av, Ai, OV, OI, bpr);
return;
}
if (k <= 8) {
auto run = [&](auto kc) {
constexpr int K = decltype(kc)::value;
size_t sh1 = (size_t)BD * K * (sizeof(float)+sizeof(int));
size_t sh2 = (size_t)BD2 * K * (sizeof(float)+sizeof(int));
if (bpr == 1) {
dim3 grid(1, batch);
regmerge<K><<<grid,BD,sh1,stream>>>(X, nullptr, nullptr,nullptr, OV, OI, n, 1, 1);
return;
}
dim3 grid(bpr, batch);
regmerge<K><<<grid,BD,sh1,stream>>>(X, nullptr, Av, Ai, nullptr,nullptr, n, bpr, 0);
int m = bpr*K;
dim3 grid2(1, batch);
regmerge<K><<<grid2,BD2,sh2,stream>>>(Av, Ai, nullptr,nullptr, OV, OI, m, 1, 1);
};
if (k==8) run(std::integral_constant<int,8>{});
else run(std::integral_constant<int,16>{});
return;
}
// large k: bitonic load-to-shared, multi-pass reduction.
cudaFuncSetAttribute(bitonic_kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, 101376);
auto np2 = [](int v){ int p=1; while(p<v) p<<=1; return p; };
if (bpr == 1) {
size_t sh = (size_t)CHUNK * 8;
dim3 grid(1, batch);
bitonic_kernel<<<grid,BD,sh,stream>>>(X, nullptr, nullptr,nullptr, OV, OI, n, k, CHUNK, 1, 1);
return;
}
{
size_t sh = (size_t)CHUNK * 8;
dim3 grid(bpr, batch);
bitonic_kernel<<<grid,BD,sh,stream>>>(X, nullptr, Av, Ai, nullptr,nullptr, n, k, CHUNK, bpr, 0);
}
int m = bpr * k;
const int RC = CHUNK2;
float *curV = Av; int *curI = Ai;
float *altV = Bv; int *altI = Bi;
while (m > RC) {
int g = (m + RC - 1) / RC;
int chunk = np2((m + g - 1) / g);
int bd = chunk < 1024 ? chunk : 1024;
size_t sh = (size_t)chunk * 8;
dim3 grid(g, batch);
bitonic_kernel<<<grid,bd,sh,stream>>>(curV, curI, altV, altI, nullptr,nullptr, m, k, chunk, g, 0);
m = g * k;
std::swap(curV, altV); std::swap(curI, altI);
}
{
int chunk = np2(m);
int bd = chunk < 1024 ? chunk : 1024;
size_t sh = (size_t)chunk * 8;
dim3 grid(1, batch);
bitonic_kernel<<<grid,bd,sh,stream>>>(curV, curI, nullptr,nullptr, OV, OI, m, k, chunk, 1, 1);
}
}
'''
_CPP = ("void topk_cuda(torch::Tensor x, int k, int bpr, int BD, int BD2, int CHUNK, int CHUNK2, "
"torch::Tensor outv, torch::Tensor outi, torch::Tensor sAv, torch::Tensor sAi, "
"torch::Tensor sBv, torch::Tensor sBi);\n"
"int topk_coop(torch::Tensor x, int k, int RC, torch::Tensor outv, torch::Tensor outi, "
"torch::Tensor bufA, torch::Tensor bufB);")
_mod = load_inline(
name="topk_hybrid",
cpp_sources=_CPP,
cuda_sources=_CUDA,
functions=["topk_cuda", "topk_coop"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
verbose=False,
)
def _nextpow2(v):
p = 1
while p < v:
p <<= 1
return p
def _floorpow2(v):
p = 1
while p * 2 <= v:
p <<= 1
return p
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.BD = self.BD2 = self.CHUNK = self.CHUNK2 = 0
self.use_coop = False
if k == 1:
self.bpr = max(1, min(round(188 / batch), (n + 1023) // 1024))
self._alloc()
return
if k <= 8:
# register top-k + tree merge; BD=128 sweet spot
BD = 128
bpr = max(1, round(n / 1536))
while bpr * k > 2048 and bpr > 1:
bpr -= 1
while bpr > 1 and (n + bpr - 1) // bpr < BD:
bpr -= 1
m = bpr * k
self.BD = BD
self.bpr = bpr
self.BD2 = _floorpow2(max(32, min(1024, (m + k - 1) // k)))
self._alloc()
return
# bitonic, multi-pass reduction. Small phase1 chunk => many
# blocks (fill SMs) + less total sort work; reduce passes shrink cands.
CHUNK1 = 256
bpr = max(1, (n + CHUNK1 - 1) // CHUNK1)
self.bpr = bpr
self.CHUNK = CHUNK1
self.BD = min(1024, CHUNK1)
self.CHUNK2 = 512 # reduce-chunk target (RC)
self.BD2 = 0
self._alloc()
# single-row large-k: cooperative single-launch kernel was slower than
# multi-pass relaunch (grid.sync barrier across many idle blocks), disabled.
self.use_coop = False
if self.use_coop:
self.RC = 512
Gmax = (n + 255) // 256
cap = Gmax * k # ull buffer per row (batch==1)
self.coopA = torch.empty(cap, dtype=torch.int64, device="cuda")
self.coopB = torch.empty(cap, dtype=torch.int64, device="cuda")
self._coop_ok = True
def _alloc(self):
# preallocate persistent scratch + output buffers (avoid per-call alloc)
dev = torch.device("cuda")
cap = max(self.batch * self.bpr * self.k, self.batch * self.k)
self.sAv = torch.empty(cap, dtype=torch.float32, device=dev)
self.sAi = torch.empty(cap, dtype=torch.int32, device=dev)
self.sBv = torch.empty(cap, dtype=torch.float32, device=dev)
self.sBi = torch.empty(cap, dtype=torch.int32, device=dev)
self.outv = torch.empty(self.batch, self.k, dtype=torch.float32, device=dev)
self.outi = torch.empty(self.batch, self.k, dtype=torch.int64, device=dev)
def forward(self, x: torch.Tensor):
if self.use_coop and self._coop_ok:
err = _mod.topk_coop(x, self.k, self.RC, self.outv, self.outi,
self.coopA, self.coopB)
if err == 0:
return self.outv, self.outi
self._coop_ok = False # fall back permanently
_mod.topk_cuda(x, self.k, self.bpr, self.BD, self.BD2, self.CHUNK, self.CHUNK2,
self.outv, self.outi, self.sAv, self.sAi, self.sBv, self.sBi)
return self.outv, self.outi
def get_inputs():
x = torch.randn(batch, n, dtype=torch.float32)
return [x]
def get_init_inputs():
return [batch, n, k]
batch = 64
n = 8192
k = 8
20260613_042313_claude_claude-opus-4-8_05_topk_bitonic