kernelbench.com

KernelBench hard · H100

TopK Bitonic Claude Opus 5

3.43%geomean peak fraction across shapes

manually audited: clean

Real single-launch top-k: float -> order-preserving uint32 keys, register-resident interval select seeded by group-max bounds, 256-bin histogram suffix scan, threadfence+ticket cross-block phase 2, ballot rank-and-scatter sort. Identity-keyed graph replay + __class__-swap fast path -- recompute on live data; the code NaN-poisons the output after capture to prove replay does real work (self-check against a silent no-op graph, added after the agent's own autotuner briefly ranked a do-nothing config fastest -- it found and fixed a self-deception hazard rather than exploiting it). Wrote a pure-C++ clone of the harness timing protocol (launchcost.cu) proving ~15us of the topk score is Python/torch submit cost (empty-kernel probe pf 0.0328 vs real kernel 0.0309) -- confirms the deck's known launch-overhead-bound ceiling. Mid-session a concurrent self-benchmark corrupted solution.py (gpu-lock-exec same-RUN_DIR reentrancy); the agent discarded the contaminated numbers, restored the md5-verified passing deliverable, and adopted a one-GPU-job rule; it queued 35+ min behind the sibling 03 run's lock rather than killing it. Grader files Read-only, template_mutated false, no foreign-archive access. Passed check.py + stress on the isolated re-grade; clean 0.0343.

harnessor-opusagent session6h 34mtotal wall6h 36mcheck6sbenchmark3soutput tokensgpu-lock wait46mgpu-lock held1h 19mregimememory

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

1×131072×640.019 ms1.4%0.03 TB/s · 1% of 2.0 TB/s HBM · also 0 TFLOPS (0% of compute)
64×8192×80.019 ms5.5%0.11 TB/s · 6% of 2.0 TB/s HBM · also 0 TFLOPS (0% of compute)
32×16384×320.019 ms5.5%0.11 TB/s · 6% of 2.0 TB/s HBM · also 0 TFLOPS (0% of compute)
16×12000×160.018 ms2.1%0.04 TB/s · 2% of 2.0 TB/s HBM · also 0 TFLOPS (0% of compute)
128×4096×10.019 ms5.5%0.11 TB/s · 6% of 2.0 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.4% · 5.5% · 5.5% · 2.1% · 5.5%) = 3.4%

Kernel source (redacted)
"""Custom fused top-k kernel (CUDA C++ via load_inline).

Algorithm
---------
One kernel launch total.  grid = (BPR, batch); each block owns a contiguous
segment of one row.

Values are mapped to order-preserving uint32 keys
    u = (bits & 0x80000000) ? ~bits : (bits | 0x80000000)
so that unsigned integer order == float order.  A candidate is the 64-bit
pack  (u << 32) | index, which sorts by value then index in one compare.

Phase 1 (every block): the segment's keys are loaded straight into RPT
registers per thread and never leave them.  An *interval select* then narrows
[lo, hi] onto the KP-th largest key: each pass histograms the 256 bins of the
current interval, warp-suffix-scans them to find the boundary bin, and
recurses into it.  The starting interval is not the whole key range but
[T, M], where M is the block max and T is the smallest of BT/W group maxima --
with BT/W >= KP groups, T is a provable lower bound on the KP-th largest, and
seeding the select with it makes the first pass' bins ~1000x finer, so one
pass is normally enough.  Survivors are compacted with two atomic counters.

Phase 2 (last block per row, found with __threadfence() + an atomic ticket -
no grid sync, no second launch): re-reads the row's shipped candidates, runs
the *same* select over them (seeded by the max of the blocks' thresholds), and
sorts.  A multi-block row ships all CAP survivors unsorted, since phase 2 only
needs the union of the shipped sets to contain the row's top KP -- that skips
phase 1's sort and lets CAP exceed KP, which keeps the select to one pass.
When BPR == 1 phase 1's survivors are already the row's top KP and phase 2 is
skipped entirely.

Sorting CAP keys is a rank-and-scatter, not a network: the packed keys are
unique (the index is in the low bits), so counting how many are greater gives
each key its slot outright, one __ballot_sync per CAP/32 registers.

Dispatch
--------
(RPT, CAP, BT) is a template triple, so the host picks a segmentation per
shape: BPR = ceil(n / (RPT*BT)) blocks per row.  Known shapes carry a frozen
shortlist (_TABLE); anything else falls back to the full candidate list.
Either way the winner is decided by measurement at build time (_tune).

The measured quantity on this machine is dominated by CPU launch cost
(~3.3 us/launch over a ~5.4 us event-pair floor), so the host path is stripped
down: pre-allocated outputs, a cached result tuple, `__call__ = forward`, and
CUDA graph replay (guarded by an input-pointer check with a normal-launch
fallback).  All work is enqueued on the caller's current torch stream.
"""

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

# ---------------------------------------------------------------------------
# CUDA
# ---------------------------------------------------------------------------

