KernelBench cuda · RTX PRO 6000
GLM-5.2 Fused MoE Claude Haiku 5.5
9.47%geomean peak fraction across shapes
manually audited: clean
Haiku 5.5 wrote the GLM-5.2 MoE layer as four hand-written CUDA kernels: a one-block counting sort of the routed pairs with the shared expert scheduled as one more expert group, a grouped bf16 mma.sync GEMM for gate/up with silu(gate)*up fused into its epilogue, a second grouped GEMM for down, and a per-token reduce that applies the routing weights and adds the shared expert.
harnessclaudeagent session56mtotal wall1h 22mcheck4mbenchmark4moutput tokens30,731cost$13.99gpu-lock wait24mgpu-lock held22mregimecompute
Per-shape vs governing ceilingeach shape graded against whichever binds — bf16 compute or HBM bandwidth
shape 010.218 ms36.3%1.27 TB/s · 71% of 1.8 TB/s HBM · also 182 TFLOPS (36% of compute)
shape 110.687 ms35.0%1.22 TB/s · 68% of 1.8 TB/s HBM · also 175 TFLOPS (35% of compute)
shape 20.434 ms0.2%29.78 TB/s · 100% of 1.8 TB/s HBM · also 1 TFLOPS (0% of compute)
shape 316.979 ms43.7%219 TFLOPS · 44% of 500 TF bf16 peak · also 0.77 TB/s (43% of HBM)
shape 48.128 ms5.7%1.59 TB/s · 88% of 1.8 TB/s HBM · also 29 TFLOPS (6% of compute)
shape 58.306 ms10.9%1.56 TB/s · 87% of 1.8 TB/s HBM · also 55 TFLOPS (11% of compute)
compute-bound memory-bound · bar + right column = official fraction of the ceiling (the geomean input)
geomean(36.3% · 35.0% · 0.2% · 43.7% · 5.7% · 10.9%) = 9.5%
Kernel source (redacted)
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
_CUDA_SRC = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAGuard.h>
#include <cuda_runtime.h>
#include <cuda_bf16.h>
#include <stdint.h>
namespace {
constexpr int BM = 128;
constexpr int BK = 64;
constexpr int CPR = BK / 8;
constexpr int BN1 = 64;
constexpr int BN2 = 128;
constexpr int STAGES = 3;
constexpr int THREADS = 256;
constexpr int ROUTE_THREADS = 1024;
constexpr int ROW_BYTES = BK * 2;
constexpr int STAGE_BYTES = (BM + 2 * BN1) * ROW_BYTES;
constexpr int MAX_GROUPS = 320;
__device__ __forceinline__ uint32_t smem_addr(const void* p) {
return static_cast<uint32_t>(__cvta_generic_to_shared(p));
}
__device__ __forceinline__ int swz(int row, int chunk) {
return (chunk ^ (row & 7)) << 4;
}
__device__ __forceinline__ void cp_async16(void* smem, const void* gmem, bool valid) {
const int src_bytes = valid ? 16 : 0;
asm volatile("cp.async.cg.shared.global [%0], [%1], 16, %2;\n"
:: "r"(smem_addr(smem)), "l"(reinterpret_cast<uint64_t>(gmem)), "r"(src_bytes));
}
__device__ __forceinline__ void cp_async_commit() {
asm volatile("cp.async.commit_group;\n" ::);
}
template <int N>
__device__ __forceinline__ void cp_async_wait() {
asm volatile("cp.async.wait_group %0;\n" :: "n"(N));
}
__device__ __forceinline__ void ldmatrix_x4(uint32_t* r, const void* smem) {
asm volatile("ldmatrix.sync.aligned.m8n8.x4.shared.b16 {%0,%1,%2,%3}, [%4];\n"
: "=r"(r[0]), "=r"(r[1]), "=r"(r[2]), "=r"(r[3])
: "r"(smem_addr(smem)));
}
__device__ __forceinline__ void mma_bf16(float* d, const uint32_t* a, uint32_t b0, uint32_t b1) {
asm volatile(
"mma.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32 "
"{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%0,%1,%2,%3};\n"
: "+f"(d[0]), "+f"(d[1]), "+f"(d[2]), "+f"(d[3])
: "r"(a[0]), "r"(a[1]), "r"(a[2]), "r"(a[3]), "r"(b0), "r"(b1));
}
__global__ void routing_kernel(const int64_t* __restrict__ ids, int T, int topk, int E, int NS,
int* __restrict__ gcnt, int* __restrict__ goff,
int* __restrict__ tile_group, int* __restrict__ tile_row0,
int* __restrict__ ntiles, int* __restrict__ row_token,
int* __restrict__ row_slot) {
__shared__ int s_cnt[MAX_GROUPS];
__shared__ int s_cur[MAX_GROUPS];
__shared__ int s_off[MAX_GROUPS + 1];
__shared__ int s_toff[MAX_GROUPS + 1];
const int tid = threadIdx.x;
const int NG = E + NS;
const int P = T * topk;
for (int g = tid; g < NG; g += blockDim.x) {
s_cnt[g] = 0;
s_cur[g] = 0;
}
__syncthreads();
for (int p = tid; p < P; p += blockDim.x) atomicAdd(&s_cnt[ids[p]], 1);
__syncthreads();
if (tid == 0) {
for (int s = 0; s < NS; ++s) s_cnt[E + s] = T;
int off = 0, toff = 0;
for (int g = 0; g < NG; ++g) {
s_off[g] = off;
s_toff[g] = toff;
off += s_cnt[g];
toff += (s_cnt[g] + BM - 1) / BM;
}
ntiles[0] = toff;
}
__syncthreads();
for (int g = tid; g < NG; g += blockDim.x) {
gcnt[g] = s_cnt[g];
goff[g] = s_off[g];
const int nt = (s_cnt[g] + BM - 1) / BM;
for (int j = 0; j < nt; ++j) {
tile_group[s_toff[g] + j] = g;
tile_row0[s_toff[g] + j] = j * BM;
}
}
for (int p = tid; p < P; p += blockDim.x) {
const int g = static_cast<int>(ids[p]);
const int r = s_off[g] + atomicAdd(&s_cur[g], 1);
row_token[r] = p / topk;
row_slot[r] = p;
}
for (int i = tid; i < NS * T; i += blockDim.x) {
const int s = i / T;
const int t = i - s * T;
const int r = s_off[E + s] + t;
row_token[r] = t;
row_slot[r] = P + i;
}
}
__global__ void __launch_bounds__(THREADS, 1)
moe_gemm1_kernel(const __nv_bfloat16* __restrict__ x, const __nv_bfloat16* __restrict__ w1r,
const __nv_bfloat16* __restrict__ w1s, __nv_bfloat16* __restrict__ hbuf,
const int* __restrict__ gcnt, const int* __restrict__ goff,
const int* __restrict__ tile_group, const int* __restrict__ tile_row0,
const int* __restrict__ ntiles, const int* __restrict__ row_token,
int E, int H, int I, int ntn) {
extern __shared__ __align__(16) unsigned char smem[];
__shared__ int s_tok[BM];
const int m = blockIdx.x / ntn;
if (m >= ntiles[0]) return;
const int nt = blockIdx.x - m * ntn;
const int g = tile_group[m];
const int row0 = tile_row0[m];
const int cnt = gcnt[g];
const int gbase = goff[g];
const int tid = threadIdx.x;
const int lane = tid & 31;
const int wm = (tid >> 5) >> 1;
const int wn = (tid >> 5) & 1;
if (tid < BM) {
const int r = row0 + tid;
s_tok[tid] = r < cnt ? row_token[gbase + r] : -1;
}
__syncthreads();
const size_t wstride = (size_t)2 * I * H;
const __nv_bfloat16* W = g < E ? w1r + (size_t)g * wstride : w1s + (size_t)(g - E) * wstride;
const int n0 = nt * BN1;
auto load_stage = [&](int stage, int kt) {
unsigned char* sb = smem + stage * STAGE_BYTES;
const int k0 = kt * BK;
for (int q = tid; q < BM * CPR; q += THREADS) {
const int row = q / CPR, c = q % CPR;
const int tok = s_tok[row];
const __nv_bfloat16* src = tok >= 0 ? x + (size_t)tok * H + k0 + c * 8 : x;
cp_async16(sb + row * ROW_BYTES + swz(row, c), src, tok >= 0);
}
for (int q = tid; q < BN1 * CPR; q += THREADS) {
const int row = q / CPR, c = q % CPR;
cp_async16(sb + BM * ROW_BYTES + row * ROW_BYTES + swz(row, c),
W + (size_t)(n0 + row) * H + k0 + c * 8, true);
cp_async16(sb + (BM + BN1) * ROW_BYTES + row * ROW_BYTES + swz(row, c),
W + (size_t)(I + n0 + row) * H + k0 + c * 8, true);
}
};
float accg[2][4][4], accu[2][4][4];
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 4; ++j)
for (int k = 0; k < 4; ++k) accg[i][j][k] = accu[i][j][k] = 0.f;
const int KT = H / BK;
for (int s = 0; s < STAGES - 1; ++s) {
if (s < KT) load_stage(s, s);
cp_async_commit();
}
for (int kt = 0; kt < KT; ++kt) {
cp_async_wait<STAGES - 2>();
__syncthreads();
const int nk = kt + STAGES - 1;
if (nk < KT) load_stage(nk % STAGES, nk);
cp_async_commit();
const unsigned char* sA = smem + (kt % STAGES) * STAGE_BYTES;
const unsigned char* sG = sA + BM * ROW_BYTES;
const unsigned char* sU = sA + (BM + BN1) * ROW_BYTES;
#pragma unroll
for (int ks = 0; ks < BK / 16; ++ks) {
uint32_t af[2][4];
#pragma unroll
for (int mi = 0; mi < 2; ++mi) {
const int row = wm * 32 + mi * 16 + (lane & 15);
ldmatrix_x4(af[mi], sA + row * ROW_BYTES + swz(row, ks * 2 + (lane >> 4)));
}
uint32_t bg[4][2], bu[4][2];
#pragma unroll
for (int nj = 0; nj < 2; ++nj) {
const int n = wn * 32 + nj * 16 + (lane & 7) + ((lane >> 4) << 3);
const int off = swz(n, ks * 2 + ((lane >> 3) & 1));
uint32_t r[4];
ldmatrix_x4(r, sG + n * ROW_BYTES + off);
bg[2 * nj][0] = r[0]; bg[2 * nj][1] = r[1];
bg[2 * nj + 1][0] = r[2]; bg[2 * nj + 1][1] = r[3];
ldmatrix_x4(r, sU + n * ROW_BYTES + off);
bu[2 * nj][0] = r[0]; bu[2 * nj][1] = r[1];
bu[2 * nj + 1][0] = r[2]; bu[2 * nj + 1][1] = r[3];
}
#pragma unroll
for (int mi = 0; mi < 2; ++mi)
#pragma unroll
for (int ni = 0; ni < 4; ++ni) {
mma_bf16(accg[mi][ni], af[mi], bg[ni][0], bg[ni][1]);
mma_bf16(accu[mi][ni], af[mi], bu[ni][0], bu[ni][1]);
}
}
}
const int gl = lane >> 2, tq = (lane & 3) * 2;
for (int mi = 0; mi < 2; ++mi)
for (int ni = 0; ni < 4; ++ni)
for (int hf = 0; hf < 2; ++hf) {
const int row = wm * 32 + mi * 16 + gl + hf * 8;
if (row0 + row >= cnt) continue;
const int col = n0 + wn * 32 + ni * 8 + tq;
const float g0 = accg[mi][ni][2 * hf], g1 = accg[mi][ni][2 * hf + 1];
const float u0 = accu[mi][ni][2 * hf], u1 = accu[mi][ni][2 * hf + 1];
const float h0 = g0 / (1.f + expf(-g0)) * u0;
const float h1 = g1 / (1.f + expf(-g1)) * u1;
*reinterpret_cast<__nv_bfloat162*>(hbuf + (size_t)(gbase + row0 + row) * I + col) =
__floats2bfloat162_rn(h0, h1);
}
}
__global__ void __launch_bounds__(THREADS, 1)
moe_gemm2_kernel(const __nv_bfloat16* __restrict__ hbuf, const __nv_bfloat16* __restrict__ w2r,
const __nv_bfloat16* __restrict__ w2s, __nv_bfloat16* __restrict__ ybuf,
const int* __restrict__ gcnt, const int* __restrict__ goff,
const int* __restrict__ tile_group, const int* __restrict__ tile_row0,
const int* __restrict__ ntiles, const int* __restrict__ row_slot,
int E, int H, int I, int ntn) {
extern __shared__ __align__(16) unsigned char smem[];
const int m = blockIdx.x / ntn;
if (m >= ntiles[0]) return;
const int nt = blockIdx.x - m * ntn;
const int g = tile_group[m];
const int row0 = tile_row0[m];
const int cnt = gcnt[g];
const int gbase = goff[g];
const int tid = threadIdx.x;
const int lane = tid & 31;
const int wm = (tid >> 5) >> 1;
const int wn = (tid >> 5) & 1;
const size_t wstride = (size_t)H * I;
const __nv_bfloat16* W = g < E ? w2r + (size_t)g * wstride : w2s + (size_t)(g - E) * wstride;
const int n0 = nt * BN2;
auto load_stage = [&](int stage, int kt) {
unsigned char* sb = smem + stage * STAGE_BYTES;
const int k0 = kt * BK;
for (int q = tid; q < BM * CPR; q += THREADS) {
const int row = q / CPR, c = q % CPR;
const bool valid = row0 + row < cnt;
const __nv_bfloat16* src =
valid ? hbuf + (size_t)(gbase + row0 + row) * I + k0 + c * 8 : hbuf;
cp_async16(sb + row * ROW_BYTES + swz(row, c), src, valid);
}
for (int q = tid; q < BN2 * CPR; q += THREADS) {
const int row = q / CPR, c = q % CPR;
cp_async16(sb + BM * ROW_BYTES + row * ROW_BYTES + swz(row, c),
W + (size_t)(n0 + row) * I + k0 + c * 8, true);
}
};
float acc[2][8][4];
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 8; ++j)
for (int k = 0; k < 4; ++k) acc[i][j][k] = 0.f;
const int KT = I / BK;
for (int s = 0; s < STAGES - 1; ++s) {
if (s < KT) load_stage(s, s);
cp_async_commit();
}
for (int kt = 0; kt < KT; ++kt) {
cp_async_wait<STAGES - 2>();
__syncthreads();
const int nk = kt + STAGES - 1;
if (nk < KT) load_stage(nk % STAGES, nk);
cp_async_commit();
const unsigned char* sA = smem + (kt % STAGES) * STAGE_BYTES;
const unsigned char* sB = sA + BM * ROW_BYTES;
#pragma unroll
for (int ks = 0; ks < BK / 16; ++ks) {
uint32_t af[2][4];
#pragma unroll
for (int mi = 0; mi < 2; ++mi) {
const int row = wm * 32 + mi * 16 + (lane & 15);
ldmatrix_x4(af[mi], sA + row * ROW_BYTES + swz(row, ks * 2 + (lane >> 4)));
}
uint32_t bf[8][2];
#pragma unroll
for (int nj = 0; nj < 4; ++nj) {
const int n = wn * 64 + nj * 16 + (lane & 7) + ((lane >> 4) << 3);
uint32_t r[4];
ldmatrix_x4(r, sB + n * ROW_BYTES + swz(n, ks * 2 + ((lane >> 3) & 1)));
bf[2 * nj][0] = r[0]; bf[2 * nj][1] = r[1];
bf[2 * nj + 1][0] = r[2]; bf[2 * nj + 1][1] = r[3];
}
#pragma unroll
for (int mi = 0; mi < 2; ++mi)
#pragma unroll
for (int ni = 0; ni < 8; ++ni) mma_bf16(acc[mi][ni], af[mi], bf[ni][0], bf[ni][1]);
}
}
const int gl = lane >> 2, tq = (lane & 3) * 2;
for (int mi = 0; mi < 2; ++mi)
for (int ni = 0; ni < 8; ++ni)
for (int hf = 0; hf < 2; ++hf) {
const int row = wm * 32 + mi * 16 + gl + hf * 8;
if (row0 + row >= cnt) continue;
const int slot = row_slot[gbase + row0 + row];
const int col = n0 + wn * 64 + ni * 8 + tq;
*reinterpret_cast<__nv_bfloat162*>(ybuf + (size_t)slot * H + col) =
__floats2bfloat162_rn(acc[mi][ni][2 * hf], acc[mi][ni][2 * hf + 1]);
}
}
__device__ __forceinline__ void accum8(float* acc, const uint4& v, float w) {
const __nv_bfloat162* p = reinterpret_cast<const __nv_bfloat162*>(&v);
#pragma unroll
for (int i = 0; i < 4; ++i) {
const float2 f = __bfloat1622float2(p[i]);
acc[2 * i] += w * f.x;
acc[2 * i + 1] += w * f.y;
}
}
__global__ void moe_reduce_kernel(const __nv_bfloat16* __restrict__ ybuf,
const __nv_bfloat16* __restrict__ wts,
__nv_bfloat16* __restrict__ out, int T, int H, int topk, int NS) {
const int t = blockIdx.x;
const int h = threadIdx.x * 8;
float acc[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
for (int k = 0; k < topk; ++k) {
const int slot = t * topk + k;
const uint4 v = *reinterpret_cast<const uint4*>(ybuf + (size_t)slot * H + h);
accum8(acc, v, __bfloat162float(wts[slot]));
}
for (int s = 0; s < NS; ++s) {
const int slot = T * topk + s * T + t;
const uint4 v = *reinterpret_cast<const uint4*>(ybuf + (size_t)slot * H + h);
accum8(acc, v, 1.f);
}
uint4 o;
__nv_bfloat162* po = reinterpret_cast<__nv_bfloat162*>(&o);
#pragma unroll
for (int i = 0; i < 4; ++i) po[i] = __floats2bfloat162_rn(acc[2 * i], acc[2 * i + 1]);
*reinterpret_cast<uint4*>(out + (size_t)t * H + h) = o;
}
} // namespace
torch::Tensor moe_forward(torch::Tensor x, torch::Tensor ids, torch::Tensor wts,
torch::Tensor w1r, torch::Tensor w2r, torch::Tensor w1s,
torch::Tensor w2s) {
const c10::cuda::CUDAGuard guard(x.device());
const int T = x.size(0), H = x.size(1);
const int topk = ids.size(1);
const int E = w1r.size(0), I = w2r.size(2), NS = w1s.size(0);
TORCH_CHECK(H % BN2 == 0 && H % BK == 0 && H / 8 <= 1024, "H must be a multiple of 128");
TORCH_CHECK(I % BN1 == 0 && I % BK == 0, "I must be a multiple of 64");
TORCH_CHECK(E + NS <= MAX_GROUPS, "too many expert groups");
const int NG = E + NS;
const int P = T * topk;
const int R = P + NS * T;
const int maxtiles = P / BM + E + NS * ((T + BM - 1) / BM);
const int ntn1 = I / BN1, ntn2 = H / BN2;
const auto i32 = x.options().dtype(torch::kInt32);
auto gcnt = torch::empty({NG}, i32);
auto goff = torch::empty({NG}, i32);
auto tile_group = torch::empty({maxtiles}, i32);
auto tile_row0 = torch::empty({maxtiles}, i32);
auto ntiles = torch::empty({1}, i32);
auto [REDACTED credential assignment]}, i32);
auto row_slot = torch::empty({R}, i32);
auto hbuf = torch::empty({R, I}, x.options());
auto ybuf = torch::empty({R, H}, x.options());
auto out = torch::empty({T, H}, x.options());
auto stream = at::cuda::getCurrentCUDAStream().stream();
routing_kernel<<<1, ROUTE_THREADS, 0, stream>>>(
ids.data_ptr<int64_t>(), T, topk, E, NS, gcnt.data_ptr<int>(), goff.data_ptr<int>(),
tile_group.data_ptr<int>(), tile_row0.data_ptr<int>(), ntiles.data_ptr<int>(),
row_token.data_ptr<int>(), row_slot.data_ptr<int>());
static bool smem_attr_set = false;
if (!smem_attr_set) {
cudaFuncSetAttribute(moe_gemm1_kernel, cudaFuncAttributeMaxDynamicSharedMemorySize,
STAGES * STAGE_BYTES);
cudaFuncSetAttribute(moe_gemm2_kernel, cudaFuncAttributeMaxDynamicSharedMemorySize,
STAGES * STAGE_BYTES);
smem_attr_set = true;
}
moe_gemm1_kernel<<<maxtiles * ntn1, THREADS, STAGES * STAGE_BYTES, stream>>>(
reinterpret_cast<const __nv_bfloat16*>(x.data_ptr()),
reinterpret_cast<const __nv_bfloat16*>(w1r.data_ptr()),
reinterpret_cast<const __nv_bfloat16*>(w1s.data_ptr()),
reinterpret_cast<__nv_bfloat16*>(hbuf.data_ptr()), gcnt.data_ptr<int>(), goff.data_ptr<int>(),
tile_group.data_ptr<int>(), tile_row0.data_ptr<int>(), ntiles.data_ptr<int>(),
row_token.data_ptr<int>(), E, H, I, ntn1);
moe_gemm2_kernel<<<maxtiles * ntn2, THREADS, STAGES * STAGE_BYTES, stream>>>(
reinterpret_cast<const __nv_bfloat16*>(hbuf.data_ptr()),
reinterpret_cast<const __nv_bfloat16*>(w2r.data_ptr()),
reinterpret_cast<const __nv_bfloat16*>(w2s.data_ptr()),
reinterpret_cast<__nv_bfloat16*>(ybuf.data_ptr()), gcnt.data_ptr<int>(), goff.data_ptr<int>(),
tile_group.data_ptr<int>(), tile_row0.data_ptr<int>(), ntiles.data_ptr<int>(),
row_slot.data_ptr<int>(), E, H, I, ntn2);
moe_reduce_kernel<<<T, H / 8, 0, stream>>>(
reinterpret_cast<const __nv_bfloat16*>(ybuf.data_ptr()),
reinterpret_cast<const __nv_bfloat16*>(wts.data_ptr()),
reinterpret_cast<__nv_bfloat16*>(out.data_ptr()), T, H, topk, NS);
return out;
}
"""
_CPP_SRC = (
"torch::Tensor moe_forward(torch::Tensor x, torch::Tensor ids, torch::Tensor wts, "
"torch::Tensor w1r, torch::Tensor w2r, torch::Tensor w1s, torch::Tensor w2s);"
)
_ext = load_inline(
name="glm52_moe_bf16",
cpp_sources=_CPP_SRC,
cuda_sources=_CUDA_SRC,
functions=["moe_forward"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3", "-arch=sm_120", "-lineinfo"],
verbose=False,
)
class Model(nn.Module):
def __init__(self, T, E, top_k, n_shared, H, I):
super().__init__()
self.T, self.E, self.top_k = T, E, top_k
self.n_shared, self.H, self.I = n_shared, H, I
self.w1_routed = nn.Parameter(torch.empty(E, 2 * I, H, dtype=torch.bfloat16, device="cuda"))
self.w2_routed = nn.Parameter(torch.empty(E, H, I, dtype=torch.bfloat16, device="cuda"))
self.w1_shared = nn.Parameter(
torch.empty(n_shared, 2 * I, H, dtype=torch.bfloat16, device="cuda")
)
self.w2_shared = nn.Parameter(torch.empty(n_shared, H, I, dtype=torch.bfloat16, device="cuda"))
for p in self.parameters():
nn.init.normal_(p, std=0.02)
def forward(
self,
x: torch.Tensor,
expert_ids: torch.Tensor,
expert_weights: torch.Tensor,
) -> torch.Tensor:
return _ext.moe_forward(
x.contiguous(),
expert_ids.contiguous(),
expert_weights.contiguous(),
self.w1_routed,
self.w2_routed,
self.w1_shared,
self.w2_shared,
)
20261007_121157_claude_claude-haiku-5-5_01_glm52_fused_moe