KernelBench cuda · RTX PRO 6000
Grid + MinGRU SPS GPT-6.1 Sol
30.5%geomean peak fraction across shapes
The whole rollout is one cooperative CUDA kernel: each CTA encodes 16 environments, runs the three MinGRU layers on fp16 tensor cores with a hi/lo split of both operands (three mma per product, fp32 accumulate) to recover near-fp32 accuracy, takes greedy actions, and does food respawn after one grid barrier per step. Recurrent state stays fp32.
harnesscodexagent session41mtotal wall42mcheck15sbenchmark2soutput tokens64,996gpu-lock wait0sgpu-lock held21sregimethroughput
Per-shape vs governing ceilingeach shape graded against whichever binds — bf16 compute or HBM bandwidth
No per-shape benchmark data archived for this run.
Kernel source (redacted)
"""CUDA grid-foraging rollout with a globally synchronized MinGRU policy."""
import os
from pathlib import Path
import torch
from torch import nn
from torch.nn import functional as F
from torch.utils.cpp_extension import load_inline
_ROOT = Path(__file__).resolve().parent
os.environ.setdefault('TORCH_CUDA_ARCH_LIST', '12.0')
os.environ.setdefault('MAX_JOBS', '4')
_CPP = r'''
#include <torch/extension.h>
std::vector<at::Tensor> gru_cuda(at::Tensor,at::Tensor,at::Tensor,int);
std::vector<at::Tensor> env_cuda(at::Tensor,at::Tensor,at::Tensor,at::Tensor);
void rollout_cuda(at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,at::Tensor,int);
PYBIND11_MODULE(TORCH_EXTENSION_NAME,m) {
m.def("gru", &gru_cuda); m.def("env", &env_cuda); m.def("rollout", &rollout_cuda);
}
'''
_CUDA = r'''
#include <ATen/ATen.h>
#include <c10/cuda/CUDAGuard.h>
#include <c10/cuda/CUDAStream.h>
#include <c10/cuda/CUDAException.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cuda_fp16.h>
#include <cooperative_groups.h>
#include <vector>
namespace cg=cooperative_groups;
using at::Tensor;
__device__ __forceinline__ float sig(float x) { return 1.f/(1.f+expf(-x)); }
__global__ void gru_kernel(const float* h,const float* gates,const float* state,float* hn,float* sn,int n,int layer) {
int i=blockIdx.x*blockDim.x+threadIdx.x;
if(i>=n*256) return;
int e=i/256,c=i%256;
float zh=gates[e*768+c],zg=gates[e*768+256+c],zp=gates[e*768+512+c];
float st=state[e*768+layer*256+c];
float o=st+sig(zg)*(tanhf(zh)-st),p=sig(zp);
sn[e*256+c]=o;
hn[i]=p*o+(1.f-p)*h[i];
}
std::vector<Tensor> gru_cuda(Tensor h,Tensor gates,Tensor state,int layer) {
c10::cuda::CUDAGuard guard(h.device());
auto hn=at::empty_like(h),sn=at::empty_like(h);
gru_kernel<<<(h.numel()+255)/256,256,0,c10::cuda::getCurrentCUDAStream()>>>(h.data_ptr<float>(),gates.data_ptr<float>(),state.data_ptr<float>(),hn.data_ptr<float>(),sn.data_ptr<float>(),h.size(0),layer);
C10_CUDA_KERNEL_LAUNCH_CHECK(); return {hn,sn};
}
__global__ void move_kernel(const float* a,const float* f,const int64_t* act,float* ao,unsigned char* hits,float* rew,int* any,int n) {
int i=blockIdx.x*blockDim.x+threadIdx.x; if(i>=n)return;
int ac=act[i]; float x=fminf(10.f,fmaxf(0.f,a[i*2]+(ac==3)-(ac==2))),y=fminf(10.f,fmaxf(0.f,a[i*2+1]+(ac==1)-(ac==0)));
ao[i*2]=x;ao[i*2+1]=y;
bool hit=(x==f[i*2] && y==f[i*2+1]);hits[i]=hit;rew[i]=hit;
if(hit)atomicExch(any,1);
}
__device__ __forceinline__ unsigned long long lcg(unsigned long long x) { return (x*6364136223846793005ULL+1ULL)&0x7fffffffffffffffULL; }
__global__ void respawn_kernel(const float* f,const unsigned long long* rng,const unsigned char* hits,const int* any,float* fo,unsigned long long* ro,int n) {
int i=blockIdx.x*blockDim.x+threadIdx.x; if(i>=n)return;
unsigned long long r=rng[i];float x=f[2*i],y=f[2*i+1];
if(*any){r=lcg(r);if(hits[i])x=r%11ULL;r=lcg(r);if(hits[i])y=r%11ULL;}
fo[2*i]=x;fo[2*i+1]=y;ro[i]=r;
}
std::vector<Tensor> env_cuda(Tensor a,Tensor f,Tensor act,Tensor rng) {
c10::cuda::CUDAGuard guard(a.device());
auto ao=at::empty_like(a),fo=at::empty_like(f),ro=at::empty_like(rng),rew=at::empty({a.size(0)},a.options());
auto hits=at::empty({a.size(0)},a.options().dtype(at::kByte)),any=at::zeros({1},a.options().dtype(at::kInt));
auto stream=c10::cuda::getCurrentCUDAStream();int n=a.size(0);
move_kernel<<<(n+255)/256,256,0,stream>>>(a.data_ptr<float>(),f.data_ptr<float>(),act.data_ptr<int64_t>(),ao.data_ptr<float>(),hits.data_ptr<unsigned char>(),rew.data_ptr<float>(),any.data_ptr<int>(),n);
respawn_kernel<<<(n+255)/256,256,0,stream>>>(f.data_ptr<float>(),(const unsigned long long*)rng.data_ptr<int64_t>(),hits.data_ptr<unsigned char>(),any.data_ptr<int>(),fo.data_ptr<float>(),(unsigned long long*)ro.data_ptr<int64_t>(),n);
C10_CUDA_KERNEL_LAUNCH_CHECK();return {ao,fo,rew,ro};
}
__device__ __forceinline__ void mma(float* c,const unsigned* a,const unsigned* b) {
asm volatile("mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 {%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%0,%1,%2,%3};"
: "+f"(c[0]),"+f"(c[1]),"+f"(c[2]),"+f"(c[3])
: "r"(a[0]),"r"(a[1]),"r"(a[2]),"r"(a[3]),"r"(b[0]),"r"(b[1]));
}
// Each CTA evaluates 16 environments. The recurrent state is FP32, and the
// matrix products use three FP16 tensor-core products with FP32 accumulation.
// Splitting both operands into a high part and a rounding residual preserves
// FP32 accuracy without rounding recurrent state or highway activations.
__global__ __launch_bounds__(256) void rollout_kernel(
const float* we,const float* be,const unsigned short* wh,const unsigned short* wl,
const float* wa,const float* ba,const float* wv,const float* bv,
int64_t* agent,int64_t* food,unsigned long long* rng,float* state,float* rewards,float* logits,
unsigned char* hits,int* flags,int n,int horizon) {
__shared__ float h[16*264];
__shared__ unsigned short ah[16*264],al[16*264];
int lane=threadIdx.x%32,warp=threadIdx.x/32;
int row=lane/4,col=(lane%4)*2;
auto grid=cg::this_grid();
for(int t=0;t<horizon;t++) {
for(int tile=blockIdx.x;tile*16<n;tile+=gridDim.x) {
int base=tile*16;
for(int i=threadIdx.x;i<4096;i+=256) {
int e=base+i/256,c=i%256;
float z=0.f;
if(e<n){
float x=agent[2*e],y=agent[2*e+1];
float ox=(float)(food[2*e]-agent[2*e])/11.f,oy=(float)(food[2*e+1]-agent[2*e+1])/11.f;
z=be[c]+we[c*4]*ox+we[c*4+1]*oy+we[c*4+2]*(x/10.f)+we[c*4+3]*(y/10.f);
}
int idx=(i/256)*264+c;h[idx]=z;__half hi=__float2half_rn(z);ah[idx]=__half_as_ushort(hi);al[idx]=__half_as_ushort(__float2half_rn(z-__half2float(hi)));
}
__syncthreads();
#pragma unroll
for(int layer=0;layer<3;layer++) {
float acc[3][4][4]={};
#pragma unroll 1
for(int k=0;k<256;k+=16) {
unsigned a[4],ar[4];
const unsigned* ap=(const unsigned*)ah;const unsigned* arp=(const unsigned*)al;
a[0]=ap[(row*264+k+col)/2];a[1]=ap[((row+8)*264+k+col)/2];
a[2]=ap[(row*264+k+col+8)/2];a[3]=ap[((row+8)*264+k+col+8)/2];
ar[0]=arp[(row*264+k+col)/2];ar[1]=arp[((row+8)*264+k+col)/2];
ar[2]=arp[(row*264+k+col+8)/2];ar[3]=arp[((row+8)*264+k+col+8)/2];
#pragma unroll
for(int g=0;g<3;g++) {
#pragma unroll
for(int j=0;j<4;j++) {
int wi=((layer*96+g*32+warp*4+j)*16+k/16)*32+lane;
uint2 bb=((const uint2*)wh)[wi],bbr=((const uint2*)wl)[wi];
unsigned b[2]={bb.x,bb.y},br[2]={bbr.x,bbr.y};
mma(acc[g][j],a,br);mma(acc[g][j],ar,b);mma(acc[g][j],a,b);
}
}
}
__syncthreads();
#pragma unroll
for(int j=0;j<4;j++) {
#pragma unroll
for(int q=0;q<4;q++) {
int r=row+(q/2)*8,c=warp*32+j*8+col+(q%2),idx=r*264+c,e=base+r;
float st=e<n?state[e*768+layer*256+c]:0.f;
float o=st+sig(acc[1][j][q])*(tanhf(acc[0][j][q])-st),p=sig(acc[2][j][q]);
float z=p*o+(1.f-p)*h[idx];
if(e<n)state[e*768+layer*256+c]=o;
h[idx]=z;__half hi=__float2half_rn(z);ah[idx]=__half_as_ushort(hi);al[idx]=__half_as_ushort(__float2half_rn(z-__half2float(hi)));
}
}
__syncthreads();
}
// Two environment rows per warp; action and value head use FP32 SIMT.
#pragma unroll
for(int rr=0;rr<2;rr++) {
int r=warp+rr*8,e=base+r;
float sums[4]={};
#pragma unroll
for(int k=0;k<8;k++) {
int c=lane+k*32;float x=h[r*264+c];
#pragma unroll
for(int a=0;a<4;a++)sums[a]+=x*wa[a*256+c];
}
#pragma unroll
for(int d=16;d>0;d/=2) {
#pragma unroll
for(int a=0;a<4;a++)sums[a]+=__shfl_down_sync(0xffffffff,sums[a],d);
}
if(lane==0 && e<n) {
int action=0;float best=sums[0]+ba[0];
#pragma unroll
for(int a=0;a<4;a++){float z=sums[a]+ba[a];logits[e*4+a]=z;if(z>best){best=z;action=a;}}
int64_t x=agent[e*2]+(action==3)-(action==2),y=agent[e*2+1]+(action==1)-(action==0);
x=x<0?0:(x>10?10:x);y=y<0?0:(y>10?10:y);
agent[e*2]=x;agent[e*2+1]=y;
bool hit=x==food[e*2] && y==food[e*2+1];hits[e]=hit;rewards[e]+=hit;
if(hit)atomicExch(flags+t,1);
}
}
__syncthreads();
}
grid.sync();
if(flags[t]) {
for(int e=blockIdx.x*256+threadIdx.x;e<n;e+=gridDim.x*256) {
unsigned long long r=lcg(rng[e]);if(hits[e])food[e*2]=r%11ULL;
r=lcg(r);if(hits[e])food[e*2+1]=r%11ULL;rng[e]=r;
}
}
grid.sync();
}
}
void rollout_cuda(Tensor we,Tensor be,Tensor wh,Tensor wl,Tensor wa,Tensor ba,Tensor wv,Tensor bv,
Tensor agent,Tensor food,Tensor rng,Tensor state,Tensor rewards,Tensor logits,Tensor flags,int horizon) {
c10::cuda::CUDAGuard guard(agent.device());
auto hits=at::empty({agent.size(0)},agent.options().dtype(at::kByte));
int n=agent.size(0),blocks_per_sm=0,dev=agent.get_device();cudaDeviceProp prop;C10_CUDA_CHECK(cudaGetDeviceProperties(&prop,dev));
C10_CUDA_CHECK(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&blocks_per_sm,rollout_kernel,256,0));
int blocks=std::min((n+15)/16,prop.multiProcessorCount*blocks_per_sm);
const float *pwe=we.data_ptr<float>(),*pbe=be.data_ptr<float>(),*pwa=wa.data_ptr<float>(),*pba=ba.data_ptr<float>(),*pwv=wv.data_ptr<float>(),*pbv=bv.data_ptr<float>();
const unsigned short *pwh=(const unsigned short*)wh.data_ptr<at::Half>(),*pwl=(const unsigned short*)wl.data_ptr<at::Half>();
int64_t *pa=agent.data_ptr<int64_t>(),*pf=food.data_ptr<int64_t>();
auto pr=(unsigned long long*)rng.data_ptr<int64_t>();float *ps=state.data_ptr<float>(),*prew=rewards.data_ptr<float>(),*pl=logits.data_ptr<float>();
auto ph=hits.data_ptr<unsigned char>();auto pflags=flags.data_ptr<int>();
void* args[]={&pwe,&pbe,&pwh,&pwl,&pwa,&pba,&pwv,&pbv,&pa,&pf,&pr,&ps,&prew,&pl,&ph,&pflags,&n,&horizon};
C10_CUDA_CHECK(cudaLaunchCooperativeKernel((void*)rollout_kernel,blocks,256,args,0,c10::cuda::getCurrentCUDAStream()));
}
'''
_EXT = None
def _ext():
global _EXT
if _EXT is None:
build = _ROOT / '.cuda_build'
build.mkdir(exist_ok=True)
_EXT = load_inline(name='grid_rollout_cuda', cpp_sources=_CPP, cuda_sources=_CUDA,
build_directory=str(build), extra_cflags=['-O3'],
extra_cuda_cflags=['-O3', '--use_fast_math', '-lineinfo'], verbose=False)
return _EXT
class Model(nn.Module):
def __init__(self):
super().__init__()
self.w_enc = nn.Parameter(torch.empty(256, 4))
self.b_enc = nn.Parameter(torch.zeros(256))
self.w_gru = nn.Parameter(torch.empty(3, 768, 256))
self.w_a = nn.Parameter(torch.empty(4, 256))
self.b_a = nn.Parameter(torch.zeros(4))
self.w_v = nn.Parameter(torch.empty(1, 256))
self.b_v = nn.Parameter(torch.zeros(1))
self.reset_parameters(0)
def reset_parameters(self, seed=0):
g = torch.Generator(device='cpu').manual_seed(seed)
for p in self.parameters():
tmp = torch.empty(p.shape, dtype=p.dtype, device='cpu')
tmp.normal_(0.0, 0.02, generator=g)
p.data.copy_(tmp)
self._packed = None
def forward(self, obs, state):
return policy_forward(self, obs, state)
def _weights(self):
key = (self.w_gru.data_ptr(), self.w_gru._version)
cached = getattr(self, '_packed', None)
if cached is None or cached[0] != key:
wh = self.w_gru.detach().to(torch.float16)
wl = (self.w_gru.detach() - wh.float()).to(torch.float16)
wh = wh.reshape(3, 96, 8, 16, 2, 4, 2).permute(0, 1, 3, 2, 5, 4, 6).contiguous()
wl = wl.reshape(3, 96, 8, 16, 2, 4, 2).permute(0, 1, 3, 2, 5, 4, 6).contiguous()
self._packed = (key, wh, wl)
return self._packed[1:]
@torch.no_grad()
def policy_forward(model, obs, state):
obs, state = obs.contiguous(), state.contiguous()
h = F.linear(obs, model.w_enc, model.b_enc)
states = []
for layer in range(3):
gates = F.linear(h, model.w_gru[layer])
h, st = _ext().gru(h, gates, state, layer)
states.append(st)
return F.linear(h, model.w_a, model.b_a), torch.stack(states, dim=1), F.linear(h, model.w_v, model.b_v).squeeze(-1)
@torch.no_grad()
def env_step(agent, food, actions, rng_state):
if agent.shape[0] == 0:
return agent.clone(), food.clone(), torch.empty(0, device=agent.device, dtype=torch.float32), rng_state.clone()
a, f, reward, rng = _ext().env(agent.float().contiguous(), food.float().contiguous(),
actions.long().contiguous(), rng_state.contiguous())
return a.to(agent.dtype), f.to(food.dtype), reward, rng
@torch.no_grad()
def run(num_envs: int, horizon: int, seed: int, model=None) -> dict:
if model is None:
model = Model()
model = model.to('cuda:0').eval()
ext = _ext()
g = torch.Generator(device='cpu').manual_seed(seed)
agent = torch.randint(0, 11, (num_envs, 2), generator=g).to('cuda:0')
food = torch.randint(0, 11, (num_envs, 2), generator=g).to('cuda:0')
rng = torch.arange(num_envs, device='cuda:0', dtype=torch.int64) + seed * 10007
state = torch.zeros(num_envs, 3, 256, device='cuda:0')
rewards = torch.zeros(num_envs, device='cuda:0')
logits = torch.zeros(num_envs, 4, device='cuda:0')
flags = torch.zeros(horizon, device='cuda:0', dtype=torch.int32)
wh, wl = model._weights()
if num_envs and horizon:
ext.rollout(model.w_enc, model.b_enc, wh, wl, model.w_a, model.b_a, model.w_v, model.b_v,
agent, food, rng, state, rewards, logits, flags, horizon)
return {'rewards': rewards, 'positions': agent, 'last_logits': logits, 'state': state}
20260930_115512_codex_gpt-6.1-sol_04_grid_mingru_sps