_CUDA = r'''
#include <cuda_runtime.h>
#include <stdint.h>

__device__ __forceinline__ uint32_t fl(uint32_t b) {
  return (b & 0x80000000u) ? ~b : (b | 0x80000000u);
}
__device__ __forceinline__ float ufl(uint32_t u) {
  uint32_t b = (u & 0x80000000u) ? (u & 0x7fffffffu) : ~u;
  return __uint_as_float(b);
}

// State of a partially-narrowed select.  The threshold is known to lie in the
// key interval [lo, hi]; each pass splits that interval into 256 bins and keeps
// the one the threshold falls in, so the interval shrinks 256-fold per pass.
//   above   = keys already known to be > hi   (all certainly in the top KP)
//   need    = KP - above  slots still owed, to be taken from [lo, hi]
//   sortall = the survivors are few enough that they all fit the sort buffer
struct Sel { uint32_t lo, hi; int above, need; bool sortall; };

// Boundary bin of a completed 256-bin histogram: the highest bin whose suffix
// sum still covers `need`.  Returns that bin's count and the count above it.
template<int BT>
__device__ __forceinline__ void hscan(
    const uint32_t* __restrict__ hist, uint32_t* s_suf, uint32_t* s_wtot,
    uint32_t* s_mask, int need, uint32_t& o_b, uint32_t& o_hb, uint32_t& o_hi)
{
  const int tid = threadIdx.x, lane = tid & 31, warp = tid >> 5;
  uint32_t c = 0u;                    // the scan is 256 bins wide whatever BT
  if (BT == 256 || tid < 256) {
    c = hist[tid];
    #pragma unroll
    for (int d = 1; d < 32; d <<= 1) {
      uint32_t v = __shfl_down_sync(0xffffffffu, c, d);
      if (lane + d < 32) c += v;
    }
    if (lane == 0) s_wtot[warp] = c;
  }
  __syncthreads();

  if (BT == 256 || tid < 256) {
    uint32_t S = c;
    #pragma unroll
    for (int w = 0; w < 8; ++w) if (w > warp) S += s_wtot[w];
    s_suf[tid] = S;
    uint32_t m = __ballot_sync(0xffffffffu, S >= (uint32_t)need);
    if (lane == 0) s_mask[warp] = m;
  }
  __syncthreads();

  uint32_t b = 0;
  #pragma unroll
  for (int w = 0; w < 8; ++w) {
    uint32_t mm = s_mask[w];
    if (mm) b = (uint32_t)((w << 5) + (31 - __clz((int)mm)));
  }
  o_b = b; o_hb = hist[b]; o_hi = s_suf[b] - hist[b];
}

// Narrow [lo, hi] until at most CAP keys remain at or above the threshold (one
// bitonic sort then finishes the job), or until the interval is a single key
// value (exact ties).  Bin width is (hi-lo)/256 rounded up to a power of two,
// so a caller that starts from a tight interval normally needs ONE pass; a
// caller that starts from the whole key range degenerates to a byte-at-a-time
// radix select, which for iid data is two.
// The CALLER owns the first clear of hist: it has a barrier of its own to hide
// it under (the one that publishes lo0/hi0), so the common one-pass select needs
// no clear-and-publish at all.
#define TK_SEL_BODY(ACCUM)                                                    \
  const int tid = threadIdx.x;                                                \
  Sel z; z.lo = lo0; z.hi = hi0; z.above = 0; z.need = KP; z.sortall = false;  \
  bool zeroed = true;                                                         \
  for (;;) {                                                                  \
    const uint32_t span = z.hi - z.lo;                                        \
    const int sh = (span < 256u) ? 0 : (24 - __clz((int)span));               \
    if (!zeroed) {                                                            \
      if (BT == 256 || tid < 256) hist[tid] = 0u;                              \
      __syncthreads();                                                        \
    }                                                                         \
    zeroed = false;                                                           \
    ACCUM                                                                     \
    __syncthreads();                                                          \
    uint32_t bb, hb, hgt;                                                     \
    hscan<BT>(hist, s_suf, s_wtot, s_mask, z.need, bb, hb, hgt);              \
    z.above += (int)hgt; z.need -= (int)hgt;                                  \
    z.lo += bb << sh;                                                         \
    z.hi = z.lo + ((1u << sh) - 1u);                                          \
    if (z.above + (int)hb <= CAP) { z.sortall = true; break; }                \
    if (sh == 0) break;                                                       \
    __syncthreads();                                                          \
  }                                                                           \
  return z;

template<int RPT, int CAP, int BT>
__device__ __forceinline__ Sel sel_reg(
    const uint32_t* r, int KP, uint32_t lo0, uint32_t hi0, uint32_t* hist,
    uint32_t* s_suf, uint32_t* s_wtot, uint32_t* s_mask)
{
  TK_SEL_BODY(
    _Pragma("unroll")
    for (int j = 0; j < RPT; ++j) {
      const uint32_t u = r[j];
      if (u >= z.lo && u <= z.hi) atomicAdd(&hist[(u - z.lo) >> sh], 1u);
    })
}

template<int CAP, int BT>
__device__ __forceinline__ Sel sel_sh(
    const uint32_t* __restrict__ s_u, int nslot, int KP, uint32_t lo0,
    uint32_t hi0, uint32_t* hist, uint32_t* s_suf, uint32_t* s_wtot,
    uint32_t* s_mask)
{
  TK_SEL_BODY(
    for (int i = tid; i < nslot; i += BT) {
      const uint32_t u = s_u[i];
      if (u >= z.lo && u <= z.hi) atomicAdd(&hist[(u - z.lo) >> sh], 1u);
    })
}

// Bitonic sort of R*32 packed keys held in registers of one warp, ascending.
// Element p = r*32 + lane.
template<int R>
__device__ __forceinline__ void warp_sort_asc(unsigned long long* s) {
  const int lane = threadIdx.x & 31;
  const int N = R * 32;
  unsigned long long a[R];
  #pragma unroll
  for (int r = 0; r < R; ++r) a[r] = s[r * 32 + lane];
  #pragma unroll
  for (int size = 2; size <= N; size <<= 1) {
    #pragma unroll
    for (int stride = size >> 1; stride > 0; stride >>= 1) {
      #pragma unroll
      for (int r = 0; r < R; ++r) {
        const int p = r * 32 + lane;
        const bool up = ((p & size) == 0);
        if (stride >= 32) {
          const int rp = r ^ (stride >> 5);
          if (rp > r) {
            unsigned long long xx = a[r], yy = a[rp];
            if ((xx > yy) == up) { a[r] = yy; a[rp] = xx; }
          }
        } else {
          unsigned long long yy = __shfl_xor_sync(0xffffffffu, a[r], stride);
          const bool low = ((p & stride) == 0);
          a[r] = (up == low) ? (a[r] < yy ? a[r] : yy) : (a[r] > yy ? a[r] : yy);
        }
      }
    }
  }
  #pragma unroll
  for (int r = 0; r < R; ++r) s[r * 32 + lane] = a[r];
}

// Sort the CAP packed keys of s_buf into s_srt by rank-and-scatter.  Every key
// is unique (its element index occupies the low 32 bits), so counting how many
// keys are greater gives each one its final slot outright.  Each lane keeps
// CAP/32 of the keys in registers, and a warp ranks one key with one ballot per
// register -- so the whole permutation costs CAP/(BT/32) rounds of a ballot,
// against a bitonic network's 15-21 serial shuffle stages in a single warp.
// Reads and writes go to different buffers, so no barrier is needed inside.
template<int CAP, int BT>
__device__ __forceinline__ void rank_sort(const unsigned long long* s_buf,
                                          unsigned long long* s_srt) {
  const int lane = threadIdx.x & 31, warp = threadIdx.x >> 5;
  const int NW = BT / 32, NR = CAP / 32, NE = (CAP + NW - 1) / NW;
  unsigned long long c[NR];
  #pragma unroll
  for (int p = 0; p < NR; ++p) c[p] = s_buf[p * 32 + lane];
  #pragma unroll
  for (int q = 0; q < NE; ++q) {
    const int e = warp + q * NW;                     // warp-uniform: no ballot
    if (e < CAP) {                                   // ever splits a warp
      const unsigned long long mine = s_buf[e];
      int rank = 0;
      #pragma unroll
      for (int p = 0; p < NR; ++p)
        rank += __popc(__ballot_sync(0xffffffffu, c[p] > mine));
      if (lane == 0) s_srt[CAP - 1 - rank] = mine;
    }
  }
}

template<int RPT, int CAP, int BT>
__global__ __launch_bounds__(BT) void topk_kernel(
    const float* __restrict__ x, float* __restrict__ ov, long long* __restrict__ oi,
    unsigned long long* __restrict__ scratch, unsigned int* __restrict__ ctr,
    int n, int k, int KP, int BPR, int NC, int NSLOT, int W)
{
  extern __shared__ __align__(16) unsigned char smem[];
  unsigned long long* s_buf = (unsigned long long*)smem;   // CAP  survivors
  unsigned long long* s_srt = s_buf + CAP;                 // CAP  sorted
  uint32_t* s_u    = (uint32_t*)(s_srt + CAP);             // NSLOT (phase 2)
  uint32_t* s_ix   = s_u + NSLOT;                          // NSLOT (phase 2)
  uint32_t* hist   = s_ix + NSLOT;                         // 256
  uint32_t* s_suf  = hist + 256;                           // 256
  uint32_t* s_wtot = s_suf + 256;                          // 8
  uint32_t* s_mask = s_wtot + 8;                           // 8
  uint32_t* s_misc = s_mask + 8;                           // 8

  const int tid = threadIdx.x;
  const int row = blockIdx.y, bx = blockIdx.x;
  // Phase 2 only needs the UNION of the shipped sets to contain the row's top
  // KP, so a block may ship any superset of its own top KP in any order: all
  // CAP survivors, unsorted.  That buys two things -- phase 1 never sorts, and
  // CAP can exceed KP, which is what lets the select stop after one pass (with
  // CAP == KP its stop test "above + hb <= CAP" can only fire on the knife edge
  // above + hb == KP, so a second pass was the common case).
  const int SEG = RPT * BT;
  const int base = bx * SEG;
  const int seg  = (bx == BPR - 1) ? (n - base) : SEG;
  const float* __restrict__ xp = x + (long long)row * (long long)n + base;

  // ---------------- phase 1: segment -> KP candidates ----------------
  // Keys live in registers for the whole select; the tail block pads with 0,
  // which can never be selected because every real key is >= 1.
  // Everything shared that the select and the compaction need cleared is
  // cleared before the loads are even issued, so the barrier that publishes the
  // bounds publishes all of it: no pass of the select and no compaction pays
  // for a clear (or a barrier) of its own.  s_misc[5..6] are the bound slots.
  if (tid < 256) hist[tid] = 0u;
  for (int i = tid; i < CAP; i += BT) s_buf[i] = 0ull;
  if (tid < 8) s_misc[tid] = (tid == 5) ? 0xFFFFFFFFu : 0u;

  uint32_t r[RPT];
  if (seg == SEG) {
    #pragma unroll
    for (int j = 0; j < RPT; ++j) r[j] = fl(__float_as_uint(xp[tid + j * BT]));
  } else {
    #pragma unroll
    for (int j = 0; j < RPT; ++j) {
      const int i = tid + j * BT;
      r[j] = (i < seg) ? fl(__float_as_uint(xp[i])) : 0u;
    }
  }

  // ---- starting interval for the select ----
  // Split the block's threads into BT/W groups of W and let T be the smallest
  // of the group maxima.  Every group max is a distinct key >= T and there are
  // BT/W >= KP of them, so the KP-th largest key of the segment is >= T; M is
  // the block max.  Handing the select the interval [T, M] instead of the whole
  // key range makes its bins ~1000x finer, which is what turns two passes into
  // one.  The per-key work is a register max that hides under the loads.
  uint32_t T = 0u, M = 0xFFFFFFFFu;
  if (W) {
    uint32_t m = r[0];
    #pragma unroll
    for (int j = 1; j < RPT; ++j) m = m > r[j] ? m : r[j];
    for (int d = 1; d < W; d <<= 1) {
      const uint32_t o = __shfl_xor_sync(0xffffffffu, m, d);
      m = m > o ? m : o;
    }
    __syncthreads();
    if ((tid & (W - 1)) == 0) {
      atomicMin(&s_misc[5], m);
      atomicMax(&s_misc[6], m);
    }
    __syncthreads();
    T = s_misc[5] > 1u ? s_misc[5] : 1u;   // 1: the tail block's 0 padding
    M = s_misc[6] > T ? s_misc[6] : T;     // a group of pure padding gives T=1
  } else {
    __syncthreads();                       // no bounds, but still publish the clears
  }

  Sel z = sel_reg<RPT, CAP, BT>(r, KP, T, M, hist, s_suf, s_wtot, s_mask);

  if (z.sortall) {
    #pragma unroll
    for (int j = 0; j < RPT; ++j) {
      const uint32_t u = r[j];
      if (u >= z.lo) {
        const uint32_t p = atomicAdd(&s_misc[0], 1u);
        const int i = tid + j * BT;
        if (p < (uint32_t)CAP)
          s_buf[p] = ((unsigned long long)u << 32) | (unsigned)(base + (i < seg ? i : 0));
      }
    }
  } else {
    #pragma unroll
    for (int j = 0; j < RPT; ++j) {
      const uint32_t u = r[j];
      const int i = tid + j * BT;
      const unsigned long long key =
          ((unsigned long long)u << 32) | (unsigned)(base + (i < seg ? i : 0));
      if (u > z.lo) {
        const uint32_t p = atomicAdd(&s_misc[0], 1u);
        if (p < (uint32_t)KP) s_buf[p] = key;
      } else if (u == z.lo) {
        const uint32_t p = atomicAdd(&s_misc[1], 1u);
        if (p < (uint32_t)z.need) s_buf[z.above + p] = key;
      }
    }
  }
  __syncthreads();
  if (BPR == 1) { rank_sort<CAP, BT>(s_buf, s_srt); __syncthreads(); }

  // ---------------- cross-block handshake ----------------
  if (BPR > 1) {
    unsigned long long* dst = scratch + (long long)row * NC + (long long)bx * CAP;
    for (int i = tid; i < CAP; i += BT) dst[i] = s_buf[i];
    // z.lo has at least KP of this block's keys at or above it, so the largest
    // z.lo over the blocks is a lower bound on the KP-th largest of the row --
    // the same quality of bound as the sorted candidates would give, but it
    // costs one atomic instead of ordering the candidates first.
    if (tid == 0) {
      atomicMax(&ctr[row * 4 + 1], z.lo);
      atomicMax(&ctr[row * 4 + 2], M);
    }
    __threadfence();
    __syncthreads();
    if (tid == 0) {
      volatile unsigned int* vctr = (volatile unsigned int*)ctr;
      unsigned int old = atomicAdd(&ctr[row * 4], 1u);
      unsigned int last = (old == (unsigned)(BPR - 1)) ? 1u : 0u;
      if (last) {                       // race-free: all BPR blocks have ticked
        vctr[row * 4] = 0u;
        s_misc[3] = vctr[row * 4 + 1];
        s_misc[4] = vctr[row * 4 + 2];
        vctr[row * 4 + 1] = 0u;
        vctr[row * 4 + 2] = 0u;
      }
      s_misc[2] = last;
    }
    __syncthreads();
    if (s_misc[2] == 0u) return;

    // ---------------- phase 2: BPR*KP candidates -> top KP ----------------
    const volatile unsigned long long* src =
        (const volatile unsigned long long*)(scratch + (long long)row * NC);
    const uint32_t T2 = s_misc[3] > 1u ? s_misc[3] : 1u;
    const uint32_t M2 = s_misc[4] > T2 ? s_misc[4] : T2;
    for (int i = tid; i < NC; i += BT) {
      unsigned long long key = src[i];
      s_u[i]  = (uint32_t)(key >> 32);
      s_ix[i] = (uint32_t)key;
    }
    if (tid < 256) hist[tid] = 0u;                 // ditto: this phase's clears
    for (int i = tid; i < CAP; i += BT) s_buf[i] = 0ull;
    if (tid < 2) s_misc[tid] = 0u;
    __syncthreads();

    z = sel_sh<CAP, BT>(s_u, NC, KP, T2, M2, hist, s_suf, s_wtot, s_mask);

    if (z.sortall) {
      for (int i = tid; i < NC; i += BT) {
        const uint32_t u = s_u[i];
        if (u >= z.lo) {
          const uint32_t p = atomicAdd(&s_misc[0], 1u);
          if (p < (uint32_t)CAP) s_buf[p] = ((unsigned long long)u << 32) | s_ix[i];
        }
      }
    } else {
      for (int i = tid; i < NC; i += BT) {
        const uint32_t u = s_u[i];
        const unsigned long long key = ((unsigned long long)u << 32) | s_ix[i];
        if (u > z.lo) {
          const uint32_t p = atomicAdd(&s_misc[0], 1u);
          if (p < (uint32_t)KP) s_buf[p] = key;
        } else if (u == z.lo) {
          const uint32_t p = atomicAdd(&s_misc[1], 1u);
          if (p < (uint32_t)z.need) s_buf[z.above + p] = key;
        }
      }
    }
    __syncthreads();
    rank_sort<CAP, BT>(s_buf, s_srt);
    __syncthreads();
  }

  // ---------------- emit top k (descending) ----------------
  for (int j = tid; j < k; j += BT) {
    unsigned long long key = s_srt[CAP - 1 - j];
    ov[(long long)row * k + j] = ufl((uint32_t)(key >> 32));
    oi[(long long)row * k + j] = (long long)(uint32_t)key;
  }
}

// ---------------------------------------------------------------------------

struct TKCfg { int n, k, KP, RPT, CAP, BT, BPR, NC, NSLOT, W, batch;
               size_t shmem; };

template<int RPT, int CAP, int BT>
static void tk_go(bool attr_only, const void* x, void* v, void* i, void* scratch,
                  void* ctr, const TKCfg& c, cudaStream_t st) {
  if (attr_only) {
    if (c.shmem > 48 * 1024)
      cudaFuncSetAttribute(topk_kernel<RPT, CAP, BT>,
                           cudaFuncAttributeMaxDynamicSharedMemorySize, (int)c.shmem);
    return;
  }
  topk_kernel<RPT, CAP, BT><<<dim3(c.BPR, c.batch), BT, c.shmem, st>>>(
      (const float*)x, (float*)v, (long long*)i,
      (unsigned long long*)scratch, (unsigned int*)ctr,
      c.n, c.k, c.KP, c.BPR, c.NC, c.NSLOT, c.W);
}

// (RPT, CAP) are compile time; KP rides along as a plain argument.
// Returns false when the host asked for an (RPT, CAP) that was never
// instantiated -- the caller MUST treat that as an error.  An earlier version
// fell off the end of this switch instead, which launched nothing at all and
// was invisible: the output buffers kept their previous (plausible) contents
// and the autotuner happily ranked the do-nothing config fastest.
#define TK_CAPS(RPT, BT)                                                      \
  switch (c.CAP) {                                                            \
    case  32: tk_go<RPT,  32, BT>(a, x, v, i, s, ct, c, st); return true;      \
    case  64: tk_go<RPT,  64, BT>(a, x, v, i, s, ct, c, st); return true;      \
    case 128: tk_go<RPT, 128, BT>(a, x, v, i, s, ct, c, st); return true;      \
    default:  return false;                                                   \
  }

bool tk_dispatch(bool a, const void* x, void* v, void* i, void* s, void* ct,
                 const TKCfg& c, cudaStream_t st) {
  if (c.CAP > 128) {                 // k > 128: correctness fallback, one shape
    if (c.CAP != 256 || c.RPT != 8 || c.BT != 256) return false;
    tk_go<8, 256, 256>(a, x, v, i, s, ct, c, st);
    return true;
  }
  // keep in sync with _BTRPT in python
  if (c.BT == 256) switch (c.RPT) {
    case  4: TK_CAPS( 4, 256)
    case  5: TK_CAPS( 5, 256)
    case  6: TK_CAPS( 6, 256)
    case  8: TK_CAPS( 8, 256)
    case 10: TK_CAPS(10, 256)
    case 12: TK_CAPS(12, 256)
    case 16: TK_CAPS(16, 256)
    case 20: TK_CAPS(20, 256)
    case 24: TK_CAPS(24, 256)
    case 32: TK_CAPS(32, 256)
    case 40: TK_CAPS(40, 256)
    case 48: TK_CAPS(48, 256)
    case 56: TK_CAPS(56, 256)
    case 64: TK_CAPS(64, 256)
    default: return false;
  }
  if (c.BT == 512) switch (c.RPT) {
    case  4: TK_CAPS( 4, 512)
    case  8: TK_CAPS( 8, 512)
    case 12: TK_CAPS(12, 512)
    case 16: TK_CAPS(16, 512)
    case 24: TK_CAPS(24, 512)
    case 32: TK_CAPS(32, 512)
    default: return false;
  }
  if (c.BT == 1024) switch (c.RPT) {
    case  2: TK_CAPS( 2, 1024)
    case  4: TK_CAPS( 4, 1024)
    case  6: TK_CAPS( 6, 1024)
    case  8: TK_CAPS( 8, 1024)
    case 12: TK_CAPS(12, 1024)
    case 16: TK_CAPS(16, 1024)
    default: return false;
  }
  return false;
}
'''

