call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\n#include <vector>\nstd::vector<torch::Tensor> topk4_forward(torch::Tensor row_ptr, torch::Tensor edge_scores);\nstd::vector<torch::Tensor> topk_forward(torch::Tensor row_ptr, torch::Tensor edge_scores, int64_t k64);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <vector>\n#include <math.h>\n#include <stdint.h>\n\ntemplate <typename PtrT>\n__global__ void csr_topk4_warp_kernel(const PtrT* __restrict__ row_ptr,\n const float* __restrict__ scores,\n float* __restrict__ out_vals,\n int64_t* __restrict__ out_idx,\n int num_nodes) {\n int lane = threadIdx.x & 31;\n int row = blockIdx.x * 4 + (threadIdx.x >> 5); // 4 warps per 128-thread block\n if (row >= num_nodes) return;\n int start = (int)row_ptr[row];\n int deg = (int)row_ptr[row + 1] - start;\n float val = (lane < deg) ? scores[start + lane] : -INFINITY;\n int idx = (lane < deg) ? (start + lane) : -1;\n int base = row << 2;\n #pragma unroll\n for (int out = 0; out < 4; ++out) {\n float best = val;\n int best_idx = idx;\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n float ov = __shfl_down_sync(0xffffffff, best, offset);\n int oi = __shfl_down_sync(0xffffffff, best_idx, offset);\n if (ov > best) { best = ov; best_idx = oi; }\n }\n best = __shfl_sync(0xffffffff, best, 0);\n best_idx = __shfl_sync(0xffffffff, best_idx, 0);\n if (lane == 0) { out_vals[base + out] = best; out_idx[base + out] = (int64_t)best_idx; }\n if (idx == best_idx) { val = -INFINITY; idx = -1; }\n }\n}\n\ntemplate <typename PtrT>\n__global__ void csr_topk_generic_kernel(const PtrT* __restrict__ row_ptr,\n const float* __restrict__ scores,\n float* __restrict__ out_vals,\n int64_t* __restrict__ out_idx,\n int num_nodes,\n int k) {\n int node = blockIdx.x * blockDim.x + threadIdx.x;\n if (node >= num_nodes) return;\n int start = (int)row_ptr[node];\n int end = (int)row_ptr[node + 1];\n int base = node * k;\n float vals[16]; int idxs[16]; int kk = k < 16 ? k : 16;\n for (int j = 0; j < kk; ++j) { vals[j] = -INFINITY; idxs[j] = -1; }\n for (int e = start; e < end; ++e) {\n float v = scores[e];\n for (int j = 0; j < kk; ++j) if (v > vals[j]) {\n for (int t = kk - 1; t > j; --t) { vals[t] = vals[t-1]; idxs[t] = idxs[t-1]; }\n vals[j] = v; idxs[j] = e; break;\n }\n }\n for (int j = 0; j < k; ++j) {\n if (j < kk) { out_vals[base + j] = vals[j]; out_idx[base + j] = (int64_t)idxs[j]; }\n else { out_vals[base + j] = -INFINITY; out_idx[base + j] = (int64_t)-1; }\n }\n}\n\ntemplate <typename PtrT>\nstatic void launch4(torch::Tensor row_ptr, torch::Tensor edge_scores, torch::Tensor vals, torch::Tensor idx, int num_nodes) {\n int blocks = (num_nodes + 3) >> 2;\n csr_topk4_warp_kernel<PtrT><<<blocks, 128>>>(row_ptr.data_ptr<PtrT>(), edge_scores.data_ptr<float>(), vals.data_ptr<float>(), idx.data_ptr<int64_t>(), num_nodes);\n}\n\ntemplate <typename PtrT>\nstatic void launch_generic(torch::Tensor row_ptr, torch::Tensor edge_scores, torch::Tensor vals, torch::Tensor idx, int num_nodes, int k) {\n int threads = 256;\n int blocks = (num_nodes + threads - 1) / threads;\n csr_topk_generic_kernel<PtrT><<<blocks, threads>>>(row_ptr.data_ptr<PtrT>(), edge_scores.data_ptr<float>(), vals.data_ptr<float>(), idx.data_ptr<int64_t>(), num_nodes, k);\n}\n\nstd::vector<torch::Tensor> topk4_forward(torch::Tensor row_ptr, torch::Tensor edge_scores) {\n int64_t n64 = row_ptr.numel() - 1;\n int n = (int)n64;\n auto vals = torch::empty({n64, 4}, edge_scores.options());\n auto idx = torch::empty({n64, 4}, edge_scores.options().dtype(torch::kInt64));\n if (row_ptr.scalar_type() == torch::kInt32) launch4<int>(row_ptr, edge_scores, vals, idx, n);\n else if (row_ptr.scalar_type() == torch::kInt64) launch4<int64_t>(row_ptr, edge_scores, vals, idx, n);\n else if (row_ptr.scalar_type() == torch::kFloat32) launch4<float>(row_ptr, edge_scores, vals, idx, n);\n else launch4<int>(row_ptr, edge_scores, vals, idx, n);\n return {vals, idx};\n}\n\nstd::vector<torch::Tensor> topk_forward(torch::Tensor row_ptr, torch::Tensor edge_scores, int64_t k64) {\n if (k64 == 4) return topk4_forward(row_ptr, edge_scores);\n int64_t n64 = row_ptr.numel() - 1; int n = (int)n64; int k = (int)k64;\n auto vals = torch::empty({n64, k64}, edge_scores.options());\n auto idx = torch::empty({n64, k64}, edge_scores.options().dtype(torch::kInt64));\n if (row_ptr.scalar_type() == torch::kInt32) launch_generic<int>(row_ptr, edge_scores, vals, idx, n, k);\n else if (row_ptr.scalar_type() == torch::kInt64) launch_generic<int64_t>(row_ptr, edge_scores, vals, idx, n, k);\n else if (row_ptr.scalar_type() == torch::kFloat32) launch_generic<float>(row_ptr, edge_scores, vals, idx, n, k);\n else launch_generic<int>(row_ptr, edge_scores, vals, idx, n, k);\n return {vals, idx};\n}\n'''\n\n_ext = load_inline(name='csr_topk4_ext_spec_v1', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['topk4_forward','topk_forward'], extra_cuda_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, k):\n super().__init__()\n self.k = int(k)\n def forward(self, row_ptr: torch.Tensor, edge_scores: torch.Tensor):\n if self.k == 4:\n return _ext.topk4_forward(row_ptr, edge_scores)\n return _ext.topk_forward(row_ptr, edge_scores, self.k)\n"
}