KernelBench hard · B200

FP8 GEMM Claude Fable 5

25.4%geomean peak fraction across shapes

manually audited: clean

harnessor-fableagent session2h 44mtotal wall2h 45mcheck11sbenchmark7soutput tokens433,871cost$83.56gpu-lock wait0sgpu-lock held18sregimecompute

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

4096×4096×40960.062 ms49.6%2,233 TFLOPS · 50% of 4,500 TF fp8 peak · also 1.09 TB/s (14% of HBM)
4096×4096×41270.071 ms43.5%1,959 TFLOPS · 44% of 4,500 TF fp8 peak · also 0.95 TB/s (12% of HBM)
32×8192×81920.030 ms3.2%2.29 TB/s · 29% of 8.0 TB/s HBM · also 145 TFLOPS (3% of compute)
4096×14336×40960.180 ms59.3%2,668 TFLOPS · 59% of 4,500 TF fp8 peak · also 1.07 TB/s (13% of HBM)

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

geomean(49.6% · 43.5% · 3.2% · 59.3%) = 25.3%

Kernel source (redacted)
"""FP8 e4m3 GEMM for B200 (SM100): hand-written tcgen05 2-SM-MMA CUDA kernel
with Triton fallbacks, dispatched per shape, replayed via CUDA graphs.

y = (x @ w.T) * weight_scale, x fp8e4m3 (M,K), w fp8e4m3 (N,K), out bf16.

Primary path (compute-bound shapes): a self-contained CUDA/PTX kernel doing a
real fp8 x fp8 tensor-core MMA (tcgen05.mma.cta_group::2, fp32 accumulate in
TMEM, M=256 tiles across a 2-CTA cluster, B split N-wise across the pair).
TMA loads use 3D atom-major tensor maps (the TMA engine is instruction-rate
limited at ~5.5M instr/s/SM, so bigger boxes matter), a 6-deep mbarrier
pipeline, double-buffered TMEM accumulators, and a swizzled-SMEM TMA-store
epilogue with the per-output-channel scale fused in.

Skinny shapes (decode-style M<=64) use a Triton split-K kernel with a
partials+reduce finish; these are DRAM-bound.

K not a multiple of 16 (TMA byte-stride rule) is handled by zero-padding to a
multiple of 128: x is re-padded every call through a persistent buffer via a
funnel-shift copy kernel (aligned u32 loads + byte recombination -- ~1.7x
faster than cudaMemcpy2D for odd strides); the padded weight is cached and
invalidated with the tensor _version counter, because the numeric-stress
harness mutates `weight` in place between forwards.

Forward is replayed through CUDA graphs keyed on (x.data_ptr, shape): a graph
re-reads live bytes at recorded addresses, so replay stays correct when tensor
contents change; new address or shape triggers a fresh capture. This removes
~10-20us of Python/launch overhead per call.
"""
import os

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

E4M3_MAX = 448.0
_NUM_SMS = None


def _alloc(size, alignment, stream):
    return torch.empty(size, device="cuda", dtype=torch.int8)


triton.set_allocator(_alloc)


def _num_sms():
    global _NUM_SMS
    if _NUM_SMS is None:
        _NUM_SMS = torch.cuda.get_device_properties(0).multi_processor_count
    return _NUM_SMS