_CPP = r'''
#include <torch/extension.h>
#include <c10/cuda/CUDAStream.h>
#include <cuda_runtime.h>

struct TKCfg { int n, k, KP, RPT, CAP, BT, BPR, NC, NSLOT, W, batch;
               size_t shmem; };
bool tk_dispatch(bool attr_only, const void* x, void* v, void* i, void* scratch,
                 void* ctr, const TKCfg& c, cudaStream_t st);

namespace {

struct Plan {
  TKCfg c;
  void *vp, *ip, *sp, *cp;
  torch::Tensor v, i, scratch, ctr;
  py::object result;

  Plan(torch::Tensor v_, torch::Tensor i_, torch::Tensor s_, torch::Tensor c_,
       int n, int k, int KP, int RPT, int CAP, int BT, int BPR, int NC,
       int NSLOT, int W, int batch, int64_t shmem)
      : v(v_), i(i_), scratch(s_), ctr(c_) {
    c.n = n; c.k = k; c.KP = KP; c.RPT = RPT; c.CAP = CAP; c.BT = BT;
    c.BPR = BPR; c.NC = NC; c.NSLOT = NSLOT; c.W = W; c.batch = batch;
    c.shmem = (size_t)shmem;
    vp = v.data_ptr(); ip = i.data_ptr();
    sp = scratch.numel() ? scratch.data_ptr() : nullptr;
    cp = ctr.numel() ? ctr.data_ptr() : nullptr;
    result = py::make_tuple(v, i);
    TORCH_CHECK(tk_dispatch(true, nullptr, nullptr, nullptr, nullptr, nullptr,
                            c, nullptr),
                "topk: no kernel instantiated for RPT=", RPT, " CAP=", CAP,
                " BT=", BT);
  }

  // launches on the caller's current stream (capturable by torch.cuda.graph)
  void launch(const torch::Tensor& x) {
    TORCH_CHECK(tk_dispatch(false, x.data_ptr(), vp, ip, sp, cp, c,
                            at::cuda::getCurrentCUDAStream()),
                "topk: no kernel instantiated for RPT=", c.RPT,
                " CAP=", c.CAP, " BT=", c.BT);
  }
  py::object call(const torch::Tensor& x) {
    launch(x);
    return result;
  }
  py::object res() { return result; }
};

}  // namespace

PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
  py::class_<Plan>(m, "Plan")
      .def(py::init<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor,
                    int, int, int, int, int, int, int, int, int, int, int,
                    int64_t>())
      .def("launch", &Plan::launch)
      .def("call", &Plan::call)
      .def("res", &Plan::res);
}
'''


