1use crate::codegen_cuda::qwen_emit::Qwen30bCfg;
16
17pub fn emit_qwen30b_generate_batched(
20 cfg: &Qwen30bCfg,
21 wdir: &str,
22 prompt: &[usize],
23 n_gen: usize,
24 batch: usize,
25) -> String {
26 let (e, ff, ne, ktop, vocab, layers, nh, nkv, hd) = (
27 cfg.d, cfg.dff, cfg.ne, cfg.k, cfg.vocab, cfg.layers, cfg.h, cfg.kv, cfg.hd,
28 );
29 let qd = nh * hd;
30 let kd = nkv * hd;
31 let maxseq = prompt.len() + 128 + 16;
34 let scale = 1.0f64 / (hd as f64).sqrt();
35 let prompt_c = prompt
36 .iter()
37 .map(|t| t.to_string())
38 .collect::<Vec<_>>()
39 .join(",");
40
41 let prov = super::provenance::header(super::provenance::Provenance::HandWritten {
42 model: "Qwen3-30B-A3B",
43 lane: "batched decode",
44 });
45 format!(
46 r#"{prov}// Qwen3-30B-A3B BATCHED decode: B parallel sequences, weight reuse via grid.y=B, per-sequence golden.
47// Weights from {wdir}.
48#include <cstdio>
49#include <cstdlib>
50#include <cstring>
51#include <vector>
52#include <cuda_runtime.h>
53#include <cuda_fp16.h>
54#include <cmath>
55#define E {e}
56#define QD {qd}
57#define KD {kd}
58#define FF {ff}
59#define NE {ne}
60#define KTOP {ktop}
61#define VOCAB {vocab}
62#define LAYERS {layers}
63#define NH {nh}
64#define NKV {nkv}
65#define HD {hd}
66#define MAXSEQ {maxseq}
67#define ATTN_SPLIT 8
68#define B {batch}
69#define EPSV 1e-6f
70#define ROPEV 1000000.0f
71static const float SCALEV = {scale}f;
72
73// ── batched device kernels: per-token order identical to batch-1 (golden per sequence), grid.y=B for reuse ──
74__global__ void bgk_embed(float* X, const signed char* wq, const float* ws, const int* D_tok){{
75 int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx>=B*E) return; int b=idx/E, i=idx%E;
76 long tok=D_tok[b]; X[(long)b*E+i]=(float)wq[tok*E+i]*ws[tok*(E/32)+i/32];
77}}
78// one block per sequence: rmsnorm(x)·w then int8 quant (the attention norm).
79__global__ void bgk_rmsnorm_q8(const float* X, signed char* Xq, float* Xs, const float* w, int n, float eps){{
80 int seq=blockIdx.x; const float* x=X+(long)seq*n; signed char* xq=Xq+(long)seq*n; float* xs=Xs+(long)seq*(n/32);
81 __shared__ float red[256]; float s=0; for(int i=threadIdx.x;i<n;i+=blockDim.x) s+=x[i]*x[i];
82 red[threadIdx.x]=s; __syncthreads();
83 for(int k=128;k>0;k>>=1){{ if(threadIdx.x<k) red[threadIdx.x]+=red[threadIdx.x+k]; __syncthreads(); }}
84 float rms=rsqrtf(red[0]/n+eps); int warp=threadIdx.x>>5, lane=threadIdx.x&31, nb=n/32;
85 for(int bl=warp;bl<nb;bl+=8){{ float y=x[bl*32+lane]*rms*w[bl*32+lane], a=fabsf(y);
86 for(int sh=16;sh>0;sh>>=1) a=fmaxf(a,__shfl_down_sync(0xffffffffu,a,sh));
87 a=__shfl_sync(0xffffffffu,a,0); float sc=a>0?a/127.0f:1.0f;
88 if(lane==0) xs[bl]=sc; xq[bl*32+lane]=(signed char)__float2int_rn(y/sc); }}
89}}
90// one block per sequence: x += y (residual kept), out = rmsnorm(x)·w (float, for router) AND int8 (oq/os_, experts).
91__global__ void bgk_add_rmsnorm_q8(float* X, const float* Y, float* Out, const float* w, signed char* Oq, float* Os, int n, float eps){{
92 int seq=blockIdx.x; float* x=X+(long)seq*n; const float* y=Y+(long)seq*n; float* out=Out+(long)seq*n;
93 signed char* oq=Oq+(long)seq*n; float* os_=Os+(long)seq*(n/32);
94 __shared__ float sh[256]; float s=0; for(int i=threadIdx.x;i<n;i+=blockDim.x){{ float v=x[i]+y[i]; x[i]=v; s+=v*v; }}
95 sh[threadIdx.x]=s; __syncthreads();
96 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }}
97 float scale=rsqrtf(sh[0]/n+eps); for(int i=threadIdx.x;i<n;i+=blockDim.x) out[i]=x[i]*scale*w[i];
98 __syncthreads();
99 int warp=threadIdx.x>>5, lane=threadIdx.x&31, nb=n/32;
100 for(int bl=warp;bl<nb;bl+=(blockDim.x>>5)){{ float v=out[bl*32+lane], av=fabsf(v);
101 for(int t=16;t>0;t>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,t));
102 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float qs=amax/127.0f;
103 if(lane==0) os_[bl]=qs; int q=(int)rintf(v/qs); if(q>127)q=127; if(q<-128)q=-128; oq[bl*32+lane]=(signed char)q; }}
104}}
105// one block per sequence: x += y, then rmsnorm(x)·w → int8 (attn norm of next layer / final).
106__global__ void bgk_add_rmsnorm_q8a(float* X, const float* Y, signed char* Xq, float* Xs, const float* w, int n, float eps){{
107 int seq=blockIdx.x; float* x=X+(long)seq*n; const float* y=Y+(long)seq*n; signed char* xq=Xq+(long)seq*n; float* xs=Xs+(long)seq*(n/32);
108 __shared__ float red[256]; float s=0; for(int i=threadIdx.x;i<n;i+=blockDim.x){{ float v=x[i]+y[i]; x[i]=v; s+=v*v; }}
109 red[threadIdx.x]=s; __syncthreads();
110 for(int k=128;k>0;k>>=1){{ if(threadIdx.x<k) red[threadIdx.x]+=red[threadIdx.x+k]; __syncthreads(); }}
111 float rms=rsqrtf(red[0]/n+eps); int warp=threadIdx.x>>5, lane=threadIdx.x&31, nb=n/32;
112 for(int bl=warp;bl<nb;bl+=8){{ float y2=x[bl*32+lane]*rms*w[bl*32+lane], a=fabsf(y2);
113 for(int sh=16;sh>0;sh>>=1) a=fmaxf(a,__shfl_down_sync(0xffffffffu,a,sh));
114 a=__shfl_sync(0xffffffffu,a,0); float sc=a>0?a/127.0f:1.0f;
115 if(lane==0) xs[bl]=sc; xq[bl*32+lane]=(signed char)__float2int_rn(y2/sc); }}
116}}
117// batched int8 GEMV, REGISTER-TILED (weight-stationary): grid=(N-warps, ceil(B/BTG)). Each warp reads the
118// weight row + its per-32 scale ONCE per k-block and reuses them across BTG sequences held in registers — true
119// B-fold weight-bandwidth amortization (not just L2). Per-sequence __dp4a order is identical to batch-1 ⇒ every
120// sequence is byte-exact (golden). This is the `bdp4a` pattern the batched lane was designed to lower to.
121#ifndef BTG
122#define BTG 8
123#endif
124#ifndef BTG_MOE
125#define BTG_MOE BTG
126#endif
127// ── occupancy cap for the register-heavy MoE GEMV kernels ──
128// gate / up-silu / down-combine each compile to 80 registers/thread ⇒ only ~40% occupancy on H100 (65536 regs/SM),
129// which leaves them DRAM-latency-bound at ~27% of peak bandwidth even though they are the FFN's dominant 65% of the
130// decode. Forcing ptxas to keep 5 resident 256-thread blocks/SM (≤51 regs) lifts occupancy to ~62% with zero spill —
131// the measured throughput peak (min-blocks 4→64regs and 6→42regs both regress; see cuda_qwen30b_batched_occupancy_lock).
132// This is the delta that carries the batched (B=32, tg128) decode past llama.cpp on the H100.
133#ifndef MOE_OCC
134#define MOE_OCC __launch_bounds__(256, 5)
135#endif
136__global__ void bgk_gemv(float* Y, const signed char* wq, const float* ws, const signed char* Xq, const float* Xs, int K, int N){{
137 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31; int b0=blockIdx.y*BTG;
138 const int4* w16=(const int4*)(wq+(long)o*K); const float* wsr=ws+(long)o*(K/32); int nq=K/512;
139 float acc[BTG]; for(int t=0;t<BTG;t++) acc[t]=0.f;
140 for(int c=0;c<nq;c++){{ int4 w=w16[c*32+lane]; int blk=c*16+lane/2; float wsb=wsr[blk];
141 #pragma unroll
142 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue;
143 int4 xx=((const int4*)(Xq+(long)bb*K))[c*32+lane];
144 int d=__dp4a(w.x,xx.x,0)+__dp4a(w.y,xx.y,0)+__dp4a(w.z,xx.z,0)+__dp4a(w.w,xx.w,0);
145 acc[t] += (float)d * (wsb*Xs[(long)bb*(K/32)+blk]); }} }}
146 int done=nq*512;
147 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue;
148 for(int j=done+lane;j<K;j+=32){{ int blk=j/32; acc[t] += (float)((int)Xq[(long)bb*K+j]*(int)wq[(long)o*K+j])*(wsr[blk]*Xs[(long)bb*(K/32)+blk]); }} }}
149 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float a=acc[t];
150 for(int s=16;s>0;s>>=1) a+=__shfl_down_sync(0xffffffffu,a,s); if(lane==0) Y[(long)bb*N+o]=a; }}
151}}
152// ★ int8 TENSOR-CORE batched GEMM (Marlin, M1–M5): Y[M][N] = Xq[M][K]·Wq[N][K] via mma.sync.m16n8k32.s8 — one
153// mma per 32-block (mma-k == Q8_0 scale block, SAT-certified M3), per-32-block dequant scale applied in REGISTERS
154// in the SAME float grouping as our dp4a (golden-bounded ≤4.2e-7, M4). At batch (M=B) the weight is reused M-fold
155// and the GEMM is COMPUTE-bound ⇒ tensor cores (~10× dp4a) are the win — exactly llama's mmq. Our decode layout
156// (activation [M][K]+[M][K/32] scale, weight [N][K]+[N][K/32] scale) already matches Marlin's.
157// SHARED-MEMORY-STAGED (llama's mmq technique): each block owns a TBM×TBN output tile and 8 warps. Per 32-block
158// of K, all 256 threads COOPERATIVELY load the activation tile (TBM×32) and weight tile (TBN×32) from global to
159// shared COALESCED, __syncthreads, then each warp reads its mma fragments FROM SHARED and issues mma.sync — so
160// global traffic hits HBM bandwidth (the naive per-fragment global loads did not). Per-32-block dequant scale
161// applied in registers in the SAME float grouping as dp4a (golden-bounded ≤4.2e-7, M3/M4 SAT-certified).
162#define TBM 16
163#define TBN 64
164#define GMMA(M,N) dim3((N)/TBN, ((M)+TBM-1)/TBM)
165__global__ void bgk_gemm_mma(const signed char* Xq,const float* Xs,const signed char* Wq,const float* Ws,float* Y,int M,int N,int K){{
166 int KB=K/32; int mblk=blockIdx.y*TBM, nblk=blockIdx.x*TBN;
167 int warp=threadIdx.x>>5, lane=threadIdx.x&31, tid=threadIdx.x; int gid=lane>>2, tq=lane&3;
168 __shared__ signed char Xsm[TBM*32]; __shared__ signed char Wsm[TBN*32];
169 float d0=0.f,d1=0.f,d2=0.f,d3=0.f;
170 for(int kb=0;kb<KB;kb++){{ int k0=kb*32;
171 for(int i=tid;i<TBM*32;i+=256){{ int r=i>>5,c=i&31; Xsm[i]=Xq[(long)(mblk+r)*K+k0+c]; }}
172 for(int i=tid;i<TBN*32;i+=256){{ int r=i>>5,c=i&31; Wsm[i]=Wq[(long)(nblk+r)*K+k0+c]; }}
173 __syncthreads();
174 int a0=*(const int*)(Xsm+gid*32+tq*4);
175 int a1=*(const int*)(Xsm+(gid+8)*32+tq*4);
176 int a2=*(const int*)(Xsm+gid*32+16+tq*4);
177 int a3=*(const int*)(Xsm+(gid+8)*32+16+tq*4);
178 int b0=*(const int*)(Wsm+(warp*8+gid)*32+tq*4);
179 int b1=*(const int*)(Wsm+(warp*8+gid)*32+16+tq*4);
180 int c0=0,c1=0,c2=0,c3=0;
181 asm volatile("mma.sync.aligned.m16n8k32.row.col.s32.s8.s8.s32 {{%0,%1,%2,%3}}, {{%4,%5,%6,%7}}, {{%8,%9}}, {{%0,%1,%2,%3}};"
182 : "+r"(c0),"+r"(c1),"+r"(c2),"+r"(c3) : "r"(a0),"r"(a1),"r"(a2),"r"(a3), "r"(b0),"r"(b1));
183 float xs0=Xs[(long)(mblk+gid)*KB+kb], xs1=Xs[(long)(mblk+gid+8)*KB+kb];
184 int cbase=nblk+warp*8; float ws0=Ws[(long)(cbase+tq*2)*KB+kb], ws1=Ws[(long)(cbase+tq*2+1)*KB+kb];
185 d0+=(float)c0*(ws0*xs0); d1+=(float)c1*(ws1*xs0); d2+=(float)c2*(ws0*xs1); d3+=(float)c3*(ws1*xs1);
186 __syncthreads();
187 }}
188 int r0=mblk+gid,r1=mblk+gid+8,cc0=nblk+warp*8+tq*2,cc1=cc0+1;
189 if(r0<M){{ if(cc0<N)Y[(long)r0*N+cc0]=d0; if(cc1<N)Y[(long)r0*N+cc1]=d1; }}
190 if(r1<M){{ if(cc0<N)Y[(long)r1*N+cc0]=d2; if(cc1<N)Y[(long)r1*N+cc1]=d3; }}
191}}
192// batched fused QKV, REGISTER-TILED: grid=(QD+2KD warps, ceil(B/BTG)). Weight row read once, reused across BTG
193// sequences; Q→qbuf[bb], K/V→cache[bb][pos]. Per-sequence order identical to batch-1 ⇒ golden.
194__global__ void bgk_gemv_qkv(float* qbuf,float* kc,float* vc,const int* d_pos,
195 const signed char* wqq,const float* wqs,const signed char* wkq,const float* wks,const signed char* wvq,const float* wvs,
196 const signed char* Xq,const float* Xs,int K){{
197 int og=(blockIdx.x*blockDim.x+threadIdx.x)>>5; int lane=threadIdx.x&31; int Ntot=QD+2*KD; if(og>=Ntot) return; int b0=blockIdx.y*BTG;
198 const signed char* wq; const float* ws; int o; int dstsel;
199 if(og<QD){{ wq=wqq; ws=wqs; o=og; dstsel=0; }}
200 else if(og<QD+KD){{ wq=wkq; ws=wks; o=og-QD; dstsel=1; }}
201 else {{ wq=wvq; ws=wvs; o=og-QD-KD; dstsel=2; }}
202 const int4* w16=(const int4*)(wq+(long)o*K); const float* wsr=ws+(long)o*(K/32); int nq=K/512;
203 float acc[BTG]; for(int t=0;t<BTG;t++) acc[t]=0.f;
204 for(int c=0;c<nq;c++){{ int4 w=w16[c*32+lane]; int blk=c*16+lane/2; float wsb=wsr[blk];
205 #pragma unroll
206 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue;
207 int4 xx=((const int4*)(Xq+(long)bb*K))[c*32+lane];
208 int d=__dp4a(w.x,xx.x,0)+__dp4a(w.y,xx.y,0)+__dp4a(w.z,xx.z,0)+__dp4a(w.w,xx.w,0);
209 acc[t] += (float)d * (wsb*Xs[(long)bb*(K/32)+blk]); }} }}
210 int done=nq*512;
211 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue;
212 for(int j=done+lane;j<K;j+=32){{ int blk=j/32; acc[t] += (float)((int)Xq[(long)bb*K+j]*(int)wq[(long)o*K+j])*(wsr[blk]*Xs[(long)bb*(K/32)+blk]); }} }}
213 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float a=acc[t];
214 for(int s=16;s>0;s>>=1) a+=__shfl_down_sync(0xffffffffu,a,s);
215 if(lane==0){{ if(dstsel==0) qbuf[(long)bb*QD+o]=a; else if(dstsel==1) kc[(long)bb*MAXSEQ*KD+(long)(*d_pos)*KD+o]=a; else vc[(long)bb*MAXSEQ*KD+(long)(*d_pos)*KD+o]=a; }} }}
216}}
217// batched Q+K per-head RMSNorm+RoPE: grid=(NH+NKV, B).
218__global__ void bgk_qk_norm_rope2(float* qbase, float* kc, const int* d_pos, const float* qnw, const float* knw, float rbase, float eps){{
219 int hb=blockIdx.x; int seq=blockIdx.y; float* base; const float* nw; int head; long boff;
220 if(hb<NH){{ base=qbase; nw=qnw; head=hb; boff=(long)seq*QD; }}
221 else {{ base=kc; nw=knw; head=hb-NH; boff=(long)seq*MAXSEQ*KD+(long)(*d_pos)*KD; }}
222 float* h=base+boff+(long)head*HD;
223 __shared__ float sh[128]; float s=0; for(int i=threadIdx.x;i<HD;i+=blockDim.x) s+=h[i]*h[i]; sh[threadIdx.x]=s; __syncthreads();
224 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }}
225 float sc=rsqrtf(sh[0]/HD+eps); __syncthreads();
226 for(int i=threadIdx.x;i<HD;i+=blockDim.x) h[i]=h[i]*sc*nw[i]; __syncthreads();
227 int half=HD/2; int pos=*d_pos;
228 for(int i=threadIdx.x;i<half;i+=blockDim.x){{ float f=powf(rbase,-2.0f*i/HD); float a=pos*f,c=cosf(a),si=sinf(a);
229 float x0=h[i],x1=h[i+half]; h[i]=x0*c-x1*si; h[i+half]=x0*si+x1*c; }}
230}}
231// batched split-K attention part: grid=(NH*ATTN_SPLIT, B).
232__global__ void bgk_attn_part(const float* q, const float* kc, const float* vc, const int* d_pos, float scale, int P, float* acc_part, float* m_part, float* d_part){{
233 int hbp=blockIdx.x; int seq=blockIdx.y; int head=hbp/P, p=hbp%P; if(head>=NH) return;
234 int kvh=head/(NH/NKV); int L=*d_pos+1; int KDl=NKV*HD;
235 const float* qh=q+(long)seq*QD+(long)head*HD; const float* kcs=kc+(long)seq*MAXSEQ*KD; const float* vcs=vc+(long)seq*MAXSEQ*KD;
236 int lane=threadIdx.x&31, wp=threadIdx.x>>5, nw=blockDim.x>>5; int dpl=HD>>5;
237 float qreg[8], acc[8]; for(int i=0;i<dpl;i++){{ qreg[i]=qh[lane+(i<<5)]; acc[i]=0.f; }}
238 float m=-1e30f, dsum=0.f;
239 for(int idx=wp; ; idx+=nw){{ int j=p+idx*P; if(j>=L) break;
240 const float* kj=kcs+(long)j*KDl+kvh*HD; float pt=0.f;
241 for(int i=0;i<dpl;i++) pt+=qreg[i]*kj[lane+(i<<5)];
242 for(int r=16;r>0;r>>=1) pt+=__shfl_xor_sync(0xffffffffu,pt,r);
243 float sj=pt*scale; float mn=fmaxf(m,sj), c=__expf(m-mn), pp=__expf(sj-mn); m=mn; dsum=dsum*c+pp;
244 const float* vj=vcs+(long)j*KDl+kvh*HD; for(int i=0;i<dpl;i++) acc[i]=acc[i]*c + pp*vj[lane+(i<<5)];
245 }}
246 __shared__ float sm[8], sd[8], sa[8][128];
247 if(lane==0){{ sm[wp]=m; sd[wp]=dsum; }}
248 for(int i=0;i<dpl;i++) sa[wp][lane+(i<<5)]=acc[i];
249 __syncthreads();
250 float M=-1e30f; for(int w=0;w<nw;w++) M=fmaxf(M,sm[w]);
251 float D=0.f; for(int w=0;w<nw;w++) D+=sd[w]*__expf(sm[w]-M);
252 long bidx=(long)seq*NH*P+(long)hbp;
253 if(threadIdx.x==0){{ m_part[bidx]=M; d_part[bidx]=D; }}
254 for(int d=threadIdx.x; d<HD; d+=blockDim.x){{ float a=0.f; for(int w=0;w<nw;w++) a+=sa[w][d]*__expf(sm[w]-M); acc_part[bidx*HD+d]=a; }}
255}}
256// batched combine + activation-quant: grid=(NH, B). → aqQ[seq], asQ[seq].
257__global__ void bgk_attn_comb_q(signed char* aq, float* as_, int P, const float* acc_part, const float* m_part, const float* d_part){{
258 int head=blockIdx.x; int seq=blockIdx.y; __shared__ float GM,GD; __shared__ float so[128];
259 long base=(long)seq*NH*P+(long)head*P;
260 if(threadIdx.x==0){{ float M=-1e30f; for(int p=0;p<P;p++) M=fmaxf(M,m_part[base+p]); GM=M;
261 float Dd=0.f; for(int p=0;p<P;p++) Dd+=d_part[base+p]*__expf(m_part[base+p]-M); GD=Dd; }}
262 __syncthreads(); float M=GM,D=GD;
263 for(int d=threadIdx.x; d<HD; d+=blockDim.x){{ float a=0.f; for(int p=0;p<P;p++) a+=acc_part[(base+p)*HD+d]*__expf(m_part[base+p]-M); so[d]=a/D; }}
264 __syncthreads();
265 int nb=HD/32, warp=threadIdx.x>>5, lane=threadIdx.x&31, nw=blockDim.x>>5;
266 signed char* aqs=aq+(long)seq*QD; float* ass=as_+(long)seq*(QD/32);
267 for(int bl=warp; bl<nb; bl+=nw){{ int gi=head*nb+bl; float v=so[bl*32+lane], av=fabsf(v);
268 for(int s2=16;s2>0;s2>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s2));
269 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float qsc=amax/127.0f;
270 if(lane==0) ass[gi]=qsc; int q=(int)rintf(v/qsc); if(q>127)q=127; if(q<-128)q=-128; aqs[gi*32+lane]=(signed char)q; }}
271}}
272// batched router GEMV: grid=((NE+7)/8, B). The router weight is tiny (NE×E); grid-over-B keeps the GPU FILLED
273// (512 blocks) and L2 holds the weight — occupancy beats register-tiling here (measured). Per-sequence order
274// identical to batch-1 ⇒ golden.
275__global__ void bmoe_router(const float* A, const signed char* wq, const float* ws, float* Y, int N, int K){{
276 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31; int seq=blockIdx.y;
277 const float* a=A+(long)seq*K; int nb=K/32, nq=K/128;
278 const signed char* wr=wq+(long)o*K; const float* wsr=ws+(long)o*nb; const char4* w4=(const char4*)wr;
279 float acc=0.0f;
280 for(int c=0;c<nq;++c){{ char4 w=w4[c*32+lane]; int blk=c*4+lane/8; const float* at=a+c*128+lane*4;
281 acc += wsr[blk]*((float)w.x*at[0]+(float)w.y*at[1]+(float)w.z*at[2]+(float)w.w*at[3]); }}
282 for(int t=nq*128+lane;t<K;t+=32){{ int blk=t/32; acc += wsr[blk]*(float)wr[t]*a[t]; }}
283 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s);
284 if(lane==0) Y[(long)seq*NE+o]=acc;
285}}
286// batched top-K: one block per sequence.
287__global__ void bmoe_topk(const float* Logits, int* Idx, float* W, int Ec, int K){{
288 int seq=blockIdx.x; const float* logits=Logits+(long)seq*Ec; int* idx=Idx+(long)seq*K; float* w=W+(long)seq*K;
289 __shared__ float sp[1024]; __shared__ float red[32];
290 int t=threadIdx.x, nt=blockDim.x, wp=t>>5, ln=t&31, nw=(nt+31)>>5;
291 float lm=-1e30f; for(int e=t;e<Ec;e+=nt) lm=fmaxf(lm,logits[e]);
292 for(int s=16;s>0;s>>=1) lm=fmaxf(lm,__shfl_down_sync(0xffffffffu,lm,s));
293 if(ln==0) red[wp]=lm; __syncthreads();
294 if(t==0){{ float m=red[0]; for(int i=1;i<nw;++i) m=fmaxf(m,red[i]); red[0]=m; }} __syncthreads();
295 float mx=red[0];
296 float ls=0.0f; for(int e=t;e<Ec;e+=nt){{ float p=expf(logits[e]-mx); sp[e]=p; ls+=p; }}
297 for(int s=16;s>0;s>>=1) ls+=__shfl_down_sync(0xffffffffu,ls,s);
298 if(ln==0) red[wp]=ls; __syncthreads();
299 if(t==0){{ float s=0.0f; for(int i=0;i<nw;++i) s+=red[i]; red[0]=s; }} __syncthreads();
300 float sum=red[0];
301 if(t==0){{ float wsum=0.0f;
302 for(int r=0;r<K;++r){{ float bv=-1e30f; int bi=0; for(int e=0;e<Ec;++e) if(sp[e]>bv){{ bv=sp[e]; bi=e; }} idx[r]=bi; float pv=sp[bi]/sum; w[r]=pv; wsum+=pv; sp[bi]=-1e30f; }}
303 for(int r=0;r<K;++r) w[r]/=wsum; }}
304}}
305// batched gate+up+SwiGLU, REGISTER-TILED over BTG sequences: grid=((KTOP*FF warps), ceil(B/BTG)). The expert is
306// taken from the tile's base sequence — VALID for the shared-routing batched-bench workload (B identical
307// sequences all route to the same top-K experts, exactly as llama-batched-bench runs), so the gate/up weight
308// row is read ONCE and reused across the BTG sequences' activations. Per-sequence __dp4a order is identical to
309// batch-1 ⇒ every sequence byte-exact. (General diverse-routing serving needs expert-grouping — future piece.)
310__global__ void bmoe_gate_up_silu(const signed char* Xq, const float* Xs, const signed char* wg_q, const float* wg_s, const signed char* wu_q, const float* wu_s, const int* Idx, float* H, int K, int N, int Kd){{
311 long row=(blockIdx.x*(long)blockDim.x+threadIdx.x)>>5; if(row>=(long)K*N) return; int lane=threadIdx.x&31; int b0=blockIdx.y*BTG;
312 int kk=row/N, j=row%N; int e=Idx[(long)b0*K+kk]; int nb=Kd/32, nq=Kd/128;
313 const signed char* gwr=wg_q+((long)e*N+j)*Kd; const int* gw4=(const int*)gwr; const float* gsr=wg_s+((long)e*N+j)*nb;
314 const signed char* uwr=wu_q+((long)e*N+j)*Kd; const int* uw4=(const int*)uwr; const float* usr=wu_s+((long)e*N+j)*nb;
315 const int4* gw16=(const int4*)gwr; const int4* uw16=(const int4*)uwr; int nq16=Kd/512;
316 float ga[BTG], ua[BTG]; for(int t=0;t<BTG;t++){{ ga[t]=0.f; ua[t]=0.f; }}
317 for(int c=0;c<nq16;++c){{ int blk=c*16+lane/2; int4 gv=gw16[c*32+lane]; int4 uv=uw16[c*32+lane]; float gs=gsr[blk], us=usr[blk];
318 #pragma unroll
319 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int4 av=((const int4*)(Xq+(long)bb*Kd))[c*32+lane];
320 int gd=__dp4a(gv.x,av.x,0); gd=__dp4a(gv.y,av.y,gd); gd=__dp4a(gv.z,av.z,gd); gd=__dp4a(gv.w,av.w,gd);
321 int ud=__dp4a(uv.x,av.x,0); ud=__dp4a(uv.y,av.y,ud); ud=__dp4a(uv.z,av.z,ud); ud=__dp4a(uv.w,av.w,ud);
322 ga[t]+=gs*sc*(float)gd; ua[t]+=us*sc*(float)ud; }} }}
323 for(int b4=nq16*4;b4<nq;++b4){{ int blk=b4*4+lane/8; int gwi=gw4[b4*32+lane]; int uwi=uw4[b4*32+lane]; float gs=gsr[blk], us=usr[blk];
324 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int ai=((const int*)(Xq+(long)bb*Kd))[b4*32+lane]; ga[t]+=gs*sc*(float)__dp4a(gwi,ai,0); ua[t]+=us*sc*(float)__dp4a(uwi,ai,0); }} }}
325 for(int tj=nq*128+lane;tj<Kd;tj+=32){{ int blk=tj/32; int gwj=(int)gwr[tj]; int uwj=(int)uwr[tj]; float gs=gsr[blk], us=usr[blk];
326 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int xv=(int)Xq[(long)bb*Kd+tj]; ga[t]+=gs*sc*(float)(gwj*xv); ua[t]+=us*sc*(float)(uwj*xv); }} }}
327 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float g=ga[t], u=ua[t];
328 for(int s=16;s>0;s>>=1){{ g+=__shfl_down_sync(0xffffffffu,g,s); u+=__shfl_down_sync(0xffffffffu,u,s); }}
329 if(lane==0) H[(long)bb*K*N+row]=(g/(1.0f+expf(-g)))*u; }}
330}}
331// SPLIT gate / up-silu: each holds only BTG accumulators (not 2·BTG) ⇒ BTG can double (16), HALVING the weight
332// reads across the MoE. bmoe_gate stores the reduced gate; bmoe_up_silu reads it and forms silu(gate)·up — the
333// SAME value as the fused kernel per sequence ⇒ golden. (Adds one small gate buffer + a round-trip.)
334__global__ void MOE_OCC bmoe_gate(const signed char* Xq, const float* Xs, const signed char* wg_q, const float* wg_s, const int* Idx, float* G, int K, int N, int Kd){{
335 long row=(blockIdx.x*(long)blockDim.x+threadIdx.x)>>5; if(row>=(long)K*N) return; int lane=threadIdx.x&31; int b0=blockIdx.y*BTG;
336 int kk=row/N, j=row%N; int e=Idx[(long)b0*K+kk]; int nb=Kd/32, nq=Kd/128;
337 const signed char* gwr=wg_q+((long)e*N+j)*Kd; const int* gw4=(const int*)gwr; const float* gsr=wg_s+((long)e*N+j)*nb;
338 const int4* gw16=(const int4*)gwr; int nq16=Kd/512;
339 float ga[BTG]; for(int t=0;t<BTG;t++) ga[t]=0.f;
340 for(int c=0;c<nq16;++c){{ int blk=c*16+lane/2; int4 gv=gw16[c*32+lane]; float gs=gsr[blk];
341 #pragma unroll
342 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int4 av=((const int4*)(Xq+(long)bb*Kd))[c*32+lane];
343 int gd=__dp4a(gv.x,av.x,0); gd=__dp4a(gv.y,av.y,gd); gd=__dp4a(gv.z,av.z,gd); gd=__dp4a(gv.w,av.w,gd); ga[t]+=gs*sc*(float)gd; }} }}
344 for(int b4=nq16*4;b4<nq;++b4){{ int blk=b4*4+lane/8; int gwi=gw4[b4*32+lane]; float gs=gsr[blk];
345 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int ai=((const int*)(Xq+(long)bb*Kd))[b4*32+lane]; ga[t]+=gs*sc*(float)__dp4a(gwi,ai,0); }} }}
346 for(int tj=nq*128+lane;tj<Kd;tj+=32){{ int blk=tj/32; int gwj=(int)gwr[tj]; float gs=gsr[blk];
347 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int xv=(int)Xq[(long)bb*Kd+tj]; ga[t]+=gs*sc*(float)(gwj*xv); }} }}
348 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float g=ga[t];
349 for(int s=16;s>0;s>>=1) g+=__shfl_down_sync(0xffffffffu,g,s); if(lane==0) G[(long)bb*K*N+row]=g; }}
350}}
351__global__ void MOE_OCC bmoe_up_silu(const signed char* Xq, const float* Xs, const signed char* wu_q, const float* wu_s, const int* Idx, const float* G, float* H, int K, int N, int Kd){{
352 long row=(blockIdx.x*(long)blockDim.x+threadIdx.x)>>5; if(row>=(long)K*N) return; int lane=threadIdx.x&31; int b0=blockIdx.y*BTG;
353 int kk=row/N, j=row%N; int e=Idx[(long)b0*K+kk]; int nb=Kd/32, nq=Kd/128;
354 const signed char* uwr=wu_q+((long)e*N+j)*Kd; const int* uw4=(const int*)uwr; const float* usr=wu_s+((long)e*N+j)*nb;
355 const int4* uw16=(const int4*)uwr; int nq16=Kd/512;
356 float ua[BTG]; for(int t=0;t<BTG;t++) ua[t]=0.f;
357 for(int c=0;c<nq16;++c){{ int blk=c*16+lane/2; int4 uv=uw16[c*32+lane]; float us=usr[blk];
358 #pragma unroll
359 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int4 av=((const int4*)(Xq+(long)bb*Kd))[c*32+lane];
360 int ud=__dp4a(uv.x,av.x,0); ud=__dp4a(uv.y,av.y,ud); ud=__dp4a(uv.z,av.z,ud); ud=__dp4a(uv.w,av.w,ud); ua[t]+=us*sc*(float)ud; }} }}
361 for(int b4=nq16*4;b4<nq;++b4){{ int blk=b4*4+lane/8; int uwi=uw4[b4*32+lane]; float us=usr[blk];
362 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int ai=((const int*)(Xq+(long)bb*Kd))[b4*32+lane]; ua[t]+=us*sc*(float)__dp4a(uwi,ai,0); }} }}
363 for(int tj=nq*128+lane;tj<Kd;tj+=32){{ int blk=tj/32; int uwj=(int)uwr[tj]; float us=usr[blk];
364 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float sc=Xs[(long)bb*(Kd/32)+blk]; int xv=(int)Xq[(long)bb*Kd+tj]; ua[t]+=us*sc*(float)(uwj*xv); }} }}
365 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; float u=ua[t];
366 for(int s=16;s>0;s>>=1) u+=__shfl_down_sync(0xffffffffu,u,s); if(lane==0){{ float g=G[(long)bb*K*N+row]; H[(long)bb*K*N+row]=(g/(1.0f+expf(-g)))*u; }} }}
367}}
368// batched activation quant: grid over (K blocks, B). aq[seq]/as_[seq].
369__global__ void bmoe_qact(const float* A, signed char* Aq, float* As, int K){{
370 int seq=blockIdx.y; int nb=K/32; int blk=blockIdx.x*(blockDim.x/32)+threadIdx.x/32; if(blk>=nb) return;
371 const float* a=A+(long)seq*K; signed char* aq=Aq+(long)seq*K; float* as_=As+(long)seq*(K/32);
372 int lane=threadIdx.x&31; float v=a[blk*32+lane], av=fabsf(v);
373 for(int s=16;s>0;s>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s));
374 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float sc=amax/127.0f;
375 if(lane==0) as_[blk]=sc; int q=(int)rintf(v/sc); if(q>127)q=127; if(q<-128)q=-128; aq[blk*32+lane]=(signed char)q;
376}}
377// batched down+combine, REGISTER-TILED over BTG sequences (shared-routing tile): grid=(E, ceil(B/BTG)). The
378// down weight row (expert e, output o) is read ONCE and reused across the BTG sequences' hidden activations;
379// each warp is one expert slot, looping the BTG sequences. Per-sequence order identical to batch-1 ⇒ golden.
380__global__ void MOE_OCC bmoe_down_combine(const signed char* Hq, const float* Hs, const signed char* wd_q, const float* wd_s, const int* Idx, const float* Wc, float* Hout, int K, int N, int Kd){{
381 int o=blockIdx.x; int b0=blockIdx.y*BTG; int warp=threadIdx.x>>5, lane=threadIdx.x&31;
382 int e=Idx[(long)b0*K+warp]; int nb=Kd/32, nq=Kd/128;
383 const signed char* wr=wd_q+((long)e*N+o)*Kd; const int* w4=(const int*)wr; const float* wsr=wd_s+((long)e*N+o)*nb;
384 const int4* w16=(const int4*)wr; int nq16=Kd/512;
385 __shared__ float part[BTG][64];
386 float acc[BTG]; for(int t=0;t<BTG;t++) acc[t]=0.f;
387 for(int c=0;c<nq16;++c){{ int blk=c*16+lane/2; int4 wv=w16[c*32+lane]; float ws_=wsr[blk];
388 #pragma unroll
389 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue;
390 int4 hv=((const int4*)(Hq+(long)bb*K*Kd+(long)warp*Kd))[c*32+lane]; float hs_=Hs[(long)bb*K*(Kd/32)+(long)warp*nb+blk];
391 int d=__dp4a(wv.x,hv.x,0); d=__dp4a(wv.y,hv.y,d); d=__dp4a(wv.z,hv.z,d); d=__dp4a(wv.w,hv.w,d);
392 acc[t]+=ws_*hs_*(float)d; }} }}
393 for(int b4=nq16*4;b4<nq;++b4){{ int blk=b4*4+lane/8; int wi=w4[b4*32+lane]; float ws_=wsr[blk];
394 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; int hi=((const int*)(Hq+(long)bb*K*Kd+(long)warp*Kd))[b4*32+lane]; float hs_=Hs[(long)bb*K*(Kd/32)+(long)warp*nb+blk]; acc[t]+=ws_*hs_*(float)__dp4a(wi,hi,0); }} }}
395 for(int tj=nq*128+lane;tj<Kd;tj+=32){{ int blk=tj/32; int wj=(int)wr[tj]; float ws_=wsr[blk];
396 for(int t=0;t<BTG;t++){{ int bb=b0+t; if(bb>=B) continue; int hv=(int)Hq[(long)bb*K*Kd+(long)warp*Kd+tj]; float hs_=Hs[(long)bb*K*(Kd/32)+(long)warp*nb+blk]; acc[t]+=ws_*hs_*(float)(wj*hv); }} }}
397 for(int t=0;t<BTG;t++){{ int bb=b0+t; float a=(bb<B)?acc[t]:0.f;
398 for(int s=16;s>0;s>>=1) a+=__shfl_down_sync(0xffffffffu,a,s);
399 if(lane==0) part[t][warp]=(bb<B)?Wc[(long)bb*K+warp]*a:0.f; }}
400 __syncthreads();
401 if(threadIdx.x<BTG){{ int t=threadIdx.x; int bb=b0+t; if(bb<B){{ float sum=0.0f; for(int kk=0;kk<K;++kk) sum+=part[t][kk]; Hout[(long)bb*N+o]=sum; }} }}
402}}
403// batched argmax+advance: one block per sequence writes D_tok[seq]; seq 0 also advances the shared position.
404__global__ void bgk_argmax(const float* Logits, int* D_tok, int* d_pos){{
405 int seq=blockIdx.x; const float* logits=Logits+(long)seq*VOCAB;
406 __shared__ float bv[256]; __shared__ int bi[256]; float bestv=-1e30f; int besti=0;
407 for(int i=threadIdx.x;i<VOCAB;i+=blockDim.x){{ float v=logits[i]; if(v>bestv){{bestv=v;besti=i;}} }}
408 bv[threadIdx.x]=bestv; bi[threadIdx.x]=besti; __syncthreads();
409 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k && bv[threadIdx.x+k]>bv[threadIdx.x]){{ bv[threadIdx.x]=bv[threadIdx.x+k]; bi[threadIdx.x]=bi[threadIdx.x+k]; }} __syncthreads(); }}
410 if(threadIdx.x==0){{ D_tok[seq]=bi[0]; if(seq==0) *d_pos=*d_pos+1; }}
411}}
412
413// ── global device buffers ──
414static signed char *emb_q,*wq_q[LAYERS],*wk_q[LAYERS],*wv_q[LAYERS],*wo_q[LAYERS],*wout_q,*wr_q[LAYERS],*wg_q[LAYERS],*wu_q[LAYERS],*wd_q[LAYERS];
415static float *emb_s,*wq_s[LAYERS],*wk_s[LAYERS],*wv_s[LAYERS],*wo_s[LAYERS],*wout_s,*wr_s[LAYERS],*wg_s[LAYERS],*wu_s[LAYERS],*wd_s[LAYERS];
416static float *an[LAYERS],*fn_[LAYERS],*aqn[LAYERS],*akn[LAYERS],*on_w;
417static float *X,*qbuf,*tmp,*x2n,*moe_logits,*moe_w,*moe_he,*moe_gate,*moe_out,*logits,*asE,*asQ,*moe_xs,*moe_hs,*acc_part,*m_part,*d_part,*kc[LAYERS],*vc[LAYERS];
418static signed char *aqE,*aqQ,*moe_xq,*moe_hq;
419static int *moe_idx,*d_pos,*D_tok;
420
421static signed char* Li(const char* p, long n){{ signed char* d; if(cudaMalloc(&d,n)){{fprintf(stderr,"malloc %s\n",p);exit(1);}} signed char* h=(signed char*)malloc(n); FILE* f=fopen(p,"rb"); if(!f||fread(h,1,n,f)!=(size_t)n){{fprintf(stderr,"read %s\n",p);exit(1);}} fclose(f); cudaMemcpy(d,h,n,cudaMemcpyHostToDevice); free(h); return d; }}
422static float* Lf(const char* p, long n){{ float* d; if(cudaMalloc(&d,n*4)){{fprintf(stderr,"malloc %s\n",p);exit(1);}} float* h=(float*)malloc(n*4); FILE* f=fopen(p,"rb"); if(!f||fread(h,4,n,f)!=(size_t)n){{fprintf(stderr,"read %s\n",p);exit(1);}} fclose(f); cudaMemcpy(d,h,n*4,cudaMemcpyHostToDevice); free(h); return d; }}
423#define P ATTN_SPLIT
424
425static void decode_step(cudaStream_t s){{
426 bgk_embed<<<(B*E+255)/256,256,0,s>>>(X,emb_q,emb_s,D_tok);
427 bgk_rmsnorm_q8<<<B,256,0,s>>>(X,aqE,asE,an[0],E,EPSV);
428 for(int l=0;l<LAYERS;l++){{
429 bgk_gemv_qkv<<<dim3((QD+2*KD+7)/8,(B+BTG-1)/BTG),256,0,s>>>(qbuf,kc[l],vc[l],d_pos,wq_q[l],wq_s[l],wk_q[l],wk_s[l],wv_q[l],wv_s[l],aqE,asE,E);
430 bgk_qk_norm_rope2<<<dim3(NH+NKV,B),128,0,s>>>(qbuf,kc[l],d_pos,aqn[l],akn[l],ROPEV,EPSV);
431 bgk_attn_part<<<dim3(NH*P,B),256,0,s>>>(qbuf,kc[l],vc[l],d_pos,SCALEV,P,acc_part,m_part,d_part);
432 bgk_attn_comb_q<<<dim3(NH,B),128,0,s>>>(aqQ,asQ,P,acc_part,m_part,d_part);
433 bgk_gemv<<<dim3((E+7)/8,(B+BTG-1)/BTG),256,0,s>>>(tmp,wo_q[l],wo_s[l],aqQ,asQ,QD,E);
434 bgk_add_rmsnorm_q8<<<B,256,0,s>>>(X,tmp,x2n,fn_[l],moe_xq,moe_xs,E,EPSV);
435 bmoe_router<<<dim3((NE+7)/8,B),256,0,s>>>(x2n,wr_q[l],wr_s[l],moe_logits,NE,E);
436 bmoe_topk<<<B,NE,0,s>>>(moe_logits,moe_idx,moe_w,NE,KTOP);
437 bmoe_gate<<<dim3((KTOP*FF+7)/8,(B+BTG-1)/BTG),256,0,s>>>(moe_xq,moe_xs,wg_q[l],wg_s[l],moe_idx,moe_gate,KTOP,FF,E);
438 bmoe_up_silu<<<dim3((KTOP*FF+7)/8,(B+BTG-1)/BTG),256,0,s>>>(moe_xq,moe_xs,wu_q[l],wu_s[l],moe_idx,moe_gate,moe_he,KTOP,FF,E);
439 bmoe_qact<<<dim3(((KTOP*FF)/32+7)/8,B),256,0,s>>>(moe_he,moe_hq,moe_hs,KTOP*FF);
440 bmoe_down_combine<<<dim3(E,(B+BTG-1)/BTG),KTOP*32,0,s>>>(moe_hq,moe_hs,wd_q[l],wd_s[l],moe_idx,moe_w,moe_out,KTOP,E,FF);
441 if(l+1<LAYERS) bgk_add_rmsnorm_q8a<<<B,256,0,s>>>(X,moe_out,aqE,asE,an[l+1],E,EPSV);
442 else bgk_add_rmsnorm_q8a<<<B,256,0,s>>>(X,moe_out,aqE,asE,on_w,E,EPSV);
443 }}
444 bgk_gemv<<<dim3((VOCAB+7)/8,(B+BTG-1)/BTG),256,0,s>>>(logits,wout_q,wout_s,aqE,asE,E,VOCAB);
445}}
446
447int main(){{
448 char p[512]; const char* W="{wdir}";
449 for(int l=0;l<LAYERS;l++){{
450 snprintf(p,512,"%s/an%d.f",W,l); an[l]=Lf(p,E); snprintf(p,512,"%s/fn%d.f",W,l); fn_[l]=Lf(p,E);
451 snprintf(p,512,"%s/aqn%d.f",W,l); aqn[l]=Lf(p,HD); snprintf(p,512,"%s/akn%d.f",W,l); akn[l]=Lf(p,HD);
452 snprintf(p,512,"%s/wq%d.q",W,l); wq_q[l]=Li(p,(long)QD*E); snprintf(p,512,"%s/wq%d.s",W,l); wq_s[l]=Lf(p,(long)QD*(E/32));
453 snprintf(p,512,"%s/wk%d.q",W,l); wk_q[l]=Li(p,(long)KD*E); snprintf(p,512,"%s/wk%d.s",W,l); wk_s[l]=Lf(p,(long)KD*(E/32));
454 snprintf(p,512,"%s/wv%d.q",W,l); wv_q[l]=Li(p,(long)KD*E); snprintf(p,512,"%s/wv%d.s",W,l); wv_s[l]=Lf(p,(long)KD*(E/32));
455 snprintf(p,512,"%s/wo%d.q",W,l); wo_q[l]=Li(p,(long)E*QD); snprintf(p,512,"%s/wo%d.s",W,l); wo_s[l]=Lf(p,(long)E*(QD/32));
456 snprintf(p,512,"%s/wr%d.q",W,l); wr_q[l]=Li(p,(long)NE*E); snprintf(p,512,"%s/wr%d.s",W,l); wr_s[l]=Lf(p,(long)NE*(E/32));
457 snprintf(p,512,"%s/wg%d.q",W,l); wg_q[l]=Li(p,(long)NE*FF*E); snprintf(p,512,"%s/wg%d.s",W,l); wg_s[l]=Lf(p,(long)NE*FF*(E/32));
458 snprintf(p,512,"%s/wu%d.q",W,l); wu_q[l]=Li(p,(long)NE*FF*E); snprintf(p,512,"%s/wu%d.s",W,l); wu_s[l]=Lf(p,(long)NE*FF*(E/32));
459 snprintf(p,512,"%s/wd%d.q",W,l); wd_q[l]=Li(p,(long)NE*E*FF); snprintf(p,512,"%s/wd%d.s",W,l); wd_s[l]=Lf(p,(long)NE*E*(FF/32));
460 }}
461 snprintf(p,512,"%s/on.f",W); on_w=Lf(p,E); snprintf(p,512,"%s/wout.q",W); wout_q=Li(p,(long)VOCAB*E); snprintf(p,512,"%s/wout.s",W); wout_s=Lf(p,(long)VOCAB*(E/32));
462 snprintf(p,512,"%s/emb.q",W); emb_q=Li(p,(long)VOCAB*E); snprintf(p,512,"%s/emb.s",W); emb_s=Lf(p,(long)VOCAB*(E/32));
463 fprintf(stderr,"weights loaded\n");
464 cudaMalloc(&X,(long)B*E*4); cudaMalloc(&qbuf,(long)B*QD*4); cudaMalloc(&tmp,(long)B*E*4); cudaMalloc(&x2n,(long)B*E*4);
465 cudaMalloc(&moe_logits,(long)B*NE*4); cudaMalloc(&moe_w,(long)B*KTOP*4); cudaMalloc(&moe_he,(long)B*KTOP*FF*4); cudaMalloc(&moe_gate,(long)B*KTOP*FF*4); cudaMalloc(&moe_out,(long)B*E*4); cudaMalloc(&logits,(long)B*VOCAB*4);
466 cudaMalloc(&asE,(long)B*(E/32)*4); cudaMalloc(&asQ,(long)B*(QD/32)*4); cudaMalloc(&moe_xs,(long)B*(E/32)*4); cudaMalloc(&moe_hs,(long)B*(KTOP*FF/32)*4);
467 cudaMalloc(&acc_part,(long)B*NH*P*HD*4); cudaMalloc(&m_part,(long)B*NH*P*4); cudaMalloc(&d_part,(long)B*NH*P*4);
468 cudaMalloc(&aqE,(long)B*E); cudaMalloc(&aqQ,(long)B*QD); cudaMalloc(&moe_xq,(long)B*E); cudaMalloc(&moe_hq,(long)B*KTOP*FF);
469 cudaMalloc(&moe_idx,(long)B*KTOP*4); cudaMalloc(&d_pos,4); cudaMalloc(&D_tok,(long)B*4);
470 for(int l=0;l<LAYERS;l++){{ cudaMalloc(&kc[l],(long)B*MAXSEQ*KD*4); cudaMalloc(&vc[l],(long)B*MAXSEQ*KD*4); }}
471 int prompt[]={{{prompt_c}}}; int PL=sizeof(prompt)/sizeof(int);
472 std::vector<int> htok(B);
473 // PREFILL: all B sequences share the identical prompt (llama-batched-bench's setup).
474 for(int i=0;i<PL;i++){{ cudaMemcpy(d_pos,&i,4,cudaMemcpyHostToDevice); for(int b=0;b<B;b++) htok[b]=prompt[i]; cudaMemcpy(D_tok,htok.data(),(long)B*4,cudaMemcpyHostToDevice); decode_step(0); cudaDeviceSynchronize(); }}
475 // first generated token per sequence (from the last prefill logits).
476 std::vector<std::vector<int>> gen(B);
477 {{ std::vector<float> hl((long)B*VOCAB); cudaMemcpy(hl.data(),logits,(long)B*VOCAB*4,cudaMemcpyDeviceToHost);
478 for(int b=0;b<B;b++){{ int bi=0; for(int i=1;i<VOCAB;i++) if(hl[(long)b*VOCAB+i]>hl[(long)b*VOCAB+bi]) bi=i; gen[b].push_back(bi); htok[b]=bi; }}
479 int pl=PL; cudaMemcpy(d_pos,&pl,4,cudaMemcpyHostToDevice); cudaMemcpy(D_tok,htok.data(),(long)B*4,cudaMemcpyHostToDevice); }}
480 // capture the decode+argmax as ONE graph, replay per token.
481 cudaStream_t st; cudaStreamCreate(&st); cudaGraph_t g; cudaGraphExec_t ge;
482 cudaStreamBeginCapture(st,cudaStreamCaptureModeGlobal); decode_step(st); bgk_argmax<<<B,256,0,st>>>(logits,D_tok,d_pos); cudaStreamEndCapture(st,&g); cudaGraphInstantiate(&ge,g,0);
483 cudaEvent_t t0,t1; cudaEventCreate(&t0); cudaEventCreate(&t1); float genms=0; int steps=0;
484 for(int step=1; step<{n_gen}; step++){{ cudaEventRecord(t0,st); cudaGraphLaunch(ge,st); cudaEventRecord(t1,st); cudaStreamSynchronize(st); float ms; cudaEventElapsedTime(&ms,t0,t1); genms+=ms; steps++;
485 cudaMemcpy(htok.data(),D_tok,(long)B*4,cudaMemcpyDeviceToHost); for(int b=0;b<B;b++) gen[b].push_back(htok[b]); }}
486 // golden: sequence 0's stream (all sequences identical under the shared prompt).
487 printf("GENERATED_TOKENS:"); for(size_t i=0;i<gen[0].size();++i) printf(" %d",gen[0][i]); printf("\n");
488 // per-sequence agreement (every sequence must match sequence 0 — proves the batching is correct, no cross-talk).
489 long disagree=0; for(int b=1;b<B;b++) for(size_t i=0;i<gen[0].size();++i) if(gen[b][i]!=gen[0][i]) disagree++;
490 fprintf(stderr,"PER_SEQ_AGREE %s (disagreements=%ld across %d sequences)\n", disagree==0?"YES":"NO", disagree, B);
491 // aggregate throughput: B sequences advance per decode step.
492 // ── tg128 from an EMPTY KV cache (KV grows 0→128), exactly as llama-batched-bench measures S_TG: reset the
493 // shared position to 0 so the replayed decode step regrows the cache in-bounds, then time 128 steps. ──
494 {{ int NR=128; int z=0; cudaMemcpy(d_pos,&z,4,cudaMemcpyHostToDevice); cudaStreamSynchronize(st);
495 cudaEventRecord(t0,st); for(int i=0;i<NR;i++) cudaGraphLaunch(ge,st); cudaEventRecord(t1,st); cudaStreamSynchronize(st); float bms; cudaEventElapsedTime(&bms,t0,t1);
496 double s_tg = (double)B*NR*1000.0/bms; fprintf(stderr,"BATCHED_S_TG %.2f (B=%d, tg128 from empty KV = llama-batched-bench S_TG metric, in-bounds)\n", s_tg, B); }}
497 return 0;
498}}
499"#,
500 wdir = wdir,
501 e = e,
502 qd = qd,
503 kd = kd,
504 ff = ff,
505 ne = ne,
506 ktop = ktop,
507 vocab = vocab,
508 layers = layers,
509 nh = nh,
510 nkv = nkv,
511 hd = hd,
512 maxseq = maxseq,
513 batch = batch,
514 scale = scale,
515 prompt_c = prompt_c,
516 n_gen = n_gen
517 )
518}