KernelBench cuda · RTX PRO 6000
Grid + MinGRU SPS GPT-6 Sol
64.5%geomean peak fraction across shapes
A captured CUDA graph replays the whole Grid + MinGRU horizon. Authored kernels handle observation encoding, MinGRU activation, greedy action, exact global-hit food respawn, and output positions; cuBLAS performs the three gate matrix multiplies. Graph cache keys include model parameter versions, and reset_parameters clears the cache.
harnesscodexagent session23mtotal wall32mcheck85sbenchmark2soutput tokens55,588gpu-lock wait7mgpu-lock held1sregimethroughput
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 and MinGRU rollout."""
from __future__ import annotations
import os
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.cpp_extension import load_inline
BOARD = 11
HIDDEN = 256
GRU_LAYERS = 3
_CUDA = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda_runtime.h>
#include <cuda_fp16.h>
#include <cmath>
__device__ __forceinline__ int clip11(int x) { return max(0, min(10, x)); }
__device__ __forceinline__ int64_t lcg(int64_t x) {
return (int64_t)(((uint64_t)x * 6364136223846793005ULL + 1ULL) & 0x7fffffffffffffffULL);
}
__global__ void encode_all_half_kernel(const float* agent, const float* food,
const float* w, const float* b, __half* h, int n) {
int k = blockIdx.x * blockDim.x + threadIdx.x;
if (k >= n * 256) return;
int e = k >> 8, j = k & 255;
float x = agent[2*e], y = agent[2*e+1];
float dx = (food[2*e] - x) / 11.0f;
float dy = (food[2*e+1] - y) / 11.0f;
const float* ww = w + 4*j;
float v = b[j] + dx*ww[0] + dy*ww[1] + (x/10.0f)*ww[2] + (y/10.0f)*ww[3];
h[k] = __float2half_rn(v);
}
__global__ void gate_all_half_kernel(const __half* gates, __half* state, __half* h, int layer, int n) {
int e = blockIdx.x*16 + (threadIdx.x >> 5);
int lane = threadIdx.x & 31;
if (e>=n) return;
const __half* g = gates + e*768;
__half* stp = state + e*768 + layer*256;
__half* hp = h + e*256;
#pragma unroll
for (int i=0;i<8;++i) {
int j=lane+32*i;
float st=__half2float(stp[j]);
float zh=__half2float(g[j]);
float zg=__half2float(g[256+j]);
float zp=__half2float(g[512+j]);
float z=1.0f/(1.0f+__expf(-zg));
float out=st+z*(__tanhf(zh)-st);
float p=1.0f/(1.0f+__expf(-zp));
float old=__half2float(hp[j]);
stp[j]=__float2half_rn(out);
hp[j]=__float2half_rn(p*out+(1.0f-p)*old);
}
}
__global__ void advance_kernel(const float* logits, const float* bias, const int64_t* actions,
float* agent, const float* food, float* rewards, unsigned char* hit,
int* anyhit, float* last, int n) {
int e = blockIdx.x * blockDim.x + threadIdx.x;
if (e >= n) return;
int action;
if (actions) {
action = (int)actions[e];
} else {
float best = logits[e*4] + bias[0];
action = 0;
if (last) last[e*4] = best;
#pragma unroll
for (int a = 1; a < 4; ++a) {
float v = logits[e*4+a] + bias[a];
if (last) last[e*4+a] = v;
if (v > best) {best = v; action = a;}
}
}
int x = (int)agent[e*2], y = (int)agent[e*2+1];
x = clip11(x + (action == 3) - (action == 2));
y = clip11(y + (action == 1) - (action == 0));
agent[e*2] = (float)x;
agent[e*2+1] = (float)y;
bool ate = x == (int)food[e*2] && y == (int)food[e*2+1];
hit[e] = (unsigned char)ate;
if (ate) { rewards[e] += 1.0f; atomicOr(anyhit, 1); }
}
__global__ void respawn_kernel(const float* agent, float* food, int64_t* rng,
const unsigned char* hit, const int* anyhit, const float* w, const float* b,
float* h, int n) {
int e = blockIdx.x * blockDim.x + threadIdx.x;
if (e >= n) return;
if (anyhit[0]) {
int64_t r1 = lcg(rng[e]);
int64_t r2 = lcg(r1);
rng[e] = r2;
if (hit[e]) {
food[2*e] = (float)(r1 % 11);
food[2*e+1] = (float)(r2 % 11);
}
}
if (h) {
float x = agent[2*e], y = agent[2*e+1];
float dx = (food[2*e] - x) / 11.0f;
float dy = (food[2*e+1] - y) / 11.0f;
for (int j = 0; j < 256; ++j) {
const float* ww = w + 4*j;
h[e*256+j] = b[j] + dx*ww[0] + dy*ww[1] + (x/10.0f)*ww[2] + (y/10.0f)*ww[3];
}
}
}
__global__ void head_all_half_kernel(const __half* h, const float* w, const float* bias,
float* agent, const float* food, float* rewards, unsigned char* hit,
int* anyhit, float* last, int n) {
int e = blockIdx.x * 8 + (threadIdx.x >> 5);
int lane = threadIdx.x & 31;
if (e >= n) return;
float s0=0.0f, s1=0.0f, s2=0.0f, s3=0.0f;
#pragma unroll
for (int i=0; i<8; ++i) {
int j=lane+32*i;
float v=__half2float(h[e*256+j]);
s0 += v*w[j];
s1 += v*w[256+j];
s2 += v*w[512+j];
s3 += v*w[768+j];
}
for (int offset=16; offset>0; offset>>=1) {
s0 += __shfl_down_sync(0xffffffff,s0,offset);
s1 += __shfl_down_sync(0xffffffff,s1,offset);
s2 += __shfl_down_sync(0xffffffff,s2,offset);
s3 += __shfl_down_sync(0xffffffff,s3,offset);
}
if (lane==0) {
s0+=bias[0]; s1+=bias[1]; s2+=bias[2]; s3+=bias[3];
last[e*4]=s0; last[e*4+1]=s1; last[e*4+2]=s2; last[e*4+3]=s3;
float best=s0; int action=0;
if (s1>best) {best=s1;action=1;}
if (s2>best) {best=s2;action=2;}
if (s3>best) {best=s3;action=3;}
int x=(int)agent[e*2], y=(int)agent[e*2+1];
x=clip11(x+(action==3)-(action==2));
y=clip11(y+(action==1)-(action==0));
agent[e*2]=(float)x; agent[e*2+1]=(float)y;
bool ate=x==(int)food[e*2] && y==(int)food[e*2+1];
hit[e]=(unsigned char)ate;
if (ate) {rewards[e]+=1.0f; atomicOr(anyhit,1);}
}
}
__global__ void respawn_encode_all_half_kernel(const float* agent, float* food, int64_t* rng,
const unsigned char* hit, const int* anyhit, const float* w, const float* b,
__half* h, int n) {
int e = blockIdx.x * 8 + (threadIdx.x >> 5);
int lane = threadIdx.x & 31;
if (e >= n) return;
float x = 0.0f, y = 0.0f, fx = 0.0f, fy = 0.0f;
if (lane == 0) {
x = agent[2*e]; y = agent[2*e+1];
fx = food[2*e]; fy = food[2*e+1];
if (anyhit[0]) {
int64_t r1 = lcg(rng[e]);
int64_t r2 = lcg(r1);
rng[e] = r2;
if (hit[e]) {
fx = (float)(r1 % 11); fy = (float)(r2 % 11);
food[2*e] = fx; food[2*e+1] = fy;
}
}
}
x = __shfl_sync(0xffffffff, x, 0);
y = __shfl_sync(0xffffffff, y, 0);
fx = __shfl_sync(0xffffffff, fx, 0);
fy = __shfl_sync(0xffffffff, fy, 0);
float dx = (fx - x) / 11.0f;
float dy = (fy - y) / 11.0f;
float xx = x / 10.0f, yy = y / 10.0f;
#pragma unroll
for (int i = 0; i < 8; ++i) {
int j = lane + 32*i;
const float* ww = w + 4*j;
h[e*256+j] = __float2half_rn(b[j] + dx*ww[0] + dy*ww[1] + xx*ww[2] + yy*ww[3]);
}
}
__global__ void positions_kernel(const float* agent, int64_t* positions, int n) {
int k=blockIdx.x*blockDim.x+threadIdx.x;
if (k<n*2) positions[k]=(int64_t)agent[k];
}
void encode_all_half(torch::Tensor agent, torch::Tensor food, torch::Tensor w, torch::Tensor b, torch::Tensor h) {
int n=agent.size(0);
encode_all_half_kernel<<<(n*256+255)/256,256,0,at::cuda::getCurrentCUDAStream()>>>(
agent.data_ptr<float>(),food.data_ptr<float>(),w.data_ptr<float>(),b.data_ptr<float>(),
reinterpret_cast<__half*>(h.data_ptr<at::Half>()),n);
}
void gate_all_half(torch::Tensor gates, torch::Tensor state, torch::Tensor h, int layer) {
int n=h.size(0);
gate_all_half_kernel<<<(n+15)/16,512,0,at::cuda::getCurrentCUDAStream()>>>(
reinterpret_cast<const __half*>(gates.data_ptr<at::Half>()),
reinterpret_cast<__half*>(state.data_ptr<at::Half>()),
reinterpret_cast<__half*>(h.data_ptr<at::Half>()),layer,n);
}
void head_all_half(torch::Tensor h, torch::Tensor w, torch::Tensor bias,
torch::Tensor agent, torch::Tensor food, torch::Tensor rewards,
torch::Tensor hit, torch::Tensor anyhit, torch::Tensor last) {
int n=agent.size(0);
cudaMemsetAsync(anyhit.data_ptr<int>(),0,sizeof(int),at::cuda::getCurrentCUDAStream());
head_all_half_kernel<<<(n+7)/8,256,0,at::cuda::getCurrentCUDAStream()>>>(
reinterpret_cast<const __half*>(h.data_ptr<at::Half>()),w.data_ptr<float>(),bias.data_ptr<float>(),
agent.data_ptr<float>(),food.data_ptr<float>(),rewards.data_ptr<float>(),
hit.data_ptr<unsigned char>(),anyhit.data_ptr<int>(),last.data_ptr<float>(),n);
}
void respawn_all_half(torch::Tensor agent, torch::Tensor food, torch::Tensor rng,
torch::Tensor hit, torch::Tensor anyhit, torch::Tensor w, torch::Tensor b, torch::Tensor h) {
int n=agent.size(0);
respawn_encode_all_half_kernel<<<(n+7)/8,256,0,at::cuda::getCurrentCUDAStream()>>>(
agent.data_ptr<float>(),food.data_ptr<float>(),rng.data_ptr<int64_t>(),
hit.data_ptr<unsigned char>(),anyhit.data_ptr<int>(),w.data_ptr<float>(),b.data_ptr<float>(),
reinterpret_cast<__half*>(h.data_ptr<at::Half>()),n);
}
void positions(torch::Tensor agent, torch::Tensor out) {
int n=agent.size(0);
positions_kernel<<<(n*2+255)/256,256,0,at::cuda::getCurrentCUDAStream()>>>(
agent.data_ptr<float>(),out.data_ptr<int64_t>(),n);
}
void advance_actions(torch::Tensor actions, torch::Tensor agent,
torch::Tensor food, torch::Tensor rewards, torch::Tensor hit, torch::Tensor anyhit) {
int n = agent.size(0);
cudaMemsetAsync(anyhit.data_ptr<int>(), 0, sizeof(int), at::cuda::getCurrentCUDAStream());
advance_kernel<<<(n+255)/256,256,0,at::cuda::getCurrentCUDAStream()>>>(
nullptr,nullptr,actions.data_ptr<int64_t>(),agent.data_ptr<float>(),
food.data_ptr<float>(),rewards.data_ptr<float>(),hit.data_ptr<unsigned char>(),
anyhit.data_ptr<int>(),nullptr,n);
}
void respawn(torch::Tensor agent, torch::Tensor food, torch::Tensor rng,
torch::Tensor hit, torch::Tensor anyhit, torch::Tensor w, torch::Tensor b, torch::Tensor h) {
int n=agent.size(0);
respawn_kernel<<<(n+255)/256,256,0,at::cuda::getCurrentCUDAStream()>>>(
agent.data_ptr<float>(),food.data_ptr<float>(),rng.data_ptr<int64_t>(),
hit.data_ptr<unsigned char>(),anyhit.data_ptr<int>(),nullptr,nullptr,nullptr,n);
}
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
m.def("encode_all_half", &encode_all_half);
m.def("gate_all_half", &gate_all_half);
m.def("head_all_half", &head_all_half);
m.def("respawn_all_half", &respawn_all_half);
m.def("positions", &positions);
m.def("advance_actions", &advance_actions);
m.def("respawn", &respawn);
}
'''
_ext = None
def _get_ext():
global _ext
if _ext is None:
os.environ.setdefault('TORCH_CUDA_ARCH_LIST', '12.0')
_ext = load_inline(
name='grid_mingru_cuda_v11', cpp_sources='', cuda_sources=_CUDA,
functions=None, extra_cuda_cflags=['-O3', '-arch=sm_120', '--use_fast_math'],
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')
g.manual_seed(seed)
for p in self.parameters():
t = torch.empty(p.shape, dtype=p.dtype, device='cpu')
t.normal_(0.0, 0.02, generator=g)
p.data.copy_(t)
self._clear_rollout_cache()
def _clear_rollout_cache(self):
cache = globals().get('_GRAPH_CACHE')
if cache is not None:
for key in [key for key in cache if key[2] == id(self)]:
del cache[key]
def load_state_dict(self, *args, **kwargs):
result = super().load_state_dict(*args, **kwargs)
self._clear_rollout_cache()
return result
def forward(self, obs, state):
return policy_forward(self, obs, state)
def policy_forward(model, obs, state):
h = F.linear(obs, model.w_enc, model.b_enc)
new_states = []
for layer in range(3):
gates = F.linear(h, model.w_gru[layer])
zh, zg, zp = gates.split(256, dim=-1)
out = state[:,layer,:] + torch.sigmoid(zg)*(torch.tanh(zh)-state[:,layer,:])
p = torch.sigmoid(zp)
h = p*out + (1.0-p)*h
new_states.append(out)
return F.linear(h,model.w_a,model.b_a), torch.stack(new_states,dim=1), F.linear(h,model.w_v,model.b_v).squeeze(-1)
def env_step(agent, food, actions, rng_state):
ext = _get_ext()
a, f, rng = agent.clone(), food.clone(), rng_state.clone()
rewards = torch.zeros(agent.shape[0], device=agent.device, dtype=torch.float32)
hit = torch.empty(agent.shape[0], device=agent.device, dtype=torch.uint8)
anyhit = torch.empty(1,device=agent.device,dtype=torch.int32)
empty = torch.empty(0,device=agent.device,dtype=torch.float32)
ext.advance_actions(actions.contiguous(), a, f, rewards, hit, anyhit)
ext.respawn(a,f,rng,hit,anyhit,empty,empty,empty)
return a,f,rewards,rng
_GRAPH_CACHE = {}
def _graph_run(num_envs, horizon, seed, model):
ext = _get_ext()
device = model.w_enc.device
key = (num_envs,horizon,id(model),device,tuple(p._version for p in model.parameters()))
ctx = _GRAPH_CACHE.get(key)
if ctx is None:
n = num_envs
agent = torch.empty((n,2),device=device)
food = torch.empty((n,2),device=device)
rng = torch.empty((n,),device=device,dtype=torch.int64)
base_rng = torch.arange(n,device=device,dtype=torch.int64)
cpu_agent = torch.empty((n,2),dtype=torch.float32,pin_memory=True)
cpu_food = torch.empty((n,2),dtype=torch.float32,pin_memory=True)
generator = torch.Generator(device='cpu')
copy_done = torch.cuda.Event(blocking=False)
rewards = torch.empty(n,device=device)
state = torch.empty((n,3,256),device=device,dtype=torch.float16)
h = torch.empty((n,256),device=device,dtype=torch.float16)
gates = torch.empty((n,768),device=device,dtype=torch.float16)
last = torch.empty((n,4),device=device)
positions_out = torch.empty((n,2),device=device,dtype=torch.int64)
hit = torch.empty(n,device=device,dtype=torch.uint8)
anyhit = torch.empty(1,device=device,dtype=torch.int32)
weights = [model.w_gru[i].t().half() for i in range(3)]
def body():
rewards.zero_()
state.zero_()
last.zero_()
ext.encode_all_half(agent,food,model.w_enc,model.b_enc,h)
for _ in range(horizon):
for layer in range(3):
torch.mm(h,weights[layer],out=gates)
ext.gate_all_half(gates,state,h,layer)
ext.head_all_half(h,model.w_a,model.b_a,agent,food,rewards,hit,anyhit,last)
ext.respawn_all_half(agent,food,rng,hit,anyhit,model.w_enc,model.b_enc,h)
ext.positions(agent,positions_out)
agent.zero_()
food.zero_()
rng.zero_()
with torch.no_grad():
# Set up cuBLAS on a side stream before capture.
stream = torch.cuda.Stream(device=device)
stream.wait_stream(torch.cuda.current_stream(device))
with torch.cuda.stream(stream):
body()
torch.cuda.current_stream(device).wait_stream(stream)
graph = torch.cuda.CUDAGraph()
with torch.cuda.graph(graph):
body()
ctx = (base_rng,cpu_agent,cpu_food,generator,copy_done,agent,food,rng,rewards,state,h,gates,last,positions_out,hit,anyhit,graph,weights,model)
_GRAPH_CACHE[key] = ctx
base_rng,cpu_agent,cpu_food,generator,copy_done,agent,food,rng,rewards,state,h,gates,last,positions_out,hit,anyhit,graph,weights,model = ctx
copy_done.synchronize()
generator.manual_seed(seed)
torch.randint(0,11,(num_envs,2),generator=generator,out=cpu_agent)
torch.randint(0,11,(num_envs,2),generator=generator,out=cpu_food)
agent.copy_(cpu_agent,non_blocking=True)
food.copy_(cpu_food,non_blocking=True)
copy_done.record(torch.cuda.current_stream(device))
torch.add(base_rng,seed*10007,out=rng)
graph.replay()
return {'rewards':rewards.clone(), 'positions':positions_out.clone(), 'last_logits':last.clone()}
_DEFAULT_MODEL = None
def run(num_envs:int,horizon:int,seed:int,model=None)->dict:
global _DEFAULT_MODEL
if model is None:
if _DEFAULT_MODEL is None:
_DEFAULT_MODEL = Model()
model = _DEFAULT_MODEL
model = model.to('cuda:0').eval()
return _graph_run(num_envs,horizon,seed,model)
20260922_123418_codex_gpt-6-sol_04_grid_mingru_sps