# ---------------------------------------------------------------------------
# host-side configuration
# ---------------------------------------------------------------------------

_NSM = 132          # H100 PCIe
# Phase-2 candidate cap.  Raising it past 4096 only unlocks configs that split
# a row into more, smaller segments; measured on shape0 (n=131072, k=64) every
# one of those loses by 1.5-3 us -- the single phase-2 block grows faster than
# the extra phase-1 parallelism pays back.
_MAX_NC = 4096
_KEEP = 10          # candidates that survive the autotuner's screening round
# Registers of keys per thread; SEG = RPT*BT elements per block.  The large
# values exist so that a whole row can fit in ONE block: BPR==1 skips the
# cross-block handoff entirely (threadfence + ticket + a single block merging
# every other block's candidates), and for every row count that already fills
# the machine that handoff's serial latency costs more than the extra
# parallelism buys -- n=16384 x 32 rows measures 1.6-1.9 us worse at BPR>=2.
# RPT=64 is 64 regs/thread of keys at BT=256, still 4 blocks/SM.
_RPTS = (4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40, 48, 56, 64)
_CAPS = (32, 64, 128)                          # ditto (256 = k>128 fallback)
# Threads per block.  A block owns one segment, so with batch=1 and n=131072
# only BPR = 32-64 blocks exist at all: at BT=256 that is 8 warps on each of 32
# SMs (12.5% occupancy, 100 SMs idle) and the select is latency- not
# throughput-bound.  Wider blocks are the only way to fill an SM when the row
# count is small, so BT joins (rpt, cap) as a tuned dimension.  Keep in sync
# with tk_dispatch.
_BTRPT = ((256, _RPTS),
          (512, (4, 8, 12, 16, 24, 32)),
          (1024, (2, 4, 6, 8, 12, 16)))

# Frozen (rpt, cap, bt) shortlists, best first, keyed by (batch, n, k).
#
# _tune has to be cheap enough to run at build time, and its verdict over ~75
# candidates lands inside this machine's run-to-run drift: two byte-identical
# modules tuned in the same process picked different configs on 3 of 5 shapes,
# and the loser cost 1-2% of the geomean -- more than any code change measured
# here.  So the ranking is done offline instead (scratch/csweep.py: 8 screening
# then 60 paired iterations per candidate) and only the survivors are kept.
# _tune still races them, because the top few are usually a statistical tie and
# the local machine gets the last word; it just can no longer pick a loser.
_TABLE = {
    (1, 131072, 64): ((8, 64, 512), (4, 128, 1024), (8, 128, 1024)),
    (64, 8192, 8):   ((16, 32, 1024), (8, 32, 1024), (32, 64, 512)),
    (32, 16384, 32): ((16, 64, 1024), (32, 64, 512), (16, 128, 1024)),
    (16, 12000, 16): ((12, 32, 1024), (12, 64, 1024), (6, 32, 256)),
    (128, 4096, 1):  ((16, 32, 256), (8, 32, 512), (8, 64, 512)),
}
# force a single (rpt, cap) candidate, keyed by (batch, n, k) -- skips autotune
_OVERRIDE = {}
_TUNE = os.environ.get("TOPK_TUNE", "1") != "0"
_USE_TABLE = os.environ.get("TOPK_TABLE", "1") != "0"


def _wsz(bt, KP):
    """Threads per bound group: the largest power of two <= min(32, BT/KP).

    BT/W groups each hand the select one witness key >= T, and BT/W >= KP is
    what makes T a valid lower bound on the KP-th largest.  Wider groups mean a
    tighter T (a narrower starting interval); 32 is the shuffle-group limit.
    0 disables the bound -- KP too large for KP groups to exist.
    """
    if KP < 1 or KP > bt // 2:
        return 0
    w, lim = 1, min(32, bt // KP)
    while w * 2 <= lim:
        w *= 2
    return w


def _cands(batch, n, k):
    """Every viable (rpt, cap) config, cheapest-looking first."""
    KP = k
    if k > 128:                      # correctness fallback: one instantiation
        caps, rpts = (256,), (8,)
    else:
        caps = tuple(c for c in _CAPS if c >= KP)
        rpts = _RPTS
    bts = _BTRPT if k <= 128 else ((256, (8,)),)
    ov = _OVERRIDE.get((batch, n, k))
    if ov is not None:
        rpts, caps = (ov[0],), (ov[1],)
        if len(ov) > 2:
            bts = ((ov[2], (ov[0],)),)
    out = []
    for bt, btrpts in bts:
        for rpt in (r for r in btrpts if r in rpts):
            SEG = bt * rpt
            BPR = max(1, (n + SEG - 1) // SEG)
            W = _wsz(bt, KP)
            total = BPR * batch
            waves = (total + _NSM - 1) // _NSM
            # single-phase first (no cross-block merge at all), then one full
            # wave, then fewer phase-2 candidates.  Only the default when
            # autotuning is unavailable -- _tune re-ranks these by measurement.
            score = (8.0 if BPR > 1 else 0.0) + (waves - 1) * 4.0 \
                + abs(1.0 - total / float(min(_NSM * waves, _NSM)))
            for cap in caps:
                # a multi-block row ships all CAP survivors, not just KP
                NC = BPR * cap
                if NC > _MAX_NC:
                    continue
                NSLOT = NC if BPR > 1 else 0
                shmem = cap * 16 + 2 * NSLOT * 4 + 256 * 4 + 256 * 4 + 3 * 8 * 4
                if shmem > 200 * 1024:
                    continue
                # smallest viable CAP first: a wider CAP both sorts more keys
                # and ships more of them, and cap=128 measures ~1 us worse than
                # cap=64 at k=64 for the same segmentation.
                out.append((score, NC, cap, rpt, bt,
                            dict(n=n, k=k, KP=KP, RPT=rpt, CAP=cap, BT=bt,
                                 SEG=SEG, BPR=BPR, NC=NC, NSLOT=NSLOT, W=W,
                                 batch=batch, shmem=shmem)))
    assert out, f"no config for n={n} k={k}"
    out.sort(key=lambda t: t[:5])
    out = [t[5] for t in out]
    tab = _TABLE.get((batch, n, k)) if (_USE_TABLE and ov is None) else None
    if tab:                          # measured shortlist wins over the heuristic
        rank = {t: j for j, t in enumerate(tab)}
        short = sorted((c for c in out
                        if (c["RPT"], c["CAP"], c["BT"]) in rank),
                       key=lambda c: rank[(c["RPT"], c["CAP"], c["BT"])])
        if short:
            return short
    return out


def _cfg(batch, n, k):
    return _cands(batch, n, k)[0]


# ---------------------------------------------------------------------------
# extension build (cached across shapes)
# ---------------------------------------------------------------------------

_EXT = None


def _ext():
    global _EXT
    if _EXT is None:
        inc = []
        try:
            import pybind11
            inc.append(pybind11.get_include())
        except Exception:
            pass
        _EXT = load_inline(
            name="topk_bitonic_ext",
            cpp_sources=_CPP,
            cuda_sources=_CUDA,
            extra_include_paths=inc,
            extra_cflags=["-O3"],
            extra_cuda_cflags=["-O3", "--use_fast_math", "-lineinfo",
                               "-gencode", "arch=compute_90,code=sm_90"],
            verbose=False,
        )
    return _EXT


# ---------------------------------------------------------------------------
# Model
# ---------------------------------------------------------------------------

class Model(nn.Module):
    """Top-k over the last dim of a 2D tensor (custom CUDA kernel)."""

    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._cands = _cands(batch, n, k)
        self._cfg = self._cands[0]
        self._plan = None
        self._graphs = {}
        self._out = None
        self._fx = None          # tensor the fast path is bound to (identity)
        self._frep = None        # its graph-replay thunk
        self._use_graph = os.environ.get("TOPK_NO_GRAPH", "0") != "1"

    # -- lazy device-side setup (buffers must follow x's device) ------------
    def _build(self, x):
        dev = x.device
        cands = self._cands
        v = torch.empty(self.batch, self.k, dtype=torch.float32, device=dev)
        i = torch.empty(self.batch, self.k, dtype=torch.int64, device=dev)
        nc = max(c["NC"] for c in cands)
        scratch = torch.empty(self.batch * nc, dtype=torch.int64, device=dev)
        ctr = torch.zeros(4 * self.batch, dtype=torch.int32,
                          device=dev)
        self._keep = (v, i, scratch, ctr)
        P = _ext().Plan
        plans = [P(v, i, scratch, ctr, c["n"], c["k"], c["KP"], c["RPT"], c["CAP"],
                   c["BT"], c["BPR"], c["NC"], c["NSLOT"], c["W"], c["batch"],
                   c["shmem"])
                 for c in cands]
        self._out = plans[0].res()
        pick, graph = 0, None
        if len(plans) > 1 and _TUNE and x.is_cuda and self._use_graph:
            try:
                pick, graph = self._tune(plans, x)
            except Exception:
                pick, graph = 0, None
        self._cfg = cands[pick]
        self._plan = plans[pick]
        self._launch = self._plan.launch
        self._call = self._plan.call
        if graph is not None:              # winner's graph is already captured
            self._graphs[x.data_ptr()] = (graph, graph.replay, x)

    # -- build-time autotune over the (rpt, cap) candidate list -------------
    # Timed exactly the way the scorer times it: cold L2, one event pair around
    # one graph replay -- the same submission path forward() will use, because
    # ranking candidates through a cheaper path mis-ranks them (a direct launch
    # costs ~3 us more than a replay and does not penalise configs equally).
    # Runs once, on the first call, on the caller's real input.
    def _tune(self, plans, x, iters=15):
        flush = torch.empty(32 * 1024 * 1024, dtype=torch.float32, device=x.device)
        gs, keep = [], []
        for j, p in enumerate(plans):
            try:                          # a candidate that will not capture
                gs.append(self._grab(p.launch, x))   # is simply not a candidate
                keep.append(j)
            except Exception:
                pass
        if not gs:
            raise RuntimeError("no candidate captured")
        fns = [g.replay for g in gs]
        for f in fns:
            f()
        torch.cuda.synchronize()

        # round-robin so that clock ramp / drift biases every candidate equally
        def race(idx, iters):
            ts = [[] for _ in idx]
            for _ in range(iters):
                for jj, j in enumerate(idx):
                    flush.zero_()
                    torch.cuda.synchronize()
                    s = torch.cuda.Event(enable_timing=True)
                    e = torch.cuda.Event(enable_timing=True)
                    s.record()
                    fns[j]()
                    e.record()
                    torch.cuda.synchronize()
                    ts[jj].append(s.elapsed_time(e))
            for t in ts:
                t.sort()
            return sorted((t[len(t) // 2], j) for t, j in zip(ts, idx))

        # Two stages: a cheap screen over every candidate, then a long re-race of
        # the survivors.  Candidate medians here sit within this machine's
        # run-to-run drift (~0.3 us peak), so a single 15-iteration pass over 75
        # candidates picks partly by luck; screening first spends 4x the
        # iterations where they decide something, for fewer launches overall.
        idx, scr = list(range(len(fns))), []
        if len(idx) > 3 * _KEEP:
            scr = race(idx, max(4, iters // 3))
            idx = [j for _, j in scr[:_KEEP]]
            iters *= 3
        elif len(idx) <= 4:
            iters = max(iters, 45)     # a frozen shortlist: spend it all here
        med = race(idx, iters)
        self._tuned = sorted([(t, keep[j]) for t, j in med] +
                             [(t, keep[j]) for t, j in scr if j not in idx])
        del flush
        j = min(med)[1]
        return keep[j], gs[j]

    # capture one launch into a graph (warm it on a side stream first, so no
    # first-touch driver work lands inside the capture)
    def _grab(self, launch, x):
        g = torch.cuda.CUDAGraph()
        s = torch.cuda.Stream()
        s.wait_stream(torch.cuda.current_stream())
        with torch.cuda.stream(s):
            for _ in range(3):
                launch(x)
        torch.cuda.current_stream().wait_stream(s)
        with torch.cuda.graph(g):
            launch(x)
        # A capture that recorded nothing replays as a no-op, and that failure
        # is invisible from the outside: the caller still receives the output
        # buffers, which the warmup above just filled with the right answer for
        # THIS x, and an autotuner would clock it as free.  So prove the replay
        # writes: poison the values and require them gone.
        v = self._out[0]
        v.fill_(float("nan"))
        g.replay()
        torch.cuda.synchronize()
        if bool(v.isnan().all()):
            raise RuntimeError("CUDA graph capture recorded no work")
        return g

    def _capture(self, x):
        g = self._grab(self._launch, x)
        e = (g, g.replay, x)
        self._graphs[x.data_ptr()] = e
        return e

    # Hot path.  Measured time here is ~95% fixed cost (GPU wake-up + one graph
    # launch), so the python side is stripped to the bone: once a tensor has a
    # captured graph, `self.__class__` is swapped for a one-off subclass whose
    # __call__ closes over the replay thunk and the result tuple as *default
    # arguments*.  Every name in the hot body is then a LOAD_FAST -- no
    # attribute lookups, no bound-method creation, one python frame.
    def _install(self, x, rep):
        def __call__(y, _x=x, _rep=rep, _out=self._out, _slow=self._slow):
            if y is _x:
                _rep()
                return _out
            return _slow(y)
        cls = type(self)
        if not cls.__dict__.get("_FAST"):      # one throwaway class per instance,
            cls = type("ModelFast", (cls,), {"_FAST": True})   # rebound in place
            self.__class__ = cls               # afterwards, never re-derived
        cls.__call__ = staticmethod(__call__)

    def forward(self, x):
        return self._slow(x)

    def _slow(self, x):
        if self._plan is None:
            self._build(x)
        if self._use_graph and x.is_cuda:
            e = self._graphs.get(x.data_ptr())
            if e is None and len(self._graphs) < 16:
                try:
                    e = self._capture(x)
                except Exception:
                    self._use_graph = False
                    e = None
            if e is not None:
                if e[2] is x:
                    self._install(x, e[1])
                e[1]()
                return self._out
        return self._call(x)

    __call__ = forward


# ---------------------------------------------------------------------------
# harness shims
# ---------------------------------------------------------------------------

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]

20260725_084321_or-opus_anthropic_claude-opus-5_05_topk_bitonic