grok-4.3 · popcorn · pop_l123_st_gpt
compile_fail 2_GraphEdgeSoftmaxCSR.py
model
grok-4.3
turns / max
1 / 1
tool calls
1
tokens (total)
3270
wall clock
500.8s
truncated
no
backend
cuda fp32
variant
popcorn
runtime
—
ref runtime
-1.00 μs
speedup
—
started
2026-05-11T09:24:34Z
compile error: Syntax error in custom generated code or ModelNew not found
timingkernelbench.timing
kernel runtime
—
ref runtime
—
speedup
—
kernel mean / median / std
—
ref mean / median / std
—
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn


class Model(nn.Module):
    """
    Row-wise softmax over edge scores stored in CSR format.

    This is a core primitive in graph attention networks and sparse attention on
    irregular neighborhoods. Each node owns a contiguous edge segment in
    `edge_scores[row_ptr[i]:row_ptr[i + 1]]`, and the kernel normalizes scores
    independently within each segment.
    """

    def __init__(self):
        super().__init__()

    def forward(
        self,
        row_ptr: torch.Tensor,
        edge_scores: torch.Tensor,
    ) -> torch.Tensor:
        """
        Args:
            row_ptr:      (num_nodes + 1,) CSR row offsets
            edge_scores:  (num_edges,) unnormalized attention logits
        Returns:
            (num_edges,) softmax-normalized edge weights per source node
        """
        num_nodes = row_ptr.numel() - 1
        out = torch.empty_like(edge_scores)

        for node in range(num_nodes):
            start = int(row_ptr[node].item())
            end = int(row_ptr[node + 1].item())
            if end > start:
                out[start:end] = torch.softmax(edge_scores[start:end], dim=0)

        return out


num_nodes = 512
avg_degree = 24
batchless_num_edges = num_nodes * avg_degree


def _make_row_ptr(num_nodes: int, avg_degree: int) -> torch.Tensor:
    base = torch.full((num_nodes,), avg_degree, dtype=torch.int32)
    return row_ptr


def get_inputs():
    return list(popcorn_pri.make_csr_scalar_edge_scores(num_nodes, avg_degree))



def get_init_inputs():
    return []
turn 0 · FINAL · 1 tool call(s) · 500.8s turn · 18.2s LLM · tokens in=1,327 · out=1,636 · total=3,270 · 7,407 chars (click to expand)
turn 0500.8s turn · 18.2s LLM · 482.6s tools · tokens in=1,327 · out=1,636 · total=3,270 · FINAL
reasoning
The task is to replace the forward computation with a custom CUDA kernel for a row-wise softmax over edge scores in CSR format.
assistant```python import torch import torch.nn as nn from torch.utils.cpp_extension import load_inline cuda_source = r''' #include <torch/extension.h> #include <cuda.h> #include <cuda_runtime.h> #include <cfloat> __global__ void sparse_row_softmax_kernel( const int* __restrict__ row_ptr, const float* __restrict__ edge_scores, float* __restrict__ out, int num_nodes ) { int node = blockIdx.x; if (node >= num_nodes) return; int start = row_ptr[node]; int end = row_ptr[node + 1]; int degree = end - start; if (degree <= 0) return; // Each block handles one row; use shared memory for reduction extern __shared__ float sdata[]; float thread_max = -FLT_MAX; for (int i = threadIdx.x; i < degree; i += blockDim.x) { float val = edge_scores[start + i]; thread_max = fmaxf(thread_max, val); } // Block reduce max sdata[threadIdx.x] = thread_max; __syncthreads(); for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { sdata[threadIdx.x] = fmaxf(sdata[threadIdx.x], sdata[threadIdx.x + s]); } __syncthreads(); } float row_max = sdata[0]; __syncthreads(); float thread_sum = 0.0f; for (int i = threadIdx.x; i < degree; i += blockDim.x) { float val = expf(edge_scores[start + i] - row_max); out[start + i] = val; // temporarily store exp thread_sum += val; } sdata[threadIdx.x] = thread_sum; __syncthreads(); for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { sdata[threadIdx.x] += sdata[threadIdx.x + s]; } __syncthreads(); } float row_sum = sdata[0]; float inv_sum = 1.0f / row_sum; for (int i = threadIdx.x; i < degree; i += blockDim.x) { out[start + i] *= inv_sum; } } torch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores) { int num_nodes = row_ptr.size(0) - 1; auto out = torch::empty_like(edge_scores); const int threads = 32; // one warp per row dim3 blocks(num_nodes); size_t shared_mem = threads * sizeof(float); sparse_row_softmax_kernel<<<blocks, threads, shared_mem>>>( row_ptr.data_ptr<int>(), edge_scores.data_ptr<float>(), out.data_ptr<float>(), num_nodes ); return out; } ''' cpp_source = ''' torch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores); ''' sparse_softmax = load_inline( name='sparse_softmax', cpp_sources=[cpp_source], cuda_sources=[cuda_source], functions=['sparse_row_softmax_cuda'], verbose=False, extra_cuda_cflags=['-O3'] ) class ModelNew(nn.Module): def __init__(self): super().__init__() def forward(self, row_ptr: torch.Tensor, edge_scores: torch.Tensor) -> torch.Tensor: return sparse_softmax.sparse_row_softmax_cuda(row_ptr, edge_scores) ``` This completes the submission.
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cfloat>\n\n__global__ void sparse_row_softmax_kernel(\n const int* __restrict__ row_ptr,\n const float* __restrict__ edge_scores,\n float* __restrict__ out,\n int num_nodes\n) {\n int node = blockIdx.x;\n if (node >= num_nodes) return;\n\n int start = row_ptr[node];\n int end = row_ptr[node + 1];\n int degree = end - start;\n\n if (degree <= 0) return;\n\n // Each block handles one row; use shared memory for reduction\n extern __shared__ float sdata[];\n\n float thread_max = -FLT_MAX;\n for (int i = threadIdx.x; i < degree; i += blockDim.x) {\n float val = edge_scores[start + i];\n thread_max = fmaxf(thread_max, val);\n }\n\n // Block reduce max\n sdata[threadIdx.x] = thread_max;\n __syncthreads();\n\n for (int s = blockDim.x / 2; s > 0; s >>= 1) {\n if (threadIdx.x < s) {\n sdata[threadIdx.x] = fmaxf(sdata[threadIdx.x], sdata[threadIdx.x + s]);\n }\n __syncthreads();\n }\n float row_max = sdata[0];\n __syncthreads();\n\n float thread_sum = 0.0f;\n for (int i = threadIdx.x; i < degree; i += blockDim.x) {\n float val = expf(edge_scores[start + i] - row_max);\n out[start + i] = val; // temporarily store exp\n thread_sum += val;\n }\n\n sdata[threadIdx.x] = thread_sum;\n __syncthreads();\n\n for (int s = blockDim.x / 2; s > 0; s >>= 1) {\n if (threadIdx.x < s) {\n sdata[threadIdx.x] += sdata[threadIdx.x + s];\n }\n __syncthreads();\n }\n float row_sum = sdata[0];\n\n float inv_sum = 1.0f / row_sum;\n for (int i = threadIdx.x; i < degree; i += blockDim.x) {\n out[start + i] *= inv_sum;\n }\n}\n\ntorch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores) {\n int num_nodes = row_ptr.size(0) - 1;\n auto out = torch::empty_like(edge_scores);\n\n const int threads = 32; // one warp per row\n dim3 blocks(num_nodes);\n\n size_t shared_mem = threads * sizeof(float);\n\n sparse_row_softmax_kernel<<<blocks, threads, shared_mem>>>(\n row_ptr.data_ptr<int>(),\n edge_scores.data_ptr<float>(),\n out.data_ptr<float>(),\n num_nodes\n );\n\n return out;\n}\n'''\n\ncpp_source = '''\ntorch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores);\n'''\n\nsparse_softmax = load_inline(\n name='sparse_softmax',\n cpp_sources=[cpp_source],\n cuda_sources=[cuda_source],\n functions=['sparse_row_softmax_cuda'],\n verbose=False,\n extra_cuda_cflags=['-O3']\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n\n def forward(self, row_ptr: torch.Tensor, edge_scores: torch.Tensor) -> torch.Tensor:\n return sparse_softmax.sparse_row_softmax_cuda(row_ptr, edge_scores)\n```" }
result ← submit_kernel (fail)
failsubmit_kernel submit_kernel FAILED: kernel did not compile. Syntax error in custom generated code or ModelNew not found
final submitted kernel (111 lines, 2,943 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

cuda_source = r'''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cfloat>

__global__ void sparse_row_softmax_kernel(
    const int* __restrict__ row_ptr,
    const float* __restrict__ edge_scores,
    float* __restrict__ out,
    int num_nodes
) {
    int node = blockIdx.x;
    if (node >= num_nodes) return;

    int start = row_ptr[node];
    int end = row_ptr[node + 1];
    int degree = end - start;

    if (degree <= 0) return;

    // Each block handles one row; use shared memory for reduction
    extern __shared__ float sdata[];

    float thread_max = -FLT_MAX;
    for (int i = threadIdx.x; i < degree; i += blockDim.x) {
        float val = edge_scores[start + i];
        thread_max = fmaxf(thread_max, val);
    }

    // Block reduce max
    sdata[threadIdx.x] = thread_max;
    __syncthreads();

    for (int s = blockDim.x / 2; s > 0; s >>= 1) {
        if (threadIdx.x < s) {
            sdata[threadIdx.x] = fmaxf(sdata[threadIdx.x], sdata[threadIdx.x + s]);
        }
        __syncthreads();
    }
    float row_max = sdata[0];
    __syncthreads();

    float thread_sum = 0.0f;
    for (int i = threadIdx.x; i < degree; i += blockDim.x) {
        float val = expf(edge_scores[start + i] - row_max);
        out[start + i] = val;  // temporarily store exp
        thread_sum += val;
    }

    sdata[threadIdx.x] = thread_sum;
    __syncthreads();

    for (int s = blockDim.x / 2; s > 0; s >>= 1) {
        if (threadIdx.x < s) {
            sdata[threadIdx.x] += sdata[threadIdx.x + s];
        }
        __syncthreads();
    }
    float row_sum = sdata[0];

    float inv_sum = 1.0f / row_sum;
    for (int i = threadIdx.x; i < degree; i += blockDim.x) {
        out[start + i] *= inv_sum;
    }
}

torch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores) {
    int num_nodes = row_ptr.size(0) - 1;
    auto out = torch::empty_like(edge_scores);

    const int threads = 32;  // one warp per row
    dim3 blocks(num_nodes);

    size_t shared_mem = threads * sizeof(float);

    sparse_row_softmax_kernel<<<blocks, threads, shared_mem>>>(
        row_ptr.data_ptr<int>(),
        edge_scores.data_ptr<float>(),
        out.data_ptr<float>(),
        num_nodes
    );

    return out;
}
'''

cpp_source = '''
torch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores);
'''

sparse_softmax = load_inline(
    name='sparse_softmax',
    cpp_sources=[cpp_source],
    cuda_sources=[cuda_source],
    functions=['sparse_row_softmax_cuda'],
    verbose=False,
    extra_cuda_cflags=['-O3']
)

class ModelNew(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, row_ptr: torch.Tensor, edge_scores: torch.Tensor) -> torch.Tensor:
        return sparse_softmax.sparse_row_softmax_cuda(row_ptr, edge_scores)
```