# ==========================================================================
# Hand-written SM100 tcgen05 kernel (primary path)
# ==========================================================================
_CUDA_SRC = r"""
// SM100 (B200) fp8e4m3 x fp8e4m3 -> bf16 GEMM with per-output-channel scale.
// Hand-rolled tcgen05 kernel: 2-CTA cluster MMA (cta_group::2, M=256), TMA
// double-sided pipeline, TMEM double-buffered accumulators, TMA-store epilogue.
//
// y[m, n] = (sum_k x[m, k] * w[n, k]) * scale[n]
//   x: (M, K) fp8e4m3 row-major, K % 16 == 0 (byte stride rule)
//   w: (N, K) fp8e4m3 row-major
//   scale: (N,) fp32; y: (M, N) bf16
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cuda_bf16.h>
#include <cstdint>

// ------------------------------ device PTX helpers ------------------------
#define DEVICE __device__ __forceinline__

DEVICE uint32_t smem_u32(const void* p) {
  return static_cast<uint32_t>(__cvta_generic_to_shared(p));
}

DEVICE bool elect_one_sync() {
  uint32_t pred = 0;
  asm volatile(
      "{\n .reg .pred %%px;\n elect.sync _|%%px, 0xffffffff;\n selp.b32 %0, 1, 0, %%px;\n}\n"
      : "+r"(pred)::"memory");
  return pred != 0;
}

DEVICE void mbar_init(uint64_t* bar, uint32_t count) {
  asm volatile("mbarrier.init.shared::cta.b64 [%0], %1;" ::"r"(smem_u32(bar)), "r"(count));
}

DEVICE void fence_barrier_init() {
  asm volatile("fence.mbarrier_init.release.cluster;" ::: "memory");
}

DEVICE void mbar_wait(uint64_t* bar, uint32_t phase) {
  asm volatile(
      "{\n"
      ".reg .pred P;\n"
      "WAIT:\n"
      "mbarrier.test_wait.parity.shared::cta.b64 P, [%0], %1;\n"
      "@P bra DONE;\n"
      "bra WAIT;\n"
      "DONE:\n"
      "}\n" ::"r"(smem_u32(bar)),
      "r"(phase));
}

DEVICE void mbar_wait_park(uint64_t* bar, uint32_t phase) {
  asm volatile(
      "{\n"
      ".reg .pred P;\n"
      "WAIT:\n"
      "mbarrier.try_wait.parity.shared::cta.b64 P, [%0], %1, 10000000;\n"
      "@P bra DONE;\n"
      "bra WAIT;\n"
      "DONE:\n"
      "}\n" ::"r"(smem_u32(bar)),
      "r"(phase));
}

DEVICE void mbar_arrive_expect_tx(uint64_t* bar, uint32_t tx) {
  asm volatile("mbarrier.arrive.expect_tx.shared::cta.b64 _, [%0], %1;" ::"r"(smem_u32(bar)),
               "r"(tx)
               : "memory");
}

DEVICE void mbar_arrive_local(uint64_t* bar) {
  asm volatile("mbarrier.arrive.shared::cta.b64 _, [%0];" ::"r"(smem_u32(bar)) : "memory");
}

// Arrive at the same barrier in the cluster-rank-0 CTA (remote for rank 1).
DEVICE void mbar_arrive_cluster0(uint64_t* bar) {
  uint32_t addr = smem_u32(bar);
  uint32_t remote;
  asm volatile("mapa.shared::cluster.u32 %0, %1, 0;" : "=r"(remote) : "r"(addr));
  asm volatile("mbarrier.arrive.release.cluster.shared::cluster.b64 _, [%0];" ::"r"(remote)
               : "memory");
}

DEVICE void cluster_sync() {
  asm volatile("barrier.cluster.arrive.aligned;" ::: "memory");
  asm volatile("barrier.cluster.wait.aligned;" ::: "memory");
}

DEVICE uint32_t cluster_ctarank() {
  uint32_t r;
  asm volatile("mov.u32 %0, %%cluster_ctarank;" : "=r"(r));
  return r;
}

DEVICE void prefetch_tmap(const void* p) {
  asm volatile("prefetch.tensormap [%0];" ::"l"(p) : "memory");
}

// TMA load (cta_group::2): both CTAs issue; tx bytes credited to rank-0 barrier.
DEVICE void tma_load_2sm(const void* tmap, uint64_t* bar, void* smem, int32_t c0, int32_t c1) {
  uint32_t mbar = smem_u32(bar) & 0xFEFFFFFF;  // clear peer bit -> leader CTA
  constexpr uint64_t kEvictNormal = 0x1000000000000000ull;
  asm volatile(
      "cp.async.bulk.tensor.2d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
      " [%0], [%1, {%3, %4}], [%2], %5;" ::"r"(smem_u32(smem)),
      "l"(reinterpret_cast<uint64_t>(tmap)), "r"(mbar), "r"(c0), "r"(c1), "l"(kEvictNormal)
      : "memory");
}

// 3D TMA load, cta_group::2: tx credited to leader CTA's barrier (peer bit cleared)
DEVICE void tma_load3d(const void* tmap, uint64_t* bar, void* smem, int32_t c1, int32_t c2) {
  uint32_t mbar = smem_u32(bar) & 0xFEFFFFFF;
  constexpr uint64_t kEvictNormal = 0x1000000000000000ull;
  asm volatile(
      "cp.async.bulk.tensor.3d.cta_group::2.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
      " [%0], [%1, {0, %3, %4}], [%2], %5;" ::"r"(smem_u32(smem)),
      "l"(reinterpret_cast<uint64_t>(tmap)), "r"(mbar), "r"(c1), "r"(c2), "l"(kEvictNormal)
      : "memory");
}

// Plain 1-CTA TMA load (for the 1SM kernel variant)
DEVICE void tma_load_1sm(const void* tmap, uint64_t* bar, void* smem, int32_t c0, int32_t c1) {
  constexpr uint64_t kEvictNormal = 0x1000000000000000ull;
  asm volatile(
      "cp.async.bulk.tensor.2d.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
      " [%0], [%1, {%3, %4}], [%2], %5;" ::"r"(smem_u32(smem)),
      "l"(reinterpret_cast<uint64_t>(tmap)), "r"(smem_u32(bar)), "r"(c0), "r"(c1),
      "l"(kEvictNormal)
      : "memory");
}

DEVICE void tma_store_2d(const void* tmap, const void* smem, int32_t c0, int32_t c1) {
  asm volatile(
      "cp.async.bulk.tensor.2d.global.shared::cta.tile.bulk_group [%0, {%2, %3}], [%1];" ::"l"(
          reinterpret_cast<uint64_t>(tmap)),
      "r"(smem_u32(smem)), "r"(c0), "r"(c1)
      : "memory");
}

DEVICE void tma_store_commit() { asm volatile("cp.async.bulk.commit_group;" ::: "memory"); }

template <int N>
DEVICE void tma_store_wait() {
  asm volatile("cp.async.bulk.wait_group.read %0;" ::"n"(N) : "memory");
}

DEVICE void fence_async_proxy() {
  asm volatile("fence.proxy.async.shared::cta;" ::: "memory");
}

// tcgen05
DEVICE void tmem_alloc_2sm(uint32_t* dst_smem, uint32_t ncols) {
  asm volatile("tcgen05.alloc.cta_group::2.sync.aligned.shared::cta.b32 [%0], %1;" ::"r"(
                   smem_u32(dst_smem)),
               "r"(ncols));
}
DEVICE void tmem_relinquish_2sm() {
  asm volatile("tcgen05.relinquish_alloc_permit.cta_group::2.sync.aligned;" ::);
}
DEVICE void tmem_dealloc_2sm(uint32_t addr, uint32_t ncols) {
  asm volatile("tcgen05.dealloc.cta_group::2.sync.aligned.b32 %0, %1;" ::"r"(addr), "r"(ncols));
}
DEVICE void tmem_alloc_1sm(uint32_t* dst_smem, uint32_t ncols) {
  asm volatile("tcgen05.alloc.cta_group::1.sync.aligned.shared::cta.b32 [%0], %1;" ::"r"(
                   smem_u32(dst_smem)),
               "r"(ncols));
}
DEVICE void tmem_relinquish_1sm() {
  asm volatile("tcgen05.relinquish_alloc_permit.cta_group::1.sync.aligned;" ::);
}
DEVICE void tmem_dealloc_1sm(uint32_t addr, uint32_t ncols) {
  asm volatile("tcgen05.dealloc.cta_group::1.sync.aligned.b32 %0, %1;" ::"r"(addr), "r"(ncols));
}

DEVICE void tcgen05_fence_after_thread_sync() {
  asm volatile("tcgen05.fence::after_thread_sync;" ::: "memory");
}
DEVICE void tcgen05_fence_before_thread_sync() {
  asm volatile("tcgen05.fence::before_thread_sync;" ::: "memory");
}
DEVICE void tcgen05_wait_ld() { asm volatile("tcgen05.wait::ld.sync.aligned;" ::: "memory"); }

// MMA: kind::f8f6f4, SS. scale_c: 0 -> overwrite acc, 1 -> accumulate.
DEVICE void umma_f8_2sm(uint32_t tmem_c, uint64_t desc_a, uint64_t desc_b, uint32_t idesc,
                        uint32_t scale_c) {
  asm volatile(
      "{\n.reg .pred p;\n setp.ne.b32 p, %4, 0;\n"
      "tcgen05.mma.cta_group::2.kind::f8f6f4 [%0], %1, %2, %3, {%5, %6, %7, %8, %9, %10, %11, %12}, p;\n}\n"
      :
      : "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(idesc), "r"(scale_c), "r"(0), "r"(0), "r"(0),
        "r"(0), "r"(0), "r"(0), "r"(0), "r"(0));
}
DEVICE void umma_f8_1sm(uint32_t tmem_c, uint64_t desc_a, uint64_t desc_b, uint32_t idesc,
                        uint32_t scale_c) {
  asm volatile(
      "{\n.reg .pred p;\n setp.ne.b32 p, %4, 0;\n"
      "tcgen05.mma.cta_group::1.kind::f8f6f4 [%0], %1, %2, %3, {%5, %6, %7, %8}, p;\n}\n"
      :
      : "r"(tmem_c), "l"(desc_a), "l"(desc_b), "r"(idesc), "r"(scale_c), "r"(0), "r"(0), "r"(0),
        "r"(0));
}

// tcgen05.commit -> mbarrier arrive, multicast to both cluster CTAs
DEVICE void umma_commit_multicast2(uint64_t* bar) {
  asm volatile(
      "tcgen05.commit.cta_group::2.mbarrier::arrive::one.shared::cluster.multicast::cluster.b64 [%0], %1;" ::
          "r"(smem_u32(bar)),
      "h"((uint16_t)0b11)
      : "memory");
}
DEVICE void umma_commit_1sm(uint64_t* bar) {
  asm volatile("tcgen05.commit.cta_group::1.mbarrier::arrive::one.shared::cluster.b64 [%0];" ::"r"(
                   smem_u32(bar))
               : "memory");
}

// TMEM load: 32 lanes x 8 consecutive 32-bit columns per lane
DEVICE void tmem_ld_32x32b_x8(uint32_t addr, uint32_t v[8]) {
  asm volatile(
      "tcgen05.ld.sync.aligned.32x32b.x8.b32 {%0, %1, %2, %3, %4, %5, %6, %7}, [%8];"
      : "=r"(v[0]), "=r"(v[1]), "=r"(v[2]), "=r"(v[3]), "=r"(v[4]), "=r"(v[5]), "=r"(v[6]),
        "=r"(v[7])
      : "r"(addr));
}

DEVICE uint32_t pack_bf16(float lo, float hi) {
  __nv_bfloat162 h = __float22bfloat162_rn({lo, hi});
  return *reinterpret_cast<uint32_t*>(&h);
}

DEVICE void st_shared_v4(void* p, uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
  asm volatile("st.shared.v4.b32 [%0], {%1, %2, %3, %4};" ::"r"(smem_u32(p)), "r"(a), "r"(b),
               "r"(c), "r"(d));
}

DEVICE void named_barrier_sync(uint32_t id, uint32_t nthreads) {
  asm volatile("bar.sync %0, %1;" ::"r"(id), "r"(nthreads) : "memory");
}

// SMEM descriptor for K-major SW128 tiles: SBO=1024B, LBO=0, version=1, layout=SWIZZLE_128B(2)
DEVICE uint64_t make_desc_k_major_sw128(const void* smem) {
  const uint32_t lo = smem_u32(smem) >> 4;
  const uint32_t hi = 64u /*SBO 1024>>4*/ | (1u << 14) /*version*/ | (2u << 29) /*SW128*/;
  return (uint64_t)lo | ((uint64_t)hi << 32);
}

// ------------------------------ kernel ------------------------------------
// Per-CTA: A tile 128 x BK, B tile (BN/2) x BK (2SM: pair covers 256 x BN).
template <uint32_t BN, uint32_t BK, uint32_t STAGES, uint32_t GROUP_M, uint32_t MODE = 0>
__global__ void __launch_bounds__(256, 1) fp8_gemm_2sm_kernel(
    const __grid_constant__ CUtensorMap tmap_a, const __grid_constant__ CUtensorMap tmap_b,
    const __grid_constant__ CUtensorMap tmap_d, const float* __restrict__ scale, uint32_t M,
    uint32_t N, uint32_t K, uint32_t num_k_blocks) {
#if __CUDA_ARCH__ >= 1000
  constexpr uint32_t BM = 256;               // pair-wide M tile
  constexpr uint32_t LOAD_M = 128;           // per-CTA A rows
  constexpr uint32_t LOAD_N = BN / 2;        // per-CTA B rows (N-split across pair)
  constexpr uint32_t ACC_STAGES = 2;
  constexpr uint32_t ATOMS = BK / 128;       // 128B swizzle atoms per stage
  constexpr uint32_t SMEM_A_STAGE = LOAD_M * BK;      // bytes (fp8)
  constexpr uint32_t SMEM_B_STAGE = LOAD_N * BK;      // bytes
  constexpr uint32_t STORE_N = 64;                    // bf16 cols per CD stage (128B swizzle)
  constexpr uint32_t CD_STAGES = 2;
  constexpr uint32_t SMEM_CD_STAGE = 128 * STORE_N * 2;  // 16KB

  extern __shared__ __align__(1024) uint8_t smem[];
  uint8_t* smem_cd = smem;                                   // CD_STAGES * 16KB
  uint8_t* smem_a = smem + CD_STAGES * SMEM_CD_STAGE;        // STAGES * SMEM_A_STAGE
  uint8_t* smem_b = smem_a + STAGES * SMEM_A_STAGE;          // STAGES * SMEM_B_STAGE
  uint64_t* bars = reinterpret_cast<uint64_t*>(smem_b + STAGES * SMEM_B_STAGE);
  uint64_t* full_bar = bars;                    // [STAGES]
  uint64_t* empty_bar = bars + STAGES;          // [STAGES]
  uint64_t* tmem_full = bars + 2 * STAGES;      // [ACC_STAGES]
  uint64_t* tmem_empty = bars + 2 * STAGES + ACC_STAGES;  // [ACC_STAGES]
  uint32_t* tmem_ptr = reinterpret_cast<uint32_t*>(bars + 2 * STAGES + 2 * ACC_STAGES);

  const uint32_t warp_idx = threadIdx.x / 32;
  const uint32_t lane_idx = threadIdx.x % 32;
  const uint32_t rank = cluster_ctarank();  // 0 = leader
  const bool is_leader = rank == 0;

  if (warp_idx == 0 && elect_one_sync()) {
    prefetch_tmap(&tmap_a);
    prefetch_tmap(&tmap_b);
    prefetch_tmap(&tmap_d);
  }

  cluster_sync();  // rendezvous before 2-CTA TMEM alloc

  if (warp_idx == 1 && elect_one_sync()) {
    for (uint32_t i = 0; i < STAGES; ++i) {
      mbar_init(&full_bar[i], 1);   // leader's arrive_expect_tx only; peer tx auto-credits
      mbar_init(&empty_bar[i], 1);  // one multicast commit per CTA
    }
    for (uint32_t i = 0; i < ACC_STAGES; ++i) {
      mbar_init(&tmem_full[i], 1);           // one multicast commit
      mbar_init(&tmem_empty[i], 2);          // one elected arrive per CTA
    }
    fence_barrier_init();
  } else if (warp_idx == 2) {
    tmem_alloc_2sm(tmem_ptr, 512);
    tmem_relinquish_2sm();
  }
  cluster_sync();

  // ---- persistent tile schedule (grouped along M) ----
  const uint32_t num_pid_m = (M + BM - 1) / BM;
  const uint32_t num_pid_n = (N + BN - 1) / BN;
  const uint32_t num_tiles = num_pid_m * num_pid_n;
  const uint32_t cluster_id = blockIdx.x / 2;
  const uint32_t num_clusters = gridDim.x / 2;
  const uint32_t pids_per_group = GROUP_M * num_pid_n;

  auto tile_coords = [&](uint32_t tile, uint32_t& pm, uint32_t& pn) {
    uint32_t group = tile / pids_per_group;
    uint32_t first_m = group * GROUP_M;
    uint32_t gsz = min(num_pid_m - first_m, GROUP_M);
    pm = first_m + (tile % pids_per_group) % gsz;
    pn = (tile % pids_per_group) / gsz;
  };

  if (warp_idx == 0) {
    // ---- TMA producer ----
    if (elect_one_sync()) {
      uint32_t stage = 0, phase = 0;
      for (uint32_t tile = cluster_id; tile < num_tiles; tile += num_clusters) {
        uint32_t pm, pn;
        tile_coords(tile, pm, pn);
        const int32_t m_idx = pm * BM + rank * LOAD_M;
        const int32_t n_idx = pn * BN + rank * LOAD_N;
        for (uint32_t kb = 0; kb < num_k_blocks; ++kb) {
          mbar_wait(&empty_bar[stage], phase ^ 1);
          if (is_leader)
            mbar_arrive_expect_tx(&full_bar[stage], 2 * (SMEM_A_STAGE + SMEM_B_STAGE));
          tma_load3d(&tmap_a, &full_bar[stage], smem_a + stage * SMEM_A_STAGE, m_idx, kb * ATOMS);
          tma_load3d(&tmap_b, &full_bar[stage], smem_b + stage * SMEM_B_STAGE, n_idx, kb * ATOMS);
          stage = stage + 1 == STAGES ? 0 : stage + 1;
          phase ^= (stage == 0);
        }
      }
    }
  } else if (warp_idx == 1 && is_leader) {
    // ---- MMA issuer (leader CTA only) ----
    // idesc: c_format=F32, e4m3 x e4m3, M=256, N=BN, K-major both
    const uint32_t idesc = (1u << 4) | ((BN >> 3) << 17) | ((256u >> 4) << 24);
    uint32_t stage = 0, phase = 0;
    uint32_t iter = 0;
    for (uint32_t tile = cluster_id; tile < num_tiles; tile += num_clusters, ++iter) {
      const uint32_t acc_stage = iter % ACC_STAGES;
      const uint32_t acc_phase = (iter / ACC_STAGES) & 1;
      mbar_wait(&tmem_empty[acc_stage], acc_phase ^ 1);
      tcgen05_fence_after_thread_sync();

      for (uint32_t kb = 0; kb < num_k_blocks; ++kb) {
        mbar_wait(&full_bar[stage], phase);
        tcgen05_fence_after_thread_sync();
        if (elect_one_sync()) {
          uint64_t desc_a = make_desc_k_major_sw128(smem_a + stage * SMEM_A_STAGE);
          uint64_t desc_b = make_desc_k_major_sw128(smem_b + stage * SMEM_B_STAGE);
          const uint32_t tmem_c = acc_stage * BN;
          uint32_t accum = (kb > 0) ? 1u : 0u;
#pragma unroll
          for (uint32_t u = 0; u < BK / 32; ++u) {
            // per-atom SMEM step = LOAD_M rows * 128B; within-atom step = 32B
            const uint32_t lo_off = (u / 4) * (LOAD_M * 128 / 16) + (u % 4) * 2;
            umma_f8_2sm(tmem_c, desc_a + lo_off, desc_b + (u / 4) * (LOAD_N * 128 / 16) + (u % 4) * 2,
                        idesc, accum | (u > 0 ? 1u : 0u));
          }
          umma_commit_multicast2(&empty_bar[stage]);
          if (kb == num_k_blocks - 1) umma_commit_multicast2(&tmem_full[acc_stage]);
        }
        __syncwarp();
        stage = stage + 1 == STAGES ? 0 : stage + 1;
        phase ^= (stage == 0);
      }
    }
    // allow safe teardown: wait for last accumulator to be drained
    if (iter > 0) {
      const uint32_t last = iter - 1;
      mbar_wait(&tmem_empty[last % ACC_STAGES], (last / ACC_STAGES) & 1);
    }
  } else if (warp_idx >= 4) {
    // ---- epilogue: 4 warps, 128 threads ----
    const uint32_t ep_warp = warp_idx - 4;
    const uint32_t row = ep_warp * 32 + lane_idx;  // row in this CTA's 128-row half
    uint32_t cd_stage = 0;
    uint32_t iter = 0;
    for (uint32_t tile = cluster_id; tile < num_tiles; tile += num_clusters, ++iter) {
      uint32_t pm, pn;
      tile_coords(tile, pm, pn);
      const uint32_t acc_stage = iter % ACC_STAGES;
      const uint32_t acc_phase = (iter / ACC_STAGES) & 1;
      mbar_wait(&tmem_full[acc_stage], acc_phase);
      tcgen05_fence_after_thread_sync();

      const int32_t m_idx = pm * BM + rank * LOAD_M;  // this CTA's 128 rows
#pragma unroll
      for (uint32_t s = 0; s < BN / STORE_N; ++s) {
        // wait for this CD buffer's previous TMA store to drain
        if (ep_warp == 0) tma_store_wait<CD_STAGES - 1>();
        named_barrier_sync(1, 128);

        uint8_t* cd = smem_cd + cd_stage * SMEM_CD_STAGE;
        const bool n_aligned = (N % BN) == 0;
#pragma unroll
        for (uint32_t i = 0; i < STORE_N / 8; i += 4) {
          uint32_t v[32];
          tmem_ld_32x32b_x8((acc_stage * BN) + s * STORE_N + i * 8, v);
          tmem_ld_32x32b_x8((acc_stage * BN) + s * STORE_N + i * 8 + 8, v + 8);
          tmem_ld_32x32b_x8((acc_stage * BN) + s * STORE_N + i * 8 + 16, v + 16);
          tmem_ld_32x32b_x8((acc_stage * BN) + s * STORE_N + i * 8 + 24, v + 24);
          tcgen05_wait_ld();
          const uint32_t n0 = pn * BN + s * STORE_N + i * 8;
          float f[32];
          if (n_aligned) {
#pragma unroll
            for (uint32_t j = 0; j < 32; ++j)
              f[j] = reinterpret_cast<float&>(v[j]) * __ldg(scale + n0 + j);
          } else {
#pragma unroll
            for (uint32_t j = 0; j < 32; ++j)
              f[j] = reinterpret_cast<float&>(v[j]) * __ldg(scale + min(n0 + j, N - 1));
          }
#pragma unroll
          for (uint32_t q = 0; q < 4; ++q) {
            uint8_t* p = cd + row * 128 + (((i + q) ^ (row % 8)) * 16);
            st_shared_v4(p, pack_bf16(f[q * 8 + 0], f[q * 8 + 1]), pack_bf16(f[q * 8 + 2], f[q * 8 + 3]),
                         pack_bf16(f[q * 8 + 4], f[q * 8 + 5]), pack_bf16(f[q * 8 + 6], f[q * 8 + 7]));
          }
        }
        if (s == BN / STORE_N - 1) tcgen05_fence_before_thread_sync();
        fence_async_proxy();
        named_barrier_sync(1, 128);
        if (ep_warp == 0 && elect_one_sync()) {
          if (s == BN / STORE_N - 1)
            mbar_arrive_cluster0(&tmem_empty[acc_stage]);  // rank0-local, rank1-remote
          tma_store_2d(&tmap_d, cd, pn * BN + s * STORE_N, m_idx);
          tma_store_commit();
        }
        cd_stage ^= 1;
      }
    }
    if (ep_warp == 0) tma_store_wait<0>();
  }

  cluster_sync();
  if (warp_idx == 2) tmem_dealloc_2sm(0, 512);
#endif
}

// ------------------------------ host side ---------------------------------
// {128B, rows, K/128 atoms} view with atom-major boxes {128, box_rows, 2}
static CUtensorMap make_tmap_3d_atoms(const void* ptr, uint64_t rows, uint64_t K,
                                      uint32_t box_rows, uint32_t box_atoms) {
  CUtensorMap tmap;
  uint64_t dims[3] = {128, rows, K / 128};
  uint64_t strides[2] = {K, 128};
  uint32_t box[3] = {128, box_rows, box_atoms};
  uint32_t es[3] = {1, 1, 1};
  CUresult res = cuTensorMapEncodeTiled(
      &tmap, CU_TENSOR_MAP_DATA_TYPE_UINT8, 3, const_cast<void*>(ptr), dims, strides, box, es,
      CU_TENSOR_MAP_INTERLEAVE_NONE, CU_TENSOR_MAP_SWIZZLE_128B,
      CU_TENSOR_MAP_L2_PROMOTION_L2_128B, CU_TENSOR_MAP_FLOAT_OOB_FILL_NONE);
  TORCH_CHECK(res == CUDA_SUCCESS, "cuTensorMapEncodeTiled 3d failed: ", (int)res);
  return tmap;
}

static CUtensorMap make_tmap_2d(const void* ptr, uint64_t inner, uint64_t outer,
                                uint64_t stride_bytes, uint32_t box_inner, uint32_t box_outer,
                                CUtensorMapDataType dtype, CUtensorMapSwizzle swizzle) {
  CUtensorMap tmap;
  uint64_t dims[2] = {inner, outer};
  uint64_t strides[1] = {stride_bytes};
  uint32_t box[2] = {box_inner, box_outer};
  uint32_t elem_strides[2] = {1, 1};
  CUresult res = cuTensorMapEncodeTiled(
      &tmap, dtype, 2, const_cast<void*>(ptr), dims, strides, box, elem_strides,
      CU_TENSOR_MAP_INTERLEAVE_NONE, swizzle, CU_TENSOR_MAP_L2_PROMOTION_L2_128B,
      CU_TENSOR_MAP_FLOAT_OOB_FILL_NONE);
  TORCH_CHECK(res == CUDA_SUCCESS, "cuTensorMapEncodeTiled failed: ", (int)res);
  return tmap;
}

template <uint32_t BN, uint32_t BK, uint32_t STAGES, uint32_t GROUP_M, uint32_t MODE = 0>
void launch_2sm(const torch::Tensor& x, const torch::Tensor& w, const torch::Tensor& scale,
                torch::Tensor& y, int sms) {
  const uint32_t M = x.size(0), K = x.size(1), N = w.size(0);
  constexpr uint32_t SMEM_A = 128 * BK, SMEM_B = (BN / 2) * BK;
  constexpr uint32_t CD_BYTES = 2 * 128 * 64 * 2;
  constexpr uint32_t BAR_BYTES = (2 * STAGES + 4) * 8 + 16;
  const uint32_t smem_size = CD_BYTES + STAGES * (SMEM_A + SMEM_B) + BAR_BYTES;

  TORCH_CHECK(K % 128 == 0, "hand kernel requires K % 128 == 0");
  auto tmap_a = make_tmap_3d_atoms(x.data_ptr(), M, K, 128, BK / 128);
  auto tmap_b = make_tmap_3d_atoms(w.data_ptr(), N, K, BN / 2, BK / 128);
  auto tmap_d = make_tmap_2d(y.data_ptr(), N, M, (uint64_t)N * 2, 64, 128,
                             CU_TENSOR_MAP_DATA_TYPE_BFLOAT16, CU_TENSOR_MAP_SWIZZLE_128B);

  auto kernel = fp8_gemm_2sm_kernel<BN, BK, STAGES, GROUP_M, MODE>;
  static bool attr_set = false;
  if (!attr_set) {
    cudaFuncSetAttribute(kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, 232448);
    attr_set = true;
  }

  const uint32_t num_k_blocks = (K + BK - 1) / BK;
  cudaLaunchConfig_t cfg = {};
  cudaLaunchAttribute attrs[1];
  attrs[0].id = cudaLaunchAttributeClusterDimension;
  attrs[0].val.clusterDim = {2, 1, 1};
  cfg.gridDim = dim3(sms, 1, 1);
  cfg.blockDim = dim3(256, 1, 1);
  cfg.dynamicSmemBytes = smem_size;
  cfg.stream = at::cuda::getCurrentCUDAStream();
  cfg.attrs = attrs;
  cfg.numAttrs = 1;
  cudaError_t err = cudaLaunchKernelEx(&cfg, kernel, tmap_a, tmap_b, tmap_d,
                                       scale.data_ptr<float>(), M, N, K, num_k_blocks);
  TORCH_CHECK(err == cudaSuccess, "launch failed: ", cudaGetErrorString(err));
}

void gemm_fp8_2sm(torch::Tensor x, torch::Tensor w, torch::Tensor scale, torch::Tensor y,
                  int64_t sms) {
  TORCH_CHECK(x.size(1) == w.size(1), "K mismatch");
  TORCH_CHECK(x.size(1) % 128 == 0, "K must be a multiple of 128");
  TORCH_CHECK(x.is_contiguous() && w.is_contiguous() && y.is_contiguous());
  launch_2sm<256, 128, 6, 8>(x, w, scale, y, sms);
}


DEVICE void tma_load3d_1sm_hint(const void* tmap, uint64_t* bar, void* smem, int32_t c1, int32_t c2,
                                uint64_t hint) {
  asm volatile(
      "cp.async.bulk.tensor.3d.shared::cluster.global.mbarrier::complete_tx::bytes.L2::cache_hint"
      " [%0], [%1, {0, %3, %4}], [%2], %5;" ::"r"(smem_u32(smem)),
      "l"((uint64_t)tmap), "r"(smem_u32(bar)), "r"(c1), "r"(c2), "l"(hint) : "memory");
}

// ------------------- skinny-M kernel -------------------

template <uint32_t BN, uint32_t BK, uint32_t STAGES, bool EVICT_FIRST>
__global__ void __launch_bounds__(256, 1) fp8_gemm_skinny_kernel(
    const __grid_constant__ CUtensorMap tmap_a, const __grid_constant__ CUtensorMap tmap_b,
    float* __restrict__ partials, uint32_t M, uint32_t N, uint32_t K, uint32_t k_per_split) {
#if __CUDA_ARCH__ >= 1000
  constexpr uint32_t ROWS = 128;                       // MMA M (rows beyond M are TMA-zero)
  constexpr uint32_t ATOMS = BK / 128;
  constexpr uint32_t SMEM_A_STAGE = ROWS * BK;         // 32KB at BK=256
  constexpr uint32_t SMEM_B_STAGE = BN * BK;

  extern __shared__ __align__(1024) uint8_t smem[];
  uint8_t* smem_a = smem;
  uint8_t* smem_b = smem + STAGES * SMEM_A_STAGE;
  uint64_t* bars = reinterpret_cast<uint64_t*>(smem_b + STAGES * SMEM_B_STAGE);
  uint64_t* full_bar = bars;
  uint64_t* empty_bar = bars + STAGES;
  uint64_t* tmem_full = bars + 2 * STAGES;
  uint32_t* tmem_ptr = reinterpret_cast<uint32_t*>(bars + 2 * STAGES + 1);

  const uint32_t warp_idx = threadIdx.x / 32;
  const uint32_t lane_idx = threadIdx.x % 32;

  if (warp_idx == 0 && elect_one_sync()) {
    asm volatile("prefetch.tensormap [%0];" ::"l"((const void*)&tmap_a) : "memory");
    asm volatile("prefetch.tensormap [%0];" ::"l"((const void*)&tmap_b) : "memory");
  }
  if (warp_idx == 1 && elect_one_sync()) {
    for (uint32_t i = 0; i < STAGES; ++i) {
      mbar_init(&full_bar[i], 1);
      mbar_init(&empty_bar[i], 1);
    }
    mbar_init(tmem_full, 1);
    asm volatile("fence.mbarrier_init.release.cluster;" ::: "memory");
  } else if (warp_idx == 2) {
    tmem_alloc_1sm(tmem_ptr, BN >= 128 ? BN : 128);
    tmem_relinquish_1sm();
  }
  __syncthreads();

  const uint32_t pid_n = blockIdx.x;
  const uint32_t pid_s = blockIdx.y;
  const int32_t n_idx = pid_n * BN;
  const uint32_t k_lo_atom = pid_s * (k_per_split / 128);
  const uint32_t num_kb = k_per_split / BK;

  constexpr uint64_t kHintNormal = 0x1000000000000000ull;
  constexpr uint64_t kHintEvictFirst = 0x12F0000000000000ull;
  constexpr uint64_t kHint = EVICT_FIRST ? kHintEvictFirst : kHintNormal;

  if (warp_idx == 0) {
    if (elect_one_sync()) {
      uint32_t stage = 0, phase = 0;
      for (uint32_t kb = 0; kb < num_kb; ++kb) {
        mbar_wait(&empty_bar[stage], phase ^ 1);
        mbar_arrive_expect_tx(&full_bar[stage], SMEM_A_STAGE + SMEM_B_STAGE);
        tma_load3d_1sm_hint(&tmap_a, &full_bar[stage], smem_a + stage * SMEM_A_STAGE, 0,
                       k_lo_atom + kb * ATOMS, kHintNormal);
        tma_load3d_1sm_hint(&tmap_b, &full_bar[stage], smem_b + stage * SMEM_B_STAGE, n_idx,
                       k_lo_atom + kb * ATOMS, kHint);
        stage = stage + 1 == STAGES ? 0 : stage + 1;
        phase ^= (stage == 0);
      }
    }
  } else if (warp_idx == 1) {
    const uint32_t idesc = (1u << 4) | ((BN >> 3) << 17) | ((ROWS >> 4) << 24);
    uint32_t stage = 0, phase = 0;
    for (uint32_t kb = 0; kb < num_kb; ++kb) {
      mbar_wait(&full_bar[stage], phase);
      tcgen05_fence_after_thread_sync();
      if (elect_one_sync()) {
        uint64_t desc_a = make_desc_k_major_sw128(smem_a + stage * SMEM_A_STAGE);
        uint64_t desc_b = make_desc_k_major_sw128(smem_b + stage * SMEM_B_STAGE);
#pragma unroll
        for (uint32_t u = 0; u < BK / 32; ++u) {
          const uint32_t a_off = (u / 4) * (ROWS * 128 / 16) + (u % 4) * 2;
          const uint32_t b_off = (u / 4) * (BN * 128 / 16) + (u % 4) * 2;
          umma_f8_1sm(0, desc_a + a_off, desc_b + b_off, idesc, (kb > 0 || u > 0) ? 1u : 0u);
        }
        umma_commit_1sm(&empty_bar[stage]);
        if (kb == num_kb - 1) umma_commit_1sm(tmem_full);
      }
      __syncwarp();
      stage = stage + 1 == STAGES ? 0 : stage + 1;
      phase ^= (stage == 0);
    }
  } else if (warp_idx >= 4) {
    const uint32_t ep_warp = warp_idx - 4;
    const uint32_t row = ep_warp * 32 + lane_idx;
    mbar_wait(tmem_full, 0);
    tcgen05_fence_after_thread_sync();
    // tcgen05.ld is warp-scoped: the whole warp must execute it uniformly, so
    // gate per warp and predicate only the stores.
    if (ep_warp * 32 < M) {
      const bool row_ok = row < M;
      float* out = partials + (uint64_t)pid_s * M * N + (uint64_t)row * N + n_idx;
#pragma unroll
      for (uint32_t i = 0; i < BN / 8; ++i) {
        uint32_t v[8];
        tmem_ld_32x32b_x8(i * 8, v);
        tcgen05_wait_ld();
        const uint32_t n0 = n_idx + i * 8;
        if (row_ok) {
          if (n0 + 8 <= N) {
            float4 lo = {reinterpret_cast<float&>(v[0]), reinterpret_cast<float&>(v[1]),
                         reinterpret_cast<float&>(v[2]), reinterpret_cast<float&>(v[3])};
            float4 hi = {reinterpret_cast<float&>(v[4]), reinterpret_cast<float&>(v[5]),
                         reinterpret_cast<float&>(v[6]), reinterpret_cast<float&>(v[7])};
            *reinterpret_cast<float4*>(out + i * 8) = lo;
            *reinterpret_cast<float4*>(out + i * 8 + 4) = hi;
          } else {
#pragma unroll
            for (uint32_t j = 0; j < 8; ++j)
              if (n0 + j < N) out[i * 8 + j] = reinterpret_cast<float&>(v[j]);
          }
        }
      }
    }
  }

  __syncthreads();
  if (warp_idx == 2) tmem_dealloc_1sm(0, BN >= 128 ? BN : 128);
#endif
}

void gemm_fp8_skinny(torch::Tensor x, torch::Tensor w, torch::Tensor partials, int64_t split,
                     int64_t evict_first) {
  const uint32_t M = x.size(0), K = x.size(1), N = w.size(0);
  TORCH_CHECK(K % 128 == 0 && M <= 128);
  constexpr uint32_t BN = 128, BK = 256, STAGES = 3;
  const uint32_t k_per_split = (K / split + BK - 1) / BK * BK;

  auto tmap_a = make_tmap_3d_atoms(x.data_ptr(), M, K, 128, BK / 128);
  auto tmap_b = make_tmap_3d_atoms(w.data_ptr(), N, K, BN, BK / 128);

  const uint32_t smem = STAGES * (128 * BK + BN * BK) + (2 * STAGES + 1) * 8 + 16;
  dim3 grid((N + BN - 1) / BN, split);
  auto stream = at::cuda::getCurrentCUDAStream();
  if (evict_first) {
    auto k = fp8_gemm_skinny_kernel<BN, BK, STAGES, true>;
    static bool set1 = false;
    if (!set1) { cudaFuncSetAttribute(k, cudaFuncAttributeMaxDynamicSharedMemorySize, 232448); set1 = true; }
    k<<<grid, 256, smem, stream>>>(tmap_a, tmap_b, partials.data_ptr<float>(), M, N, K, k_per_split);
  } else {
    auto k = fp8_gemm_skinny_kernel<BN, BK, STAGES, false>;
    static bool set2 = false;
    if (!set2) { cudaFuncSetAttribute(k, cudaFuncAttributeMaxDynamicSharedMemorySize, 232448); set2 = true; }
    k<<<grid, 256, smem, stream>>>(tmap_a, tmap_b, partials.data_ptr<float>(), M, N, K, k_per_split);
  }
  cudaError_t err = cudaGetLastError();
  TORCH_CHECK(err == cudaSuccess, "skinny launch failed: ", cudaGetErrorString(err));
}

PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
  m.def("gemm_fp8_2sm", &gemm_fp8_2sm, "fp8 GEMM 2SM tcgen05");
  m.def("gemm_fp8_skinny", &gemm_fp8_skinny, "fp8 skinny GEMM 1SM tcgen05");
}

"""

