call → compile_kernel
callcompile_kernel
{
"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>\ntorch::Tensor gcn_forward(torch::Tensor row_ptr, torch::Tensor col_idx, torch::Tensor node_feat, torch::Tensor degrees);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cstdint>\n\n#define MAX_DEG_SHARED 1024\n\ntemplate <typename row_t, typename col_t>\n__global__ __launch_bounds__(128) void gcn_kernel80_t(const row_t* __restrict__ row_ptr,\n const col_t* __restrict__ col_idx,\n const float* __restrict__ node_feat,\n const float* __restrict__ degrees,\n float* __restrict__ out,\n int num_nodes) {\n int dst = blockIdx.x;\n int tid = threadIdx.x;\n int start = (int)row_ptr[dst];\n int end = (int)row_ptr[dst + 1];\n int deg = end - start;\n\n __shared__ int sh_cols[MAX_DEG_SHARED];\n __shared__ float sh_norm[MAX_DEG_SHARED];\n\n if (deg > 0 && deg <= MAX_DEG_SHARED) {\n float dd = degrees[dst];\n for (int i = tid; i < deg; i += 128) {\n int src = (int)col_idx[start + i];\n sh_cols[i] = src;\n sh_norm[i] = rsqrtf(dd * degrees[src]);\n }\n __syncthreads();\n if (tid < 80) {\n float sum = 0.0f;\n #pragma unroll 32\n for (int i = 0; i < deg; ++i) {\n sum += node_feat[sh_cols[i] * 80 + tid] * sh_norm[i];\n }\n out[dst * 80 + tid] = sum;\n }\n } else if (tid < 80) {\n float sum = 0.0f;\n if (deg > 0) {\n float dd = degrees[dst];\n for (int e = start; e < end; ++e) {\n int src = (int)col_idx[e];\n sum += node_feat[src * 80 + tid] * rsqrtf(dd * degrees[src]);\n }\n }\n out[dst * 80 + tid] = sum;\n }\n}\n\ntemplate <typename row_t, typename col_t>\n__global__ void gcn_kernel_generic_t(const row_t* __restrict__ row_ptr,\n const col_t* __restrict__ col_idx,\n const float* __restrict__ node_feat,\n const float* __restrict__ degrees,\n float* __restrict__ out,\n int num_nodes, int feat_dim) {\n int dst = blockIdx.x;\n int tid = threadIdx.x;\n int start = (int)row_ptr[dst];\n int end = (int)row_ptr[dst + 1];\n int deg = end - start;\n if (deg <= 0) {\n for (int f = tid; f < feat_dim; f += blockDim.x) out[dst * feat_dim + f] = 0.0f;\n return;\n }\n __shared__ int sh_cols[MAX_DEG_SHARED];\n __shared__ float sh_norm[MAX_DEG_SHARED];\n if (deg <= MAX_DEG_SHARED) {\n float dd = degrees[dst];\n for (int i = tid; i < deg; i += blockDim.x) {\n int src = (int)col_idx[start + i];\n sh_cols[i] = src;\n sh_norm[i] = rsqrtf(dd * degrees[src]);\n }\n __syncthreads();\n for (int f = tid; f < feat_dim; f += blockDim.x) {\n float sum = 0.0f;\n for (int i = 0; i < deg; ++i) sum += node_feat[sh_cols[i] * feat_dim + f] * sh_norm[i];\n out[dst * feat_dim + f] = sum;\n }\n } else {\n float dd = degrees[dst];\n for (int f = tid; f < feat_dim; f += blockDim.x) {\n float sum = 0.0f;\n for (int e = start; e < end; ++e) {\n int src = (int)col_idx[e];\n sum += node_feat[src * feat_dim + f] * rsqrtf(dd * degrees[src]);\n }\n out[dst * feat_dim + f] = sum;\n }\n }\n}\n\ntorch::Tensor gcn_forward(torch::Tensor row_ptr, torch::Tensor col_idx, torch::Tensor node_feat, torch::Tensor degrees) {\n const int num_nodes = row_ptr.numel() - 1;\n const int feat_dim = node_feat.size(1);\n auto out = torch::empty({num_nodes, feat_dim}, node_feat.options());\n if (num_nodes == 0 || feat_dim == 0) return out;\n c10::cuda::CUDAGuard device_guard(node_feat.device());\n const int threads = 128;\n dim3 blocks(num_nodes);\n auto stream = at::cuda::getCurrentCUDAStream();\n\n if (feat_dim == 80) {\n if (row_ptr.scalar_type() == at::kFloat && col_idx.scalar_type() == at::kFloat) {\n gcn_kernel80_t<float, float><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<float>(), col_idx.data_ptr<float>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes);\n } else if (row_ptr.scalar_type() == at::kInt && col_idx.scalar_type() == at::kInt) {\n gcn_kernel80_t<int, int><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<int>(), col_idx.data_ptr<int>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes);\n } else if (row_ptr.scalar_type() == at::kLong && col_idx.scalar_type() == at::kLong) {\n gcn_kernel80_t<int64_t, int64_t><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<int64_t>(), col_idx.data_ptr<int64_t>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes);\n } else if (row_ptr.scalar_type() == at::kFloat && col_idx.scalar_type() == at::kInt) {\n gcn_kernel80_t<float, int><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<float>(), col_idx.data_ptr<int>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes);\n } else if (row_ptr.scalar_type() == at::kInt && col_idx.scalar_type() == at::kFloat) {\n gcn_kernel80_t<int, float><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<int>(), col_idx.data_ptr<float>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes);\n } else {\n TORCH_CHECK(false, \"unsupported row_ptr/col_idx dtypes\");\n }\n } else {\n if (row_ptr.scalar_type() == at::kFloat && col_idx.scalar_type() == at::kFloat) {\n gcn_kernel_generic_t<float, float><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<float>(), col_idx.data_ptr<float>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes, feat_dim);\n } else if (row_ptr.scalar_type() == at::kInt && col_idx.scalar_type() == at::kInt) {\n gcn_kernel_generic_t<int, int><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<int>(), col_idx.data_ptr<int>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes, feat_dim);\n } else if (row_ptr.scalar_type() == at::kLong && col_idx.scalar_type() == at::kLong) {\n gcn_kernel_generic_t<int64_t, int64_t><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<int64_t>(), col_idx.data_ptr<int64_t>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes, feat_dim);\n } else if (row_ptr.scalar_type() == at::kFloat && col_idx.scalar_type() == at::kInt) {\n gcn_kernel_generic_t<float, int><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<float>(), col_idx.data_ptr<int>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes, feat_dim);\n } else if (row_ptr.scalar_type() == at::kInt && col_idx.scalar_type() == at::kFloat) {\n gcn_kernel_generic_t<int, float><<<blocks, threads, 0, stream>>>(row_ptr.data_ptr<int>(), col_idx.data_ptr<float>(), node_feat.data_ptr<float>(), degrees.data_ptr<float>(), out.data_ptr<float>(), num_nodes, feat_dim);\n } else {\n TORCH_CHECK(false, \"unsupported row_ptr/col_idx dtypes\");\n }\n }\n return out;\n}\n'''\n\n_gcn_ext = load_inline(\n name='gcn_norm_agg_ext_v3',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['gcn_forward'],\n with_cuda=True,\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n def forward(self, row_ptr: torch.Tensor, col_idx: torch.Tensor, node_feat: torch.Tensor, degrees: torch.Tensor) -> torch.Tensor:\n return _gcn_ext.gcn_forward(row_ptr, col_idx, node_feat, degrees)\n"
}