KernelBench cuda · RTX PRO 6000
MegaQwen Decode Claude Fable 5
manually audited: clean
Genuine cooperative-groups CUDA megakernel for the 4-layer Qwen3-0.6B decode block: one cudaLaunchCooperativeKernel runs an entire decode_steps call, 5 stages per layer separated by grid.sync() (20 grid barriers per step, zero inter-stage launch overhead). Stages: input-mix + RMSNorm + QKV GEMV; Q/K head-RMSNorm + RoPE + KV append + 18-split flash-decode GQA attention; split-softmax combine + O GEMV + residual; post-RMSNorm + gate/up GEMV + SiLU; down GEMV + residual. Two template instantiations (small-ctx one-token-per-warp vs big-ctx four-tokens-per-warp with 8-lane groups) picked at launch by position >= 4096. Inline PTX prefetch.global.L2 pipelines the next stage's weight rows; L2 persisting access policy pins the 126 MB weight buffer. No Triton, no DSLs, no forbidden ops, no reference import, no output caching. Rebench (clean sequential isolated re-grade on B200) PASS, geomean peak_fraction 0.0778; result.json carries the same rescue_sequential_isolated numbers, so original and rebench agree.
Kernel source (redacted)
"""MegaQwen-style Qwen3-0.6B multi-layer decode — CUDA cooperative megakernel.
Improves on Infatoshi/MegaQwen's cooperative-megakernel idea (sm_86) for the
Blackwell-class GPU this box actually has (arch detected at build time).
Design:
One cooperative kernel launch runs an ENTIRE decode_steps call:
for step { for layer { 5 stages separated by grid.sync() } } —
20 grid barriers per decode step (~1.2us each measured on this GPU),
zero per-stage kernel-launch overhead. Stages per layer:
S1 input mix (step start) + RMSNorm (redundant per block) + QKV GEMV
S2 Q/K head-RMSNorm + RoPE + KV append (prep split across 4 warps),
flash-decode GQA attention (8 kv-head groups x 18 ctx splits; the
current token is emitted by the prep warps as a 19th softmax partial)
S3 split-softmax combine (redundant per block) + O GEMV + residual
S4 post RMSNorm (redundant) + gate/up GEMV + SiLU*up
S5 down GEMV + residual -> bf16 hidden
Each GEMV stage's tail issues prefetch.global.L2 for the next stage's
weight rows.
TWO kernel instantiations (template<bool BIG>) exist because 512 threads x
1 CTA/SM caps registers at 128/thread, and ptxas otherwise serializes the
attention loop's global loads (measured 1.7 TB/s vs ~5 TB/s):
- small-ctx path: one token per warp iteration (full-warp reduces)
- big-ctx path (positions >= 4096): FOUR tokens per warp iteration in
8-lane groups (3-stage quarter-warp reduces, per-group online-softmax
state, xor-8/16 merge), double-buffered 4-row prefetch.
Host picks the kernel per launch; prefill/decode chunk at the threshold.
KV cache layout is internal to this solution (check.py only compares
last_hidden): one interleaved bf16 tensor per layer of shape
[8 kv-heads, max_seq, 2 (K|V), 128], so the attention scan streams one
contiguous 512B row per (head, token) (~6.5 TB/s pattern ceiling measured).
Numerics mirror reference.py: everything fp32 inside a block; bf16
rounding exactly where the reference rounds (input mix, KV store, block
output). RoPE cos/sin tables are precomputed with the same torch ops as
the reference so they match bitwise. The CPU-side torch.Generator randn
protocol is reproduced exactly (batched randn is bitwise-identical to
the reference's per-step randn calls; verified). Prefill (untimed) runs
the same kernel from position 0 with the seed+1 stream.
"""
from __future__ import annotations
import math
import os
os.environ.setdefault("CUDA_HOME", "/usr/local/cuda-12.8")
import torch
import torch.nn as nn
OP_TYPE = "megaqwen_decode"
SUPPORTED_PRECISIONS = ["bf16"]
HIDDEN = 1024
INTERMEDIATE = 3072
NUM_Q = 16
NUM_KV = 8
HEAD_DIM = 128
NUM_LAYERS = 4
EPS = 1e-6
BIG_THRESH = int(os.environ.get("MQ_BIG_THRESH", "4096"))
LAYER_ELEMS = 15_728_640 # qkv 4096*1024 + o 1024*2048 + gu 3072*2048 + dn 1024*3072
NORMS_PER_LAYER = 2304
SPLITS = 18
PARTIAL_STRIDE = 132
_CUDA_SRC = r"""
#include <cuda_runtime.h>
#include <cuda_bf16.h>
#include <cooperative_groups.h>
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <vector>
namespace cg = cooperative_groups;
using bf16 = __nv_bfloat16;
#define H 1024
#define I3 3072
#define NQ 16
#define NKV 8
#define HD 128
#define QKV_ROWS 4096
#define SPLITS 18
#define ATT_BLOCKS (NKV * SPLITS)
#define NTHR 512
#define NWARP 16
#define LAYER_ELEMS 15728640L
#define OFF_O 4194304L
#define OFF_GU 6291456L
#define OFF_DN 12582912L
#define NORMS_PER_LAYER 2304
#define PSTRIDE 132
#define NSPLIT (SPLITS + 1) // 18 ctx splits + current-token partial
#define EPS 1e-6f
#define NEG_BIG (-1e30f)
#define SCALE 0.088388347648318447f
__device__ __forceinline__ float bf2f(bf16 v) { return __bfloat162float(v); }
#ifndef MQ_PF
#define MQ_PF 1
#endif
__device__ __forceinline__ void l2_prefetch(const void* ptr) {
#if MQ_PF
asm volatile("prefetch.global.L2 [%0];" :: "l"(ptr));
#endif
}
// Two-plane float4 smem layout: float4 #f lives at slot (f>>1) in plane (f&1).
// Lane-consecutive readers then hit consecutive 16B slots -> conflict-free.
__device__ __forceinline__ float* elem_ptr(float* base, int half4, int e) {
int f = e >> 2;
int slot = (f & 1) ? (half4 + (f >> 1)) : (f >> 1);
return base + slot * 4 + (e & 3);
}
struct Params {
const bf16* __restrict__ W;
const float* __restrict__ norms;
bf16* kv[8];
const float* __restrict__ cos_tab;
const float* __restrict__ sin_tab;
const bf16* __restrict__ rand_seq;
bf16* h_io;
bf16* x_buf;
float* qkv_raw;
float* partials;
float* h_attn;
float* act;
long max_seq;
int start_pos;
int n_steps;
int num_layers;
int total_warps;
unsigned long long* dbg; // optional per-stage cycle accumulators [16]
};
#ifndef MQ_DBG
#define MQ_DBG 0
#endif
#if MQ_DBG
#define DBG_MARK(slot) \
if (p.dbg && bid == 0 && tid == 0) { \
unsigned long long now = clock64(); \
atomicAdd(&p.dbg[slot], now - dbg_t); \
dbg_t = now; \
}
#else
#define DBG_MARK(slot)
#endif
struct SmemAttn {
float q[2][HD];
float kcur[HD];
float vcur[HD];
float wm[NWARP][2];
float wl[NWARP][2];
float wacc[2][NWARP][HD];
};
struct Smem {
float xhat[H];
float red[NWARP];
float cw[NQ][NSPLIT];
union {
SmemAttn attn;
float attn_vec[NQ * HD];
float act_s[I3];
} u;
};
__device__ __forceinline__ float warp_sum(float v) {
#pragma unroll
for (int o = 16; o; o >>= 1) v += __shfl_xor_sync(0xffffffffu, v, o);
return v;
}
__device__ float block_sum(float v, Smem* s) {
v = warp_sum(v);
int w = threadIdx.x >> 5, lane = threadIdx.x & 31;
if (lane == 0) s->red[w] = v;
__syncthreads();
if (w == 0) {
float x = (lane < NWARP) ? s->red[lane] : 0.f;
x = warp_sum(x);
if (lane == 0) s->red[0] = x;
}
__syncthreads();
return s->red[0];
}
// ---------- S1: input mix + RMSNorm + QKV GEMV ----------
__device__ __noinline__ void stage1(const Params& p, Smem& s,
const bf16* __restrict__ Wl,
const float* __restrict__ nl,
int l, int step) {
const int bid = blockIdx.x, tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
float sq = 0.f;
for (int e = tid; e < H; e += NTHR) {
float xv;
if (l == 0) {
float r = bf2f(p.rand_seq[(long)step * H + e]);
float hv = bf2f(p.h_io[e]);
bf16 xb = __float2bfloat16(0.5f * r + 0.5f * hv);
xv = bf2f(xb);
if (bid == 0) p.x_buf[e] = xb;
} else {
xv = bf2f(p.h_io[e]);
}
*elem_ptr(s.xhat, 128, e) = xv;
sq += xv * xv;
}
float tot = block_sum(sq, &s);
float rms = rsqrtf(tot * (1.f / H) + EPS);
for (int e = tid; e < H; e += NTHR) {
float* q = elem_ptr(s.xhat, 128, e);
*q = *q * rms * nl[e];
}
__syncthreads();
const float4* xt = reinterpret_cast<const float4*>(s.xhat);
for (int pr = warp * gridDim.x + bid; pr < QKV_ROWS / 2; pr += p.total_warps) {
const float4* w0 = reinterpret_cast<const float4*>(Wl + (long)(2 * pr) * H);
const float4* w1 = reinterpret_cast<const float4*>(Wl + (long)(2 * pr + 1) * H);
float4 va[4], vb[4];
#pragma unroll
for (int it = 0; it < 4; ++it) {
va[it] = w0[it * 32 + lane];
vb[it] = w1[it * 32 + lane];
}
float a0 = 0.f, a1 = 0.f;
#pragma unroll
for (int it = 0; it < 4; ++it) {
const bf16* pa = reinterpret_cast<const bf16*>(&va[it]);
const bf16* pb = reinterpret_cast<const bf16*>(&vb[it]);
float4 x0 = xt[it * 32 + lane];
float4 x1 = xt[128 + it * 32 + lane];
const float* xp0 = reinterpret_cast<const float*>(&x0);
const float* xp1 = reinterpret_cast<const float*>(&x1);
#pragma unroll
for (int j = 0; j < 4; ++j) {
a0 += bf2f(pa[j]) * xp0[j] + bf2f(pa[4 + j]) * xp1[j];
a1 += bf2f(pb[j]) * xp0[j] + bf2f(pb[4 + j]) * xp1[j];
}
}
#pragma unroll
for (int o = 16; o; o >>= 1) {
a0 += __shfl_xor_sync(0xffffffffu, a0, o);
a1 += __shfl_xor_sync(0xffffffffu, a1, o);
}
if (lane == 0) {
p.qkv_raw[2 * pr] = a0;
p.qkv_raw[2 * pr + 1] = a1;
}
}
const bf16* Wo_pf = Wl + OFF_O;
for (int r = warp * gridDim.x + bid; r < H; r += p.total_warps)
l2_prefetch(reinterpret_cast<const char*>(Wo_pf + (long)r * 2048) + lane * 128);
}
// ---------- S2 prep: q/k head-RMSNorm + RoPE + KV append (warp 0) ----------
__device__ __noinline__ void stage2_prep_body(const Params& p, Smem& s,
const float* __restrict__ nl,
int l, int pos) {
const int bid = blockIdx.x, tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
if (bid >= ATT_BLOCKS) return;
const int g = bid / SPLITS, sp = bid % SPLITS;
// parallel prep: warps 0,1 = q heads; warp 2 = k; warp 3 = v
if (warp < 2) {
const float* qn = nl + 2048;
const float* ct = p.cos_tab + (long)pos * 64;
const float* st = p.sin_tab + (long)pos * 64;
float c0 = ct[lane], s0r = st[lane], c1 = ct[lane + 32], s1r = st[lane + 32];
const int h2 = warp;
const float* src = p.qkv_raw + (2 * g + h2) * HD;
float v0 = src[lane], v1 = src[lane + 32], v2 = src[lane + 64], v3 = src[lane + 96];
float ssum = warp_sum(v0 * v0 + v1 * v1 + v2 * v2 + v3 * v3);
float rms = rsqrtf(ssum * (1.f / HD) + EPS);
float n0 = v0 * rms * qn[lane], n1 = v1 * rms * qn[lane + 32];
float n2 = v2 * rms * qn[lane + 64], n3 = v3 * rms * qn[lane + 96];
s.u.attn.q[h2][lane] = n0 * c0 - n2 * s0r;
s.u.attn.q[h2][lane + 32] = n1 * c1 - n3 * s1r;
s.u.attn.q[h2][lane + 64] = n0 * s0r + n2 * c0;
s.u.attn.q[h2][lane + 96] = n1 * s1r + n3 * c1;
} else if (warp == 2) {
const float* kn = nl + 2048 + HD;
const float* ct = p.cos_tab + (long)pos * 64;
const float* st = p.sin_tab + (long)pos * 64;
float c0 = ct[lane], s0r = st[lane], c1 = ct[lane + 32], s1r = st[lane + 32];
const float* src = p.qkv_raw + 2048 + g * HD;
float v0 = src[lane], v1 = src[lane + 32], v2 = src[lane + 64], v3 = src[lane + 96];
float ssum = warp_sum(v0 * v0 + v1 * v1 + v2 * v2 + v3 * v3);
float rms = rsqrtf(ssum * (1.f / HD) + EPS);
float n0 = v0 * rms * kn[lane], n1 = v1 * rms * kn[lane + 32];
float n2 = v2 * rms * kn[lane + 64], n3 = v3 * rms * kn[lane + 96];
bf16 b0 = __float2bfloat16(n0 * c0 - n2 * s0r);
bf16 b1 = __float2bfloat16(n1 * c1 - n3 * s1r);
bf16 b2 = __float2bfloat16(n0 * s0r + n2 * c0);
bf16 b3 = __float2bfloat16(n1 * s1r + n3 * c1);
s.u.attn.kcur[lane] = bf2f(b0);
s.u.attn.kcur[lane + 32] = bf2f(b1);
s.u.attn.kcur[lane + 64] = bf2f(b2);
s.u.attn.kcur[lane + 96] = bf2f(b3);
if (sp == 0) {
bf16* cache = p.kv[l] + ((long)g * p.max_seq + pos) * 256;
cache[lane] = b0; cache[lane + 32] = b1;
cache[lane + 64] = b2; cache[lane + 96] = b3;
}
} else if (warp == 3) {
const float* vs = p.qkv_raw + 3072 + g * HD;
bf16 y0 = __float2bfloat16(vs[lane]);
bf16 y1 = __float2bfloat16(vs[lane + 32]);
bf16 y2 = __float2bfloat16(vs[lane + 64]);
bf16 y3 = __float2bfloat16(vs[lane + 96]);
s.u.attn.vcur[lane] = bf2f(y0);
s.u.attn.vcur[lane + 32] = bf2f(y1);
s.u.attn.vcur[lane + 64] = bf2f(y2);
s.u.attn.vcur[lane + 96] = bf2f(y3);
if (sp == 0) {
bf16* cache = p.kv[l] + ((long)g * p.max_seq + pos) * 256;
cache[128 + lane] = y0; cache[128 + lane + 32] = y1;
cache[128 + lane + 64] = y2; cache[128 + lane + 96] = y3;
}
}
__syncthreads();
if (sp == 0 && warp < 2) {
// current token as the 19th softmax partial: m=score, l=1, acc=vcur
const int h2 = warp;
float pd = s.u.attn.q[h2][lane] * s.u.attn.kcur[lane]
+ s.u.attn.q[h2][lane + 32] * s.u.attn.kcur[lane + 32]
+ s.u.attn.q[h2][lane + 64] * s.u.attn.kcur[lane + 64]
+ s.u.attn.q[h2][lane + 96] * s.u.attn.kcur[lane + 96];
pd = warp_sum(pd) * SCALE;
float* dst = p.partials + ((long)(2 * g + h2) * NSPLIT + SPLITS) * PSTRIDE;
if (lane == 0) { dst[0] = pd; dst[1] = 1.f; }
dst[4 + lane] = s.u.attn.vcur[lane];
dst[4 + lane + 32] = s.u.attn.vcur[lane + 32];
dst[4 + lane + 64] = s.u.attn.vcur[lane + 64];
dst[4 + lane + 96] = s.u.attn.vcur[lane + 96];
}
}
// warp-state -> per-(head,split) partial, shared by both stage2 variants
__device__ __noinline__ void stage2_tail(const Params& p, Smem& s, int g, int sp) {
const int tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
if (warp < 2) {
const int h2 = warp;
float mw = (lane < NWARP) ? s.u.attn.wm[lane][h2] : NEG_BIG;
float lw = (lane < NWARP) ? s.u.attn.wl[lane][h2] : 0.f;
float M = mw;
#pragma unroll
for (int o = 16; o; o >>= 1) M = fmaxf(M, __shfl_xor_sync(0xffffffffu, M, o));
float e = __expf(mw - M); // empty warp range: mw=-1e30 -> 0 (or M=-1e30 -> e=1, acc=0)
float L = warp_sum(e * lw);
float out[4] = {0, 0, 0, 0};
#pragma unroll
for (int i = 0; i < NWARP; ++i) {
float ei = __shfl_sync(0xffffffffu, e, i);
#pragma unroll
for (int j = 0; j < 4; ++j)
out[j] += ei * s.u.attn.wacc[h2][i][lane * 4 + j];
}
float* dst = p.partials + ((long)(2 * g + h2) * NSPLIT + sp) * PSTRIDE;
if (lane == 0) { dst[0] = M; dst[1] = L; }
#pragma unroll
for (int j = 0; j < 4; ++j) dst[4 + lane * 4 + j] = out[j];
}
}
// ---------- S2 big-ctx token loop (isolated for its own register budget) ----------
__device__ __forceinline__ void stage2_loop_big(const Params& p, Smem& s,
int l, int pos, int g, int sp) {
const int tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
// 4 tokens per iteration, one per 8-lane group; quarter-warp reduces.
const int grp = lane >> 3; // token t+grp
const int l8 = lane & 7;
const int sub = l8 * 16; // 16 head dims per lane
// q read from smem inside the loop: keeps the register footprint low
// enough that ptxas does not spill the prefetch/acc state.
const float* q0p = s.u.attn.q[0] + sub;
const float* q1p = s.u.attn.q[1] + sub;
const int len_past = pos;
const int cs = (len_past + SPLITS - 1) / SPLITS;
const int t0 = sp * cs, t1 = min(len_past, t0 + cs);
int per_w = (t1 - t0 + NWARP - 1) / NWARP;
per_w = (per_w + 3) & ~3;
const int w0 = t0 + warp * per_w, w1 = min(t1, w0 + per_w);
float m0 = NEG_BIG, l0 = 0.f, m1 = NEG_BIG, l1 = 0.f;
float acc0[16], acc1[16];
#pragma unroll
for (int j = 0; j < 16; ++j) { acc0[j] = 0.f; acc1[j] = 0.f; }
const bf16* kvb = p.kv[l] + (long)g * p.max_seq * 256;
if (w0 < w1) {
// double-buffered prefetch; addresses clamped to the last valid row so
// tail groups never touch uninitialized cache rows
float4 ka0, ka1, va0, va1, kb0, kb1, vb0, vb1;
{
long tt = min(w0 + grp, w1 - 1);
const float4* pk = reinterpret_cast<const float4*>(kvb + tt * 256 + sub);
ka0 = pk[0]; ka1 = pk[1];
const float4* pv = reinterpret_cast<const float4*>(kvb + tt * 256 + 128 + sub);
va0 = pv[0]; va1 = pv[1];
long t2 = min(w0 + 4 + grp, w1 - 1);
const float4* pk2 = reinterpret_cast<const float4*>(kvb + t2 * 256 + sub);
kb0 = pk2[0]; kb1 = pk2[1];
const float4* pv2 = reinterpret_cast<const float4*>(kvb + t2 * 256 + 128 + sub);
vb0 = pv2[0]; vb1 = pv2[1];
}
for (int t = w0; t < w1; t += 4) {
int my_t = t + grp;
bool valid = my_t < w1;
float4 k0 = ka0, k1 = ka1, v0 = va0, v1 = va1;
ka0 = kb0; ka1 = kb1; va0 = vb0; va1 = vb1;
long nxt = min((long)(my_t + 8), (long)(w1 - 1));
{
const float4* pk = reinterpret_cast<const float4*>(kvb + nxt * 256 + sub);
kb0 = pk[0]; kb1 = pk[1];
const float4* pv = reinterpret_cast<const float4*>(kvb + nxt * 256 + 128 + sub);
vb0 = pv[0]; vb1 = pv[1];
}
const bf16* kA = reinterpret_cast<const bf16*>(&k0);
const bf16* kB = reinterpret_cast<const bf16*>(&k1);
float p0 = 0.f, p1 = 0.f;
#pragma unroll
for (int j = 0; j < 8; ++j) {
float kf = bf2f(kA[j]);
p0 += q0p[j] * kf; p1 += q1p[j] * kf;
}
#pragma unroll
for (int j = 0; j < 8; ++j) {
float kf = bf2f(kB[j]);
p0 += q0p[8 + j] * kf; p1 += q1p[8 + j] * kf;
}
#pragma unroll
for (int o = 4; o; o >>= 1) {
p0 += __shfl_xor_sync(0xffffffffu, p0, o);
p1 += __shfl_xor_sync(0xffffffffu, p1, o);
}
p0 *= SCALE; p1 *= SCALE;
if (!valid) { p0 = NEG_BIG; p1 = NEG_BIG; }
// factor form: acc = acc*c + w*f with (c,w) in {(1,e),(e,1)} — one
// 8-wide conversion batch at a time keeps register pressure down
float c0f, w0f;
if (p0 <= m0) { c0f = 1.f; w0f = __expf(p0 - m0); l0 += w0f; }
else { c0f = __expf(m0 - p0); w0f = 1.f; l0 = l0 * c0f + 1.f; m0 = p0; }
float c1f, w1f;
if (p1 <= m1) { c1f = 1.f; w1f = __expf(p1 - m1); l1 += w1f; }
else { c1f = __expf(m1 - p1); w1f = 1.f; l1 = l1 * c1f + 1.f; m1 = p1; }
const bf16* vA = reinterpret_cast<const bf16*>(&v0);
const bf16* vB = reinterpret_cast<const bf16*>(&v1);
float fw[8];
#pragma unroll
for (int j = 0; j < 8; ++j) fw[j] = bf2f(vA[j]);
#pragma unroll
for (int j = 0; j < 8; ++j) {
acc0[j] = acc0[j] * c0f + w0f * fw[j];
acc1[j] = acc1[j] * c1f + w1f * fw[j];
}
#pragma unroll
for (int j = 0; j < 8; ++j) fw[j] = bf2f(vB[j]);
#pragma unroll
for (int j = 0; j < 8; ++j) {
acc0[8 + j] = acc0[8 + j] * c0f + w0f * fw[j];
acc1[8 + j] = acc1[8 + j] * c1f + w1f * fw[j];
}
}
}
// merge the 4 group states (xor 8, then xor 16); empty states are safe:
// exp(-1e30 - -1e30)=exp(0)=1 scales l=0/acc=0.
#pragma unroll
for (int o = 8; o <= 16; o <<= 1) {
float mo0 = __shfl_xor_sync(0xffffffffu, m0, o);
float lo0 = __shfl_xor_sync(0xffffffffu, l0, o);
float M0 = fmaxf(m0, mo0);
float ce = __expf(m0 - M0), co = __expf(mo0 - M0);
l0 = l0 * ce + lo0 * co;
#pragma unroll
for (int j = 0; j < 16; ++j) {
float other = __shfl_xor_sync(0xffffffffu, acc0[j], o);
acc0[j] = acc0[j] * ce + other * co;
}
m0 = M0;
float mo1 = __shfl_xor_sync(0xffffffffu, m1, o);
float lo1 = __shfl_xor_sync(0xffffffffu, l1, o);
float M1 = fmaxf(m1, mo1);
float ce1 = __expf(m1 - M1), co1 = __expf(mo1 - M1);
l1 = l1 * ce1 + lo1 * co1;
#pragma unroll
for (int j = 0; j < 16; ++j) {
float other = __shfl_xor_sync(0xffffffffu, acc1[j], o);
acc1[j] = acc1[j] * ce1 + other * co1;
}
m1 = M1;
}
if (lane == 0) {
s.u.attn.wm[warp][0] = m0; s.u.attn.wl[warp][0] = l0;
s.u.attn.wm[warp][1] = m1; s.u.attn.wl[warp][1] = l1;
}
if (grp == 0) {
#pragma unroll
for (int j = 0; j < 16; ++j) {
s.u.attn.wacc[0][warp][sub + j] = acc0[j];
s.u.attn.wacc[1][warp][sub + j] = acc1[j];
}
}
}
// ---------- S2: q/k norm + rope + KV append + flash-decode attention ----------
__device__ __forceinline__ void stage2_big(const Params& p, Smem& s,
const float* __restrict__ nl,
int l, int pos) {
const int bid = blockIdx.x, tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
if (bid >= ATT_BLOCKS) return;
const int g = bid / SPLITS, sp = bid % SPLITS;
stage2_prep_body(p, s, nl, l, pos);
stage2_loop_big(p, s, l, pos, g, sp);
__syncthreads();
stage2_tail(p, s, g, sp);
}
// ---------- S2 small-ctx body: one token per warp iteration ----------
__device__ __forceinline__ void stage2_small(const Params& p, Smem& s,
const float* __restrict__ nl, int l, int pos) {
const int bid = blockIdx.x, tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
if (bid >= ATT_BLOCKS) return;
const int g = bid / SPLITS, sp = bid % SPLITS;
stage2_prep_body(p, s, nl, l, pos);
const int l16 = lane & 15;
const bool vlane = lane >= 16;
const int sub = l16 * 8;
float q0s[8], q1s[8];
#pragma unroll
for (int j = 0; j < 8; ++j) {
q0s[j] = s.u.attn.q[0][sub + j];
q1s[j] = s.u.attn.q[1][sub + j];
}
const int len_past = pos;
const int cs = (len_past + SPLITS - 1) / SPLITS;
const int t0 = sp * cs, t1 = min(len_past, t0 + cs);
const int per_w = (t1 - t0 + NWARP - 1) / NWARP;
const int w0 = t0 + warp * per_w, w1 = min(t1, w0 + per_w);
float m0 = NEG_BIG, l0 = 0.f, m1 = NEG_BIG, l1 = 0.f;
float acc0[8] = {0, 0, 0, 0, 0, 0, 0, 0};
float acc1[8] = {0, 0, 0, 0, 0, 0, 0, 0};
const int roff = (vlane ? 128 : 0) + sub;
const bf16* kvb = p.kv[l] + (long)g * p.max_seq * 256;
float4 pf0, pf1, pf2, pf3;
if (w0 + 0 < w1) pf0 = *reinterpret_cast<const float4*>(kvb + (long)(w0 + 0) * 256 + roff);
if (w0 + 1 < w1) pf1 = *reinterpret_cast<const float4*>(kvb + (long)(w0 + 1) * 256 + roff);
if (w0 + 2 < w1) pf2 = *reinterpret_cast<const float4*>(kvb + (long)(w0 + 2) * 256 + roff);
if (w0 + 3 < w1) pf3 = *reinterpret_cast<const float4*>(kvb + (long)(w0 + 3) * 256 + roff);
for (int t = w0; t < w1; ++t) {
float4 rv = pf0;
pf0 = pf1; pf1 = pf2; pf2 = pf3;
if (t + 4 < w1) pf3 = *reinterpret_cast<const float4*>(kvb + (long)(t + 4) * 256 + roff);
const bf16* fb = reinterpret_cast<const bf16*>(&rv);
float fv[8];
#pragma unroll
for (int j = 0; j < 8; ++j) fv[j] = bf2f(fb[j]);
float p0 = 0.f, p1 = 0.f;
if (!vlane) {
#pragma unroll
for (int j = 0; j < 8; ++j) { p0 += q0s[j] * fv[j]; p1 += q1s[j] * fv[j]; }
}
#pragma unroll
for (int o = 16; o; o >>= 1) {
p0 += __shfl_xor_sync(0xffffffffu, p0, o);
p1 += __shfl_xor_sync(0xffffffffu, p1, o);
}
p0 *= SCALE; p1 *= SCALE;
float c0f, w0f;
if (p0 <= m0) { c0f = 1.f; w0f = __expf(p0 - m0); }
else { c0f = __expf(m0 - p0); w0f = 1.f; m0 = p0; }
l0 = l0 * c0f + w0f;
float c1f, w1f;
if (p1 <= m1) { c1f = 1.f; w1f = __expf(p1 - m1); }
else { c1f = __expf(m1 - p1); w1f = 1.f; m1 = p1; }
l1 = l1 * c1f + w1f;
if (vlane) {
#pragma unroll
for (int j = 0; j < 8; ++j) {
acc0[j] = acc0[j] * c0f + w0f * fv[j];
acc1[j] = acc1[j] * c1f + w1f * fv[j];
}
}
}
if (lane == 0) {
s.u.attn.wm[warp][0] = m0; s.u.attn.wl[warp][0] = l0;
s.u.attn.wm[warp][1] = m1; s.u.attn.wl[warp][1] = l1;
}
if (vlane) {
#pragma unroll
for (int j = 0; j < 8; ++j) {
s.u.attn.wacc[0][warp][sub + j] = acc0[j];
s.u.attn.wacc[1][warp][sub + j] = acc1[j];
}
}
__syncthreads();
stage2_tail(p, s, g, sp);
}
// ---------- S3: combine + O GEMV + residual ----------
__device__ __noinline__ void stage3(const Params& p, Smem& s,
const bf16* __restrict__ Wl, int l) {
const int bid = blockIdx.x, tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
{
const int h = warp;
const float* ph = p.partials + (long)h * NSPLIT * PSTRIDE;
float ms = (lane < NSPLIT) ? ph[lane * PSTRIDE] : NEG_BIG;
float ls = (lane < NSPLIT) ? ph[lane * PSTRIDE + 1] : 0.f;
float M = ms;
#pragma unroll
for (int o = 16; o; o >>= 1) M = fmaxf(M, __shfl_xor_sync(0xffffffffu, M, o));
float e = __expf(ms - M); // empty split: ms=-1e30 -> 0
float L = warp_sum(e * ls);
if (lane < NSPLIT) s.cw[h][lane] = e / L;
__syncwarp();
#pragma unroll
for (int cch = 0; cch < 4; ++cch) {
int d = cch * 32 + lane;
float v = 0.f;
#pragma unroll
for (int sp2 = 0; sp2 < NSPLIT; ++sp2)
v += s.cw[h][sp2] * ph[sp2 * PSTRIDE + 4 + d];
*elem_ptr(s.u.attn_vec, 256, h * HD + d) = v;
}
}
__syncthreads();
const bf16* xin = (l == 0) ? p.x_buf : p.h_io;
const bf16* Wo = Wl + OFF_O;
const float4* av = reinterpret_cast<const float4*>(s.u.attn_vec);
for (int r = warp * gridDim.x + bid; r < H; r += p.total_warps) {
const float4* wr = reinterpret_cast<const float4*>(Wo + (long)r * 2048);
float4 wv[8];
#pragma unroll
for (int it = 0; it < 8; ++it) wv[it] = wr[it * 32 + lane];
float acc = 0.f;
#pragma unroll
for (int it = 0; it < 8; ++it) {
const bf16* wb = reinterpret_cast<const bf16*>(&wv[it]);
float4 x0 = av[it * 32 + lane];
float4 x1 = av[256 + it * 32 + lane];
const float* xp0 = reinterpret_cast<const float*>(&x0);
const float* xp1 = reinterpret_cast<const float*>(&x1);
#pragma unroll
for (int j = 0; j < 4; ++j)
acc += bf2f(wb[j]) * xp0[j] + bf2f(wb[4 + j]) * xp1[j];
}
acc = warp_sum(acc);
if (lane == 0) p.h_attn[r] = bf2f(xin[r]) + acc;
}
const bf16* Wgu_pf = Wl + OFF_GU;
for (int r = warp * gridDim.x + bid; r < I3; r += p.total_warps)
l2_prefetch(reinterpret_cast<const char*>(Wgu_pf + (long)r * 2048) + lane * 128);
}
// ---------- S4: post RMSNorm + gate/up GEMV + SiLU ----------
__device__ __noinline__ void stage4(const Params& p, Smem& s,
const bf16* __restrict__ Wl,
const float* __restrict__ nl) {
const int bid = blockIdx.x, tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
float sq = 0.f;
for (int e = tid; e < H; e += NTHR) {
float v = p.h_attn[e];
*elem_ptr(s.xhat, 128, e) = v;
sq += v * v;
}
float tot = block_sum(sq, &s);
float rms = rsqrtf(tot * (1.f / H) + EPS);
const float* pn = nl + 1024;
for (int e = tid; e < H; e += NTHR) {
float* q = elem_ptr(s.xhat, 128, e);
*q = *q * rms * pn[e];
}
__syncthreads();
const bf16* Wgu = Wl + OFF_GU;
const float4* xt = reinterpret_cast<const float4*>(s.xhat);
for (int r = warp * gridDim.x + bid; r < I3; r += p.total_warps) {
const float4* wr = reinterpret_cast<const float4*>(Wgu + (long)r * 2048);
float4 wv[8];
#pragma unroll
for (int it = 0; it < 8; ++it) wv[it] = wr[it * 32 + lane];
float aG = 0.f, aU = 0.f;
#pragma unroll
for (int it = 0; it < 8; ++it) {
const bf16* wb = reinterpret_cast<const bf16*>(&wv[it]);
int itm = (it < 4) ? it : (it - 4);
float4 x0 = xt[itm * 32 + lane];
float4 x1 = xt[128 + itm * 32 + lane];
const float* xp0 = reinterpret_cast<const float*>(&x0);
const float* xp1 = reinterpret_cast<const float*>(&x1);
if (it < 4) {
#pragma unroll
for (int j = 0; j < 4; ++j)
aG += bf2f(wb[j]) * xp0[j] + bf2f(wb[4 + j]) * xp1[j];
} else {
#pragma unroll
for (int j = 0; j < 4; ++j)
aU += bf2f(wb[j]) * xp0[j] + bf2f(wb[4 + j]) * xp1[j];
}
}
#pragma unroll
for (int o = 16; o; o >>= 1) {
aG += __shfl_xor_sync(0xffffffffu, aG, o);
aU += __shfl_xor_sync(0xffffffffu, aU, o);
}
if (lane == 0) {
float sig = 1.f / (1.f + __expf(-aG));
p.act[r] = aG * sig * aU;
}
}
const bf16* Wd_pf = Wl + OFF_DN;
for (int r = warp * gridDim.x + bid; r < H; r += p.total_warps) {
const char* base = reinterpret_cast<const char*>(Wd_pf + (long)r * I3);
l2_prefetch(base + lane * 128);
if (lane < 16) l2_prefetch(base + 4096 + lane * 128);
}
}
// ---------- S5: down GEMV + residual ----------
__device__ __noinline__ void stage5(const Params& p, Smem& s,
const bf16* __restrict__ Wl, int l) {
const int bid = blockIdx.x, tid = threadIdx.x;
const int warp = tid >> 5, lane = tid & 31;
for (int e = tid; e < I3; e += NTHR) *elem_ptr(s.u.act_s, 384, e) = p.act[e];
__syncthreads();
const bf16* Wd = Wl + OFF_DN;
const float4* at = reinterpret_cast<const float4*>(s.u.act_s);
for (int r = warp * gridDim.x + bid; r < H; r += p.total_warps) {
const float4* wr = reinterpret_cast<const float4*>(Wd + (long)r * I3);
float4 wv[12];
#pragma unroll
for (int it = 0; it < 12; ++it) wv[it] = wr[it * 32 + lane];
float acc = 0.f;
#pragma unroll
for (int it = 0; it < 12; ++it) {
const bf16* wb = reinterpret_cast<const bf16*>(&wv[it]);
float4 x0 = at[it * 32 + lane];
float4 x1 = at[384 + it * 32 + lane];
const float* xp0 = reinterpret_cast<const float*>(&x0);
const float* xp1 = reinterpret_cast<const float*>(&x1);
#pragma unroll
for (int j = 0; j < 4; ++j)
acc += bf2f(wb[j]) * xp0[j] + bf2f(wb[4 + j]) * xp1[j];
}
acc = warp_sum(acc);
if (lane == 0) p.h_io[r] = __float2bfloat16(p.h_attn[r] + acc);
}
const bf16* Wn = p.W + (long)((l + 1) % p.num_layers) * LAYER_ELEMS;
for (int pr = warp * gridDim.x + bid; pr < QKV_ROWS / 2; pr += p.total_warps)
l2_prefetch(reinterpret_cast<const char*>(Wn + (long)(2 * pr) * H) + lane * 128);
}
template <bool BIG>
__global__ void __launch_bounds__(NTHR, 1) megaqwen_kernel(Params p) {
__shared__ Smem s;
const int bid = blockIdx.x;
const int tid = threadIdx.x;
#if MQ_DBG
unsigned long long dbg_t = (p.dbg && bid == 0 && tid == 0) ? clock64() : 0;
#endif
for (int step = 0; step < p.n_steps; ++step) {
const int pos = p.start_pos + step;
for (int l = 0; l < p.num_layers; ++l) {
const bf16* Wl = p.W + (long)l * LAYER_ELEMS;
const float* nl = p.norms + l * NORMS_PER_LAYER;
stage1(p, s, Wl, nl, l, step);
DBG_MARK(0);
cg::this_grid().sync();
DBG_MARK(5);
if (BIG) stage2_big(p, s, nl, l, pos);
else stage2_small(p, s, nl, l, pos);
DBG_MARK(1);
cg::this_grid().sync();
DBG_MARK(6);
stage3(p, s, Wl, l);
DBG_MARK(2);
cg::this_grid().sync();
DBG_MARK(7);
stage4(p, s, Wl, nl);
DBG_MARK(3);
cg::this_grid().sync();
DBG_MARK(8);
stage5(p, s, Wl, l);
DBG_MARK(4);
cg::this_grid().sync();
DBG_MARK(9);
}
}
}
void megaqwen_launch(torch::Tensor W, torch::Tensor norms,
std::vector<torch::Tensor> kv,
torch::Tensor cos_tab, torch::Tensor sin_tab,
torch::Tensor rand_seq, torch::Tensor h_io, torch::Tensor x_buf,
torch::Tensor qkv_raw, torch::Tensor partials,
torch::Tensor h_attn, torch::Tensor act,
int64_t max_seq, int64_t start_pos, int64_t n_steps,
torch::Tensor dbg, int64_t big_thresh) {
Params p;
p.W = reinterpret_cast<const bf16*>(W.data_ptr());
p.norms = norms.data_ptr<float>();
int nl = (int)kv.size();
TORCH_CHECK(nl >= 1 && nl <= 8, "num_layers must be in [1,8]");
for (int i = 0; i < 8; ++i)
p.kv[i] = reinterpret_cast<bf16*>(kv[i < nl ? i : 0].data_ptr());
p.cos_tab = cos_tab.data_ptr<float>();
p.sin_tab = sin_tab.data_ptr<float>();
p.rand_seq = reinterpret_cast<const bf16*>(rand_seq.data_ptr());
p.h_io = reinterpret_cast<bf16*>(h_io.data_ptr());
p.x_buf = reinterpret_cast<bf16*>(x_buf.data_ptr());
p.qkv_raw = qkv_raw.data_ptr<float>();
p.partials = partials.data_ptr<float>();
p.h_attn = h_attn.data_ptr<float>();
p.act = act.data_ptr<float>();
p.max_seq = (long)max_seq;
p.start_pos = (int)start_pos;
p.n_steps = (int)n_steps;
p.num_layers = nl;
p.dbg = dbg.numel() ? reinterpret_cast<unsigned long long*>(dbg.data_ptr()) : nullptr;
int dev = 0;
cudaGetDevice(&dev);
static int grid_cached = -1;
if (grid_cached < 0) {
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, dev);
int per_sm_a = 0, per_sm_b = 0;
cudaOccupancyMaxActiveBlocksPerMultiprocessor(&per_sm_a, (void*)megaqwen_kernel<true>, NTHR, 0);
cudaOccupancyMaxActiveBlocksPerMultiprocessor(&per_sm_b, (void*)megaqwen_kernel<false>, NTHR, 0);
TORCH_CHECK(per_sm_a >= 1 && per_sm_b >= 1, "megaqwen kernel does not fit 1 block/SM");
grid_cached = prop.multiProcessorCount;
TORCH_CHECK(grid_cached >= ATT_BLOCKS, "need >= 144 SMs for the split layout");
}
p.total_warps = grid_cached * NWARP;
void* args[] = {&p};
auto stream = at::cuda::getCurrentCUDAStream();
bool big = start_pos >= big_thresh;
void* fn = big ? (void*)megaqwen_kernel<true> : (void*)megaqwen_kernel<false>;
cudaError_t err = cudaLaunchCooperativeKernel(
fn, dim3(grid_cached), dim3(NTHR), args, 0, stream.stream());
TORCH_CHECK(err == cudaSuccess, "cooperative launch failed: ", cudaGetErrorString(err));
}
void set_l2_policy(torch::Tensor W, double fraction) {
int dev = 0;
cudaGetDevice(&dev);
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, dev);
size_t persist_max = prop.persistingL2CacheMaxSize;
if (persist_max == 0) return;
cudaDeviceSetLimit(cudaLimitPersistingL2CacheSize, persist_max);
size_t nbytes = (size_t)W.numel() * W.element_size();
size_t window = nbytes;
if (window > (size_t)prop.accessPolicyMaxWindowSize)
window = (size_t)prop.accessPolicyMaxWindowSize;
cudaStreamAttrValue attr;
attr.accessPolicyWindow.base_ptr = W.data_ptr();
attr.accessPolicyWindow.num_bytes = window;
float hr = (float)fraction;
if (hr > 1.f) hr = 1.f;
attr.accessPolicyWindow.hitRatio = hr;
attr.accessPolicyWindow.hitProp = cudaAccessPropertyPersisting;
attr.accessPolicyWindow.missProp = cudaAccessPropertyStreaming;
auto stream = at::cuda::getCurrentCUDAStream();
cudaStreamSetAttribute(stream.stream(), cudaStreamAttributeAccessPolicyWindow, &attr);
}
void clear_l2_policy() {
cudaStreamAttrValue attr;
attr.accessPolicyWindow.base_ptr = nullptr;
attr.accessPolicyWindow.num_bytes = 0;
attr.accessPolicyWindow.hitRatio = 0.f;
attr.accessPolicyWindow.hitProp = cudaAccessPropertyNormal;
attr.accessPolicyWindow.missProp = cudaAccessPropertyNormal;
auto stream = at::cuda::getCurrentCUDAStream();
cudaStreamSetAttribute(stream.stream(), cudaStreamAttributeAccessPolicyWindow, &attr);
}
"""
_CPP_SRC = """
#include <vector>
#include <torch/extension.h>
void megaqwen_launch(torch::Tensor W, torch::Tensor norms,
std::vector<torch::Tensor> kv,
torch::Tensor cos_tab, torch::Tensor sin_tab,
torch::Tensor rand_seq, torch::Tensor h_io, torch::Tensor x_buf,
torch::Tensor qkv_raw, torch::Tensor partials,
torch::Tensor h_attn, torch::Tensor act,
int64_t max_seq, int64_t start_pos, int64_t n_steps,
torch::Tensor dbg, int64_t big_thresh);
void set_l2_policy(torch::Tensor W, double fraction);
void clear_l2_policy();
"""
_ext = None
def _get_ext():
global _ext
if _ext is None:
from torch.utils.cpp_extension import load_inline
cap = torch.cuda.get_device_capability(0)
arch = f"{cap[0]}{cap[1]}"
_ext = load_inline(
name="megaqwen_decode_v19" + ("_dbg" if os.environ.get("MQ_DBG") == "1" else "") + ("_nopf" if os.environ.get("MQ_PF") == "0" else ""),
cpp_sources=_CPP_SRC,
cuda_sources=_CUDA_SRC,
functions=["megaqwen_launch", "set_l2_policy", "clear_l2_policy"],
extra_cuda_cflags=[
"-O3",
f"-gencode=arch=compute_{arch},code=sm_{arch}",
"--use_fast_math",
f"-DMQ_DBG={1 if os.environ.get('MQ_DBG') == '1' else 0}",
f"-DMQ_PF={0 if os.environ.get('MQ_PF') == '0' else 1}",
],
verbose=False,
)
return _ext
class Block(nn.Module):
def __init__(self):
super().__init__()
H, I, D = HIDDEN, INTERMEDIATE, HEAD_DIM
self.input_ln = nn.Parameter(torch.ones(H, dtype=torch.bfloat16))
self.q_proj = nn.Parameter(torch.empty(NUM_Q * D, H, dtype=torch.bfloat16))
self.k_proj = nn.Parameter(torch.empty(NUM_KV * D, H, dtype=torch.bfloat16))
self.v_proj = nn.Parameter(torch.empty(NUM_KV * D, H, dtype=torch.bfloat16))
self.q_norm = nn.Parameter(torch.ones(D, dtype=torch.bfloat16))
self.k_norm = nn.Parameter(torch.ones(D, dtype=torch.bfloat16))
self.o_proj = nn.Parameter(torch.empty(H, NUM_Q * D, dtype=torch.bfloat16))
self.post_ln = nn.Parameter(torch.ones(H, dtype=torch.bfloat16))
self.gate_proj = nn.Parameter(torch.empty(I, H, dtype=torch.bfloat16))
self.up_proj = nn.Parameter(torch.empty(I, H, dtype=torch.bfloat16))
self.down_proj = nn.Parameter(torch.empty(H, I, dtype=torch.bfloat16))
for p in self.parameters():
if p.dim() >= 2:
nn.init.normal_(p, std=0.02)
class Model(nn.Module):
def __init__(self, num_layers: int = NUM_LAYERS, max_seq: int = 131072):
super().__init__()
self.num_layers = num_layers
self.max_seq = max_seq
self.blocks = nn.ModuleList([Block() for _ in range(num_layers)])
self._mq: dict = {}
def _ensure_packed(model: Model, device: torch.device) -> dict:
"""(Re)pack weights into flat kernel buffers. Called from prefill (untimed);
always repacks because load_state_dict may have replaced values."""
st = model._mq
L = model.num_layers
if st.get("device") != device or st.get("L") != L:
st.clear()
st["device"] = device
st["L"] = L
st["W"] = torch.empty(L * LAYER_ELEMS, dtype=torch.bfloat16, device=device)
st["norms"] = torch.empty(L * NORMS_PER_LAYER, dtype=torch.float32, device=device)
st["qkv_raw"] = torch.empty(4096, dtype=torch.float32, device=device)
st["partials"] = torch.empty(NUM_Q * (SPLITS + 1) * PARTIAL_STRIDE, dtype=torch.float32, device=device)
st["h_attn"] = torch.empty(HIDDEN, dtype=torch.float32, device=device)
st["act"] = torch.empty(INTERMEDIATE, dtype=torch.float32, device=device)
st["x_buf"] = torch.empty(HIDDEN, dtype=torch.bfloat16, device=device)
st["empty_dbg"] = torch.empty(0, dtype=torch.int64, device=device)
W = st["W"]
norms = st["norms"]
for i, b in enumerate(model.blocks):
base = i * LAYER_ELEMS
W[base:base + 4194304].view(4096, 1024)[:2048].copy_(b.q_proj.detach())
W[base:base + 4194304].view(4096, 1024)[2048:3072].copy_(b.k_proj.detach())
W[base:base + 4194304].view(4096, 1024)[3072:].copy_(b.v_proj.detach())
W[base + 4194304:base + 6291456].view(1024, 2048).copy_(b.o_proj.detach())
gu = W[base + 6291456:base + 12582912].view(3072, 2, 1024)
gu[:, 0].copy_(b.gate_proj.detach())
gu[:, 1].copy_(b.up_proj.detach())
W[base + 12582912:base + 15728640].view(1024, 3072).copy_(b.down_proj.detach())
nb = i * NORMS_PER_LAYER
norms[nb:nb + 1024].copy_(b.input_ln.detach().float())
norms[nb + 1024:nb + 2048].copy_(b.post_ln.detach().float())
norms[nb + 2048:nb + 2176].copy_(b.q_norm.detach().float())
norms[nb + 2176:nb + 2304].copy_(b.k_norm.detach().float())
if st.get("rope_len", 0) < model.max_seq:
# Bitwise-identical to reference._rope: same torch ops, fp32 on device.
half = HEAD_DIM // 2
inv = 1.0 / (
10000
** (torch.arange(0, half, device=device, dtype=torch.float32) / half)
)
t = torch.arange(model.max_seq, device=device, dtype=torch.float32)
freqs = torch.outer(t, inv)
st["cos"] = freqs.cos().contiguous()
st["sin"] = freqs.sin().contiguous()
st["rope_len"] = model.max_seq
return st
DBG_CYCLES = None # set to a cuda int64[8] tensor to collect per-stage cycles
def _launch(st, kv_list, rand, hidden, max_seq, start_pos, n_steps):
dbg = DBG_CYCLES if DBG_CYCLES is not None else st["empty_dbg"]
_get_ext().megaqwen_launch(
st["W"], st["norms"], kv_list, st["cos"], st["sin"], rand, hidden,
st["x_buf"], st["qkv_raw"], st["partials"], st["h_attn"], st["act"],
max_seq, start_pos, n_steps, dbg, BIG_THRESH,
)
@torch.no_grad()
def prefill(model: Model, ctx_len: int, seed: int, device: torch.device | None = None):
"""Build KV of length ctx_len. NOT timed in benchmark."""
device = device or next(model.parameters()).device
assert device.type == "cuda", "CUDA required"
model.eval()
assert ctx_len <= model.max_seq
st = _ensure_packed(model, device)
if os.environ.get("MQ_L2", "1") != "0":
_get_ext().set_l2_policy(st["W"], 1.0)
else:
_get_ext().clear_l2_policy()
S = model.max_seq
kv = [
torch.empty(NUM_KV, S, 2, HEAD_DIM, dtype=torch.bfloat16, device=device)
for _ in range(model.num_layers)
]
g0 = torch.Generator(device="cpu")
g0.manual_seed(seed)
hidden = torch.randn(HIDDEN, generator=g0, dtype=torch.bfloat16).to(device)
g = torch.Generator(device="cpu")
g.manual_seed(seed + 1)
t = 0
CHUNK = 8192
while t < ctx_len:
n = min(CHUNK, ctx_len - t)
if t < BIG_THRESH < t + n:
n = BIG_THRESH - t # kernel variant switches at this position
# Batched randn is bitwise-identical to n sequential randn(1024) calls.
rand = (
torch.randn(n * HIDDEN, generator=g, dtype=torch.bfloat16)
.view(n, HIDDEN)
.to(device)
)
_launch(st, kv, rand, hidden, S, t, n)
t += n
k_caches = kv # interleaved [8, S, 2(K|V), 128] — internal layout
v_caches = [c[:, :, 1, :] for c in kv]
return hidden, k_caches, v_caches
@torch.no_grad()
def decode_steps(
model: Model,
hidden: torch.Tensor,
k_caches,
v_caches,
start_pos: int,
n_steps: int,
seed: int,
):
"""Run n_steps decode steps starting at start_pos. Timed in benchmark."""
if n_steps <= 0:
return hidden, k_caches, v_caches
device = hidden.device
st = model._mq
assert st.get("device") == device, "call prefill first"
assert start_pos + n_steps <= model.max_seq
g = torch.Generator(device="cpu")
g.manual_seed(seed + 2)
kv = list(k_caches)
# Chunked launches: a small first chunk starts the GPU immediately; the
# CPU generates the remaining randn stream while the GPU runs. Batched
# randn from one generator is bitwise-identical to per-step calls.
done = 0
keep = []
while done < n_steps:
n = min(8 if done == 0 else n_steps, n_steps - done)
sp0 = start_pos + done
if sp0 < BIG_THRESH < sp0 + n:
n = BIG_THRESH - sp0 # kernel variant switches at this position
rand = (
torch.randn(n * HIDDEN, generator=g, dtype=torch.bfloat16)
.view(n, HIDDEN)
.to(device, non_blocking=True)
)
keep.append(rand)
_launch(st, kv, rand, hidden, model.max_seq, start_pos + done, n)
done += n
return hidden, k_caches, v_caches
def run(
ctx_len: int,
n_decode: int,
seed: int,
model: Model | None = None,
max_seq: int | None = None,
) -> dict:
"""Prefill then decode. Returns last_hidden for numeric correctness."""
device = torch.device("cuda:0")
max_seq = max_seq or max(ctx_len + n_decode, 512)
if model is None:
model = Model(NUM_LAYERS, max_seq)
else:
if getattr(model, "max_seq", 0) < ctx_len + n_decode:
raise ValueError(
f"model.max_seq={getattr(model, 'max_seq', None)} too small for "
f"ctx_len={ctx_len}+n_decode={n_decode}"
)
model = model.to(device).eval()
h, k_caches, v_caches = prefill(model, ctx_len, seed, device=device)
h, k_caches, v_caches = decode_steps(
model, h, k_caches, v_caches, start_pos=ctx_len, n_steps=n_decode, seed=seed
)
torch.cuda.synchronize()
return {
"last_hidden": h.detach(),
"ctx_len": ctx_len,
"decode_steps": n_decode,
}
def get_init_inputs():
return [NUM_LAYERS, 131072]
def get_inputs():
return []
20260719_112613_or-fable_anthropic_claude-fable-5_03_megaqwen_decode