_HAND = None
if os.environ.get("KBH_DISABLE_HAND", "0") != "1":
    try:
        if torch.cuda.get_device_capability(0)[0] == 10:
            from torch.utils.cpp_extension import load_inline

            # tcgen05 needs the arch-specific target; the container pre-sets a
            # multi-arch TORCH_CUDA_ARCH_LIST that would break the build.
            _saved_arch = os.environ.get("TORCH_CUDA_ARCH_LIST")
            os.environ["TORCH_CUDA_ARCH_LIST"] = "10.0a"
            try:
                _HAND = load_inline(
                    name="fp8_gemm_sm100_hand",
                    cpp_sources=[],
                    cuda_sources=[_CUDA_SRC],
                    extra_cuda_cflags=["-O3", "--use_fast_math", "-std=c++17"],
                    extra_ldflags=["-lcuda"],
                    verbose=False,
                )
            finally:
                if _saved_arch is None:
                    os.environ.pop("TORCH_CUDA_ARCH_LIST", None)
                else:
                    os.environ["TORCH_CUDA_ARCH_LIST"] = _saved_arch
    except Exception:
        _HAND = None


def _hand_ok(M, N, K_pad):
    return (
        _HAND is not None
        and M >= 128
        and N % 16 == 0
        and K_pad % 128 == 0
        and torch.cuda.get_device_capability(0)[0] == 10
    )


# ==========================================================================
# Triton kernels: persistent fallback GEMM, skinny split-K, pad copy
# ==========================================================================
@triton.jit
def _gemm_persistent(
    x_ptr, w_ptr, y_ptr, scale_ptr,
    M, N, K_pad,
    BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr,
    GROUP_M: tl.constexpr, NUM_SMS: tl.constexpr, SUBTILE: tl.constexpr,
):
    start_pid = tl.program_id(0)
    num_pid_m = tl.cdiv(M, BLOCK_M)
    num_pid_n = tl.cdiv(N, BLOCK_N)
    k_tiles = tl.cdiv(K_pad, BLOCK_K)
    num_tiles = num_pid_m * num_pid_n

    x_desc = tl.make_tensor_descriptor(x_ptr, [M, K_pad], [K_pad, 1], [BLOCK_M, BLOCK_K])
    w_desc = tl.make_tensor_descriptor(w_ptr, [N, K_pad], [K_pad, 1], [BLOCK_N, BLOCK_K])
    y_desc = tl.make_tensor_descriptor(
        y_ptr, [M, N], [N, 1],
        [BLOCK_M, BLOCK_N // 2 if SUBTILE else BLOCK_N],
    )

    num_pid_in_group = GROUP_M * num_pid_n

    for tile_id in tl.range(start_pid, num_tiles, NUM_SMS, flatten=True, warp_specialize=True):
        group_id = tile_id // num_pid_in_group
        first_pid_m = group_id * GROUP_M
        group_size_m = min(num_pid_m - first_pid_m, GROUP_M)
        pid_m = first_pid_m + (tile_id % num_pid_in_group) % group_size_m
        pid_n = (tile_id % num_pid_in_group) // group_size_m

        off_m = pid_m * BLOCK_M
        off_n = pid_n * BLOCK_N

        acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32)
        for k in tl.range(0, k_tiles):
            x = x_desc.load([off_m, k * BLOCK_K])
            w = w_desc.load([off_n, k * BLOCK_K])
            acc = tl.dot(x, w.T, acc)

        offs_n = off_n + tl.arange(0, BLOCK_N)
        scale = tl.load(scale_ptr + offs_n, mask=offs_n < N, other=0.0).to(tl.float32)
        acc = acc * scale[None, :]
        if SUBTILE:
            acc0, acc1 = acc.reshape(BLOCK_M, 2, BLOCK_N // 2).permute(0, 2, 1).split()
            y_desc.store([off_m, off_n], acc0.to(tl.bfloat16))
            y_desc.store([off_m, off_n + BLOCK_N // 2], acc1.to(tl.bfloat16))
        else:
            y_desc.store([off_m, off_n], acc.to(tl.bfloat16))


@triton.jit
def _gemm_skinny(
    x_ptr, w_ptr, p_ptr,
    M, N, K,
    K_PER: tl.constexpr, BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr,
):
    pid_n = tl.program_id(0)
    pid_s = tl.program_id(1)
    x_desc = tl.make_tensor_descriptor(x_ptr, [M, K], [K, 1], [BLOCK_M, BLOCK_K])
    w_desc = tl.make_tensor_descriptor(w_ptr, [N, K], [K, 1], [BLOCK_N, BLOCK_K])
    off_n = pid_n * BLOCK_N
    k_lo = pid_s * K_PER
    acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32)
    for k in tl.range(0, K_PER // BLOCK_K, flatten=True):
        x = x_desc.load([0, k_lo + k * BLOCK_K])
        w = w_desc.load([off_n, k_lo + k * BLOCK_K])
        acc = tl.dot(x, w.T, acc)
    offs_m = tl.arange(0, BLOCK_M)
    offs_n = off_n + tl.arange(0, BLOCK_N)
    ptrs = p_ptr + pid_s.to(tl.int64) * M * N + offs_m[:, None] * N + offs_n[None, :]
    tl.store(ptrs, acc, mask=(offs_m[:, None] < M))


@triton.jit
def _skinny_reduce(p_ptr, scale_ptr, y_ptr, MN, N, S: tl.constexpr, BLOCK: tl.constexpr):
    pid = tl.program_id(0)
    offs = pid * BLOCK + tl.arange(0, BLOCK)
    mask = offs < MN
    acc = tl.zeros((BLOCK,), dtype=tl.float32)
    for s_i in tl.static_range(S):
        acc += tl.load(p_ptr + s_i * MN + offs, mask=mask, other=0.0)
    sc = tl.load(scale_ptr + offs % N, mask=mask, other=0.0)
    tl.store(y_ptr + offs, (acc * sc).to(tl.bfloat16), mask=mask)


@triton.jit
def _pad_rows_u32(src_ptr, dst_ptr, M, K, K_pad,
                  N_U32: tl.constexpr, BLOCK: tl.constexpr):
    """Copy (M,K) bytes with odd row stride K into (M,K_pad) zero-padded.

    Vectorized despite misalignment: aligned u32 pair loads + funnel shift,
    aligned u32 stores. Dst pad columns beyond the partial u32 stay untouched
    (pre-zeroed buffer)."""
    pid = tl.program_id(0)
    row = pid // tl.cdiv(N_U32, BLOCK)
    chunk = pid % tl.cdiv(N_U32, BLOCK)
    jc = chunk * BLOCK + tl.arange(0, BLOCK)
    in_row = jc < N_U32

    row_start = row * K
    sh = (row_start % 4).to(tl.uint32)
    idx = row_start // 4 + jc
    total_u32 = (M * K + 3) // 4

    lo = tl.load(src_ptr + idx, mask=in_row & (idx < total_u32), other=0,
                 eviction_policy="evict_first").to(tl.uint32, bitcast=True)
    hi = tl.load(src_ptr + idx + 1, mask=in_row & (idx + 1 < total_u32), other=0,
                 eviction_policy="evict_first").to(tl.uint32, bitcast=True)
    val = tl.where(sh == 0, lo, (lo >> (8 * sh)) | (hi << (32 - 8 * sh)))

    rem = K - jc * 4
    val = tl.where(rem >= 4, val,
                   val & ((tl.full((BLOCK,), 1, tl.uint32) << (8 * tl.maximum(rem, 0).to(tl.uint32))) - 1))

    tl.store(dst_ptr + row * (K_pad // 4) + jc, val.to(tl.int32, bitcast=True), mask=in_row)


def _pad_copy(x: torch.Tensor, xpad: torch.Tensor):
    M, K = x.shape
    K_pad = xpad.shape[1]
    n_u32 = (K + 3) // 4
    src32 = x.view(-1)[: M * K // 4 * 4].view(torch.int32)
    grid = (M * triton.cdiv(n_u32, 512),)
    _pad_rows_u32[grid](src32, xpad.view(-1).view(torch.int32), M, K, K_pad,
                        n_u32, 512, num_warps=4)


# ==========================================================================
# config selection
# ==========================================================================
# triton persistent fallback: (BM, BN, BK, GROUP_M, stages, warps, subtile)
_PERSISTENT_CFGS = {
    (4096, 4096): (128, 128, 128, 8, 6, 8, False),
    (4096, 14336): (256, 128, 128, 8, 4, 8, True),
}
_PERSISTENT_DEFAULT = (128, 128, 128, 8, 6, 8, False)
# skinny: (BM, BN, BK, SPLIT, stages, warps)
_SKINNY_CFG = (64, 128, 256, 2, 4, 4)


def _pad_k(K):
    """Padded K when K breaks TMA's 16B-stride rule: round to 128B so every
    TMA box row stays DRAM-sector aligned (16B-only alignment measurably
    loses ~25% mainloop throughput), and so the hand kernel's K%128 rule
    holds."""
    return K if K % 16 == 0 else (K + 127) // 128 * 128


class _Plan:
    __slots__ = ("launch", "graph", "y")

    def __init__(self, launch, y):
        self.launch = launch
        self.graph = None
        self.y = y


class Model(nn.Module):
    """y = ((x @ w.T) * weight_scale).to(bf16) via fp8 tensor-core MMA."""

    def __init__(self, M: int, N: int, K: int):
        super().__init__()
        self.M, self.N, self.K = M, N, K
        w = torch.empty(N, K, dtype=torch.bfloat16)
        nn.init.normal_(w, std=0.02)
        s = (w.float().abs().amax(dim=1, keepdim=True) / E4M3_MAX).clamp(min=1e-12)
        w_fp8 = (w.float() / s).to(torch.float8_e4m3fn)
        self.register_buffer("weight", w_fp8)
        self.register_buffer("weight_scale", s.squeeze(1).to(torch.float32))
        # runtime state (not in state_dict)
        self._wpad = None
        self._wpad_key = None
        self._xpad = None
        self._partials = None
        self._plans = {}
        self._graphs_ok = True

    # -- padding ----------------------------------------------------------
    def _padded_weight(self) -> torch.Tensor:
        w = self.weight
        K = w.shape[1]
        Kp = _pad_k(K)
        key = (w.data_ptr(), w._version)
        if self._wpad_key != key:
            if self._wpad is None or self._wpad.shape != (w.shape[0], Kp):
                self._wpad = torch.zeros(w.shape[0], Kp, device=w.device, dtype=w.dtype)
            _pad_copy(w, self._wpad)
            self._wpad_key = key
        return self._wpad

    # -- launchers ----------------------------------------------------------
    def _make_launch(self, x, w, y, M, N, K_pad):
        scale = self.weight_scale
        K_orig = x.shape[1]
        needs_pad = K_pad != K_orig

        if M <= 64:
            if _HAND is not None and K_pad % 128 == 0 and M <= 128:
                SPLIT = 2
                if self._partials is None or self._partials.shape != (SPLIT, M, N):
                    self._partials = torch.empty(SPLIT, M, N, device=x.device, dtype=torch.float32)
                P = self._partials
                grid2 = (triton.cdiv(M * N, 2048),)
                xp = self._xpad if needs_pad else x

                def launch():
                    if needs_pad:
                        _pad_copy(x, self._xpad)
                    _HAND.gemm_fp8_skinny(xp, w, P, SPLIT, 1)
                    _skinny_reduce[grid2](P, scale, y, M * N, N, SPLIT, 2048, num_warps=4)
                return launch
            BM, BN, BK, SPLIT, stages, warps = _SKINNY_CFG
            k_per = triton.cdiv(triton.cdiv(K_pad, SPLIT), BK) * BK
            n_split = max(1, triton.cdiv(K_pad, k_per))
            if self._partials is None or self._partials.shape != (n_split, M, N):
                self._partials = torch.empty(n_split, M, N, device=x.device, dtype=torch.float32)
            P = self._partials
            grid = (triton.cdiv(N, BN), n_split)
            grid2 = (triton.cdiv(M * N, 2048),)
            xp = self._xpad if needs_pad else x

            def launch():
                if needs_pad:
                    _pad_copy(x, self._xpad)
                _gemm_skinny[grid](xp, w, P, M, N, K_pad, k_per, BM, BN, BK,
                                   num_stages=stages, num_warps=warps)
                _skinny_reduce[grid2](P, scale, y, M * N, N, n_split, 2048, num_warps=4)
        elif _hand_ok(M, N, K_pad):
            # Balance persistent waves: with 256x256 tiles, pick the smallest
            # cluster count that keeps the same wave count as the full GPU
            # (e.g. 256 tiles -> 64 clusters x 4 exact waves beats 74 ragged).
            max_clusters = _num_sms() // 2
            tiles = ((M + 255) // 256) * ((N + 255) // 256)
            waves = -(-tiles // max_clusters)
            clusters = min(max_clusters, -(-tiles // waves))
            sms = 2 * clusters
            xp = self._xpad if needs_pad else x

            def launch():
                if needs_pad:
                    _pad_copy(x, self._xpad)
                _HAND.gemm_fp8_2sm(xp, w, scale, y, sms)
        else:
            BM, BN, BK, GM, stages, warps, subtile = _PERSISTENT_CFGS.get(
                (M, N), _PERSISTENT_DEFAULT)
            NUM_SMS = _num_sms()
            grid = (min(NUM_SMS, triton.cdiv(M, BM) * triton.cdiv(N, BN)),)
            xp = self._xpad if needs_pad else x

            def launch():
                if needs_pad:
                    _pad_copy(x, self._xpad)
                _gemm_persistent[grid](xp, w, y, scale, M, N, K_pad,
                                       BM, BN, BK, GM, NUM_SMS, subtile,
                                       num_stages=stages, num_warps=warps)
        return launch

    # -- forward ------------------------------------------------------------
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        if not x.is_contiguous():
            x = x.contiguous()
        M, K = x.shape
        N = self.weight.shape[0]
        Kp = _pad_k(K)
        needs_pad = Kp != K

        if needs_pad:
            self._padded_weight()  # refresh cache if weight mutated (checked every call)
            w = self._wpad
            if self._xpad is None or self._xpad.shape != (M, Kp):
                self._xpad = torch.zeros(M, Kp, device=x.device, dtype=x.dtype)
        else:
            w = self.weight

        key = (x.data_ptr(), M, K, x.stride(0))
        plan = self._plans.get(key)
        if plan is None:
            y = torch.empty(M, N, device=x.device, dtype=torch.bfloat16)
            launch = self._make_launch(x, w, y, M, N, Kp)
            plan = _Plan(launch, y)
            launch()  # compile + warm
            if self._graphs_ok:
                try:
                    torch.cuda.synchronize()
                    g = torch.cuda.CUDAGraph()
                    with torch.cuda.graph(g):
                        launch()
                    plan.graph = g
                except Exception:
                    self._graphs_ok = False
                    plan.graph = None
            if len(self._plans) > 64:
                self._plans.clear()
            self._plans[key] = plan
            if plan.graph is not None:
                plan.graph.replay()
            return plan.y

        if plan.graph is not None:
            plan.graph.replay()
        else:
            plan.launch()
        return plan.y


M = 4096
N = 4096
K = 4096


def get_inputs():
    x = (torch.rand(M, K) * 8 - 4).to(torch.float8_e4m3fn)
    return [x]


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

20260702_090059_claude_claude-fable-5_01_fp8_gemm