gpt-5.5-priority · popcorn · l123_single_gpt
correct 30_SelectiveScan_Mamba.py
model
gpt-5.5-priority
turns / max
1 / 1
tool calls
1
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
popcorn
runtime
0.84 μs
ref runtime
135.00 μs
speedup
159.76x
started
2026-05-05T00:32:21Z
timingkernelbench.timing
kernel runtime
0.84 μs
ref runtime
135.00 μs
speedup
159.76x
kernel mean / median / std
0.84 / — / 0.01 μs
ref mean / median / std
135.00 / — / 186.00 μs
numerical precisioneval_kernel_against_ref
max abs error
2.67e-05
mean abs error
1.45e-07
max rel error
238418.58
mean rel error
0.01
gpu memoryextended_metrics.measure_memory
kernel peak
133.60 MB
ref peak
1765.86 MB
kernel / ref
0.08x
kernel launches / fusiontorch.profiler
kernel launches
28
ref launches
26681
fusion ratio (ref / kernel)
952.89x
total cuda time
1217 μs
energyNVML (pynvml)
kernel mJ / run
352.66
ref mJ / run
10509.44
ratio (ref / kernel)
29.80x
avg power
418.87 W
ref avg power
145.48 W
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
1.000
dram util %
100.0%
compute util %
6.2%
bottleneck
memory-bound
dominant pipe
tensor-core
arithmetic intensity
—
ridge point
295.22
roofline / occupancynsight_hardware_counters
dram bandwidth
6279.98 GB/s
dram util %
100.0%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
142.9%
bottleneck
memory-bound
dominant pipe %
6.2%
arithmetic intensity
—
ridge point
295.22
L1 hit %
—
L2 hit %
305.9%
ld sectors / req
29.50
st sectors / req
—
regs / thread
569
smem / block
71168 B
block size
640
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
1458.1%
short_scoreboard
489.9%
mio_throttle
32.1%
flagssubmit_kernel guard
excessive speedup
flagged
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn

class Model(nn.Module):
    """
    Selective scan (Mamba's S6 layer): projects input to derive input-dependent SSM parameters
    (delta, B, C), discretizes a learned state matrix A, runs the linear recurrence, and
    applies a skip connection via D. The fusion opportunity is keeping all intermediates
    (discretized parameters, hidden states) in SRAM rather than materializing them to global memory.

    Args:
        d_model (int): Input feature dimension.
        d_state (int): Hidden state dimension per channel (N in Mamba, typically 16).
    """
    def __init__(self, d_model: int, d_state: int):
        super(Model, self).__init__()
        self.d_model = d_model
        self.d_state = d_state
        self.A_log = nn.Parameter(torch.randn(d_model, d_state))
        self.proj_B = nn.Linear(d_model, d_state, bias=False)
        self.proj_C = nn.Linear(d_model, d_state, bias=False)
        self.proj_delta = nn.Linear(d_model, d_model, bias=True)
        self.D = nn.Parameter(torch.ones(d_model))

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        B, L, D = x.shape
        N = self.d_state

        delta = torch.nn.functional.softplus(self.proj_delta(x))
        B_t = self.proj_B(x)
        C_t = self.proj_C(x)

        A = -torch.exp(self.A_log)
        dA = torch.exp(delta.unsqueeze(-1) * A.unsqueeze(0).unsqueeze(0))
        dB = delta.unsqueeze(-1) * B_t.unsqueeze(2)
        x_db = x.unsqueeze(-1) * dB

        h = torch.zeros(B, D, N, device=x.device, dtype=x.dtype)
        outputs = []
        for t in range(L):
            h = dA[:, t] * h + x_db[:, t]
            y_t = (h * C_t[:, t].unsqueeze(1)).sum(dim=-1)
            outputs.append(y_t)

        y = torch.stack(outputs, dim=1)
        y = y + x * self.D.unsqueeze(0).unsqueeze(0)
        return y

batch_size = 16
d_model = 256
d_state = 16
seq_len = 2048

def get_inputs():
    return [torch.randn(popcorn_pri.jitter_int(batch_size), popcorn_pri.jitter_int(seq_len), d_model)]

def get_init_inputs():
    return [d_model, d_state]
turn 0 · FINAL · 1 tool call(s) · 74.4s turn · 74.4s LLM · 6,735 chars (click to expand)
turn 074.4s turn · 74.4s LLM · 0.0s tools · FINAL
reasoning
**Evaluating tile handling** I'm trying to figure out if D is not a multiple of TILE, and I need to check if the shape C_t is linear, which should be in the format of [B, L, N]. I'm also considering if everything is contiguous. This seems a bit complicated, but I want to make sure I understand the requirements clearly. It’s all about ensuring that I'm correctly handling those shapes and conditions for the task ahead!
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\n\n\n_cpp_src = r'''\n#include <torch/extension.h>\n\ntorch::Tensor selective_scan_forward(torch::Tensor x,\n torch::Tensor delta,\n torch::Tensor B_t,\n torch::Tensor C_t,\n torch::Tensor A_log,\n torch::Tensor D_param);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n#ifndef TILE_D\n#define TILE_D 8\n#endif\n#ifndef STATE_W\n#define STATE_W 16\n#endif\n\n__global__ __launch_bounds__(TILE_D * STATE_W, 2)\nvoid selective_scan_kernel(const float* __restrict__ x,\n const float* __restrict__ delta,\n const float* __restrict__ B_t,\n const float* __restrict__ C_t,\n const float* __restrict__ A_log,\n const float* __restrict__ D_param,\n float* __restrict__ y,\n int B, int L, int D, int N) {\n const int b = (int)blockIdx.y;\n const int d_base = (int)blockIdx.x * TILE_D;\n const int tid = (int)threadIdx.x;\n const int kd = tid >> 4; // channel within the tile\n const int n = tid & 15; // state lane\n const int d = d_base + kd;\n\n const int lane_in_warp = tid & 31;\n const unsigned mask = 0xFFFFu << (lane_in_warp & 16);\n\n float h = 0.0f;\n float a = 0.0f;\n if (d < D && n < N) {\n a = -expf(A_log[d * N + n]);\n }\n\n float d_skip = 0.0f;\n if (d < D && n == 0) d_skip = D_param[d];\n\n const int bd_x_base = (b * L) * D;\n const int bd_s_base = (b * L) * N;\n\n for (int t = 0; t < L; ++t) {\n float xv = 0.0f;\n float dt = 0.0f;\n const int x_idx = bd_x_base + t * D + d;\n if (d < D && n == 0) {\n xv = x[x_idx];\n dt = delta[x_idx];\n }\n xv = __shfl_sync(mask, xv, 0, STATE_W);\n dt = __shfl_sync(mask, dt, 0, STATE_W);\n\n float acc = 0.0f;\n if (d < D && n < N) {\n const int s_idx = bd_s_base + t * N + n;\n const float bn = B_t[s_idx];\n const float cn = C_t[s_idx];\n const float ea = expf(dt * a);\n h = fmaf(xv * dt, bn, ea * h);\n acc = h * cn;\n }\n\n acc += __shfl_down_sync(mask, acc, 8, STATE_W);\n acc += __shfl_down_sync(mask, acc, 4, STATE_W);\n acc += __shfl_down_sync(mask, acc, 2, STATE_W);\n acc += __shfl_down_sync(mask, acc, 1, STATE_W);\n\n if (d < D && n == 0) {\n y[x_idx] = acc + xv * d_skip;\n }\n }\n}\n\ntorch::Tensor selective_scan_forward(torch::Tensor x,\n torch::Tensor delta,\n torch::Tensor B_t,\n torch::Tensor C_t,\n torch::Tensor A_log,\n torch::Tensor D_param) {\n const int B = (int)x.size(0);\n const int L = (int)x.size(1);\n const int D = (int)x.size(2);\n const int N = (int)A_log.size(1);\n\n auto y = torch::empty_like(x);\n dim3 block(TILE_D * STATE_W);\n dim3 grid((D + TILE_D - 1) / TILE_D, B);\n\n selective_scan_kernel<<<grid, block, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), delta.data_ptr<float>(), B_t.data_ptr<float>(), C_t.data_ptr<float>(),\n A_log.data_ptr<float>(), D_param.data_ptr<float>(), y.data_ptr<float>(), B, L, D, N);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='selective_scan_mamba_s6_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['selective_scan_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, d_model: int, d_state: int):\n super(ModelNew, self).__init__()\n self.d_model = d_model\n self.d_state = d_state\n self.A_log = nn.Parameter(torch.randn(d_model, d_state))\n self.proj_B = nn.Linear(d_model, d_state, bias=False)\n self.proj_C = nn.Linear(d_model, d_state, bias=False)\n self.proj_delta = nn.Linear(d_model, d_model, bias=True)\n self.D = nn.Parameter(torch.ones(d_model))\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n delta = F.softplus(self.proj_delta(x))\n B_t = self.proj_B(x)\n C_t = self.proj_C(x)\n return _ext.selective_scan_forward(x, delta, B_t, C_t, self.A_log, self.D)\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 0.84 μs Runtime stats: mean=0.84μs median=?μs std=0.01μs Numerical precision: max_abs_err=2.67e-05 mean_abs_err=1.45e-07 max_rel_err=2.38e+05 Memory: 133.6 MB peak (ref: 1765.86 MB, ratio: 0.0757x) Kernel launches: 28 (ref: 26681, fusion ratio: 952.8929) Energy: 352.66 mJ/run (ref: 10509.44 mJ, ratio: 29.8005x) SOL score: 1.0 Flagged for excessive speedup — this submission may have been rejected by automated review.
final submitted kernel (145 lines, 4,776 chars) — full source, untruncated
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.cpp_extension import load_inline


_cpp_src = r'''
#include <torch/extension.h>

torch::Tensor selective_scan_forward(torch::Tensor x,
                                     torch::Tensor delta,
                                     torch::Tensor B_t,
                                     torch::Tensor C_t,
                                     torch::Tensor A_log,
                                     torch::Tensor D_param);
'''

_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAException.h>
#include <cuda.h>
#include <cuda_runtime.h>

#ifndef TILE_D
#define TILE_D 8
#endif
#ifndef STATE_W
#define STATE_W 16
#endif

__global__ __launch_bounds__(TILE_D * STATE_W, 2)
void selective_scan_kernel(const float* __restrict__ x,
                           const float* __restrict__ delta,
                           const float* __restrict__ B_t,
                           const float* __restrict__ C_t,
                           const float* __restrict__ A_log,
                           const float* __restrict__ D_param,
                           float* __restrict__ y,
                           int B, int L, int D, int N) {
    const int b = (int)blockIdx.y;
    const int d_base = (int)blockIdx.x * TILE_D;
    const int tid = (int)threadIdx.x;
    const int kd = tid >> 4;        // channel within the tile
    const int n  = tid & 15;        // state lane
    const int d = d_base + kd;

    const int lane_in_warp = tid & 31;
    const unsigned mask = 0xFFFFu << (lane_in_warp & 16);

    float h = 0.0f;
    float a = 0.0f;
    if (d < D && n < N) {
        a = -expf(A_log[d * N + n]);
    }

    float d_skip = 0.0f;
    if (d < D && n == 0) d_skip = D_param[d];

    const int bd_x_base = (b * L) * D;
    const int bd_s_base = (b * L) * N;

    for (int t = 0; t < L; ++t) {
        float xv = 0.0f;
        float dt = 0.0f;
        const int x_idx = bd_x_base + t * D + d;
        if (d < D && n == 0) {
            xv = x[x_idx];
            dt = delta[x_idx];
        }
        xv = __shfl_sync(mask, xv, 0, STATE_W);
        dt = __shfl_sync(mask, dt, 0, STATE_W);

        float acc = 0.0f;
        if (d < D && n < N) {
            const int s_idx = bd_s_base + t * N + n;
            const float bn = B_t[s_idx];
            const float cn = C_t[s_idx];
            const float ea = expf(dt * a);
            h = fmaf(xv * dt, bn, ea * h);
            acc = h * cn;
        }

        acc += __shfl_down_sync(mask, acc, 8, STATE_W);
        acc += __shfl_down_sync(mask, acc, 4, STATE_W);
        acc += __shfl_down_sync(mask, acc, 2, STATE_W);
        acc += __shfl_down_sync(mask, acc, 1, STATE_W);

        if (d < D && n == 0) {
            y[x_idx] = acc + xv * d_skip;
        }
    }
}

torch::Tensor selective_scan_forward(torch::Tensor x,
                                     torch::Tensor delta,
                                     torch::Tensor B_t,
                                     torch::Tensor C_t,
                                     torch::Tensor A_log,
                                     torch::Tensor D_param) {
    const int B = (int)x.size(0);
    const int L = (int)x.size(1);
    const int D = (int)x.size(2);
    const int N = (int)A_log.size(1);

    auto y = torch::empty_like(x);
    dim3 block(TILE_D * STATE_W);
    dim3 grid((D + TILE_D - 1) / TILE_D, B);

    selective_scan_kernel<<<grid, block, 0, at::cuda::getCurrentCUDAStream()>>>(
        x.data_ptr<float>(), delta.data_ptr<float>(), B_t.data_ptr<float>(), C_t.data_ptr<float>(),
        A_log.data_ptr<float>(), D_param.data_ptr<float>(), y.data_ptr<float>(), B, L, D, N);
    C10_CUDA_KERNEL_LAUNCH_CHECK();
    return y;
}
'''

_ext = load_inline(
    name='selective_scan_mamba_s6_ext_v1',
    cpp_sources=_cpp_src,
    cuda_sources=_cuda_src,
    functions=['selective_scan_forward'],
    extra_cflags=['-O3'],
    extra_cuda_cflags=['-O3', '--use_fast_math'],
    verbose=False,
)


class ModelNew(nn.Module):
    def __init__(self, d_model: int, d_state: int):
        super(ModelNew, self).__init__()
        self.d_model = d_model
        self.d_state = d_state
        self.A_log = nn.Parameter(torch.randn(d_model, d_state))
        self.proj_B = nn.Linear(d_model, d_state, bias=False)
        self.proj_C = nn.Linear(d_model, d_state, bias=False)
        self.proj_delta = nn.Linear(d_model, d_model, bias=True)
        self.D = nn.Parameter(torch.ones(d_model))

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        delta = F.softplus(self.proj_delta(x))
        B_t = self.proj_B(x)
        C_t = self.proj_C(x)
        return _ext.selective_scan_forward(x, delta, B_t, C_t, self.A_log, self.D)