correct
19_PairwiseDistanceMatrix.py
started
2026-05-05T02:03:52Z
timingkernelbench.timing
kernel mean / median / std
0.01 / — / 1.91e-04 μs
ref mean / median / std
0.08 / — / 0.00 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
12.00x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
warp stalls (top 5)nsight
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
class Model(nn.Module):
"""
Compute all-pairs Euclidean distance matrix from a 3-D point cloud.
A core primitive in molecular dynamics simulations, docking, and
distance-geometry-based structure prediction.
"""
def __init__(self):
super().__init__()
def forward(self, coords: torch.Tensor) -> torch.Tensor:
"""
Args:
coords: (B, N, 3) – 3-D coordinates of N atoms / residues
Returns:
dist: (B, N, N) – pairwise Euclidean distance matrix
"""
diff = coords.unsqueeze(2) - coords.unsqueeze(1) # (B, N, N, 3)
dist = torch.sqrt((diff ** 2).sum(dim=-1) + 1e-8)
return dist
num_atoms = 512
batch_size = 8
def get_inputs():
p = popcorn_pri
return [torch.randn(p.jitter_int(batch_size), p.jitter_int(num_atoms), 3)]
def get_init_inputs():
return []
turn 031.3s turn · 31.3s LLM · 0.0s tools · FINAL
reasoning
**Considering performance optimization**
I'm looking into a numerical approach, particularly focusing on diagonal performance with a value like 1e-4. I realize that integer division can be costly, so I’m thinking about using a 2D grid, possibly with a block size of (16,16) to compute tile pairs. Each block would handle a 16x16 tile, and shared memory could store coordinates to minimize load times. The mapping appears straightforward, avoiding divisions by organizing the blocks efficiently. This setup could enhance performance significantly!
call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n\ntorch::Tensor pairwise_cuda(torch::Tensor coords);\n\ntorch::Tensor pairwise_forward(torch::Tensor coords) {\n return pairwise_cuda(coords);\n}\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n#define TILE 16\n\n__global__ __launch_bounds__(256) void pairwise_kernel_3d(\n const float* __restrict__ coords,\n float* __restrict__ out,\n const int N)\n{\n const int tx = threadIdx.x;\n const int ty = threadIdx.y;\n const int i = blockIdx.y * TILE + ty;\n const int j = blockIdx.x * TILE + tx;\n const int b = blockIdx.z;\n\n __shared__ float ci[TILE][3];\n __shared__ float cj[TILE][3];\n\n const int tid = ty * TILE + tx;\n if (tid < TILE * 3) {\n const int r = tid / 3;\n const int c = tid - r * 3;\n const int gi = blockIdx.y * TILE + r;\n const int gj = blockIdx.x * TILE + r;\n if (gi < N) ci[r][c] = __ldg(coords + ((b * N + gi) * 3 + c));\n if (gj < N) cj[r][c] = __ldg(coords + ((b * N + gj) * 3 + c));\n }\n __syncthreads();\n\n if (i < N && j < N) {\n const float dx = ci[ty][0] - cj[tx][0];\n const float dy = ci[ty][1] - cj[tx][1];\n const float dz = ci[ty][2] - cj[tx][2];\n const float s = fmaf(dx, dx, fmaf(dy, dy, dz * dz)) + 1.0e-8f;\n out[(static_cast<long long>(b) * N + i) * N + j] = sqrtf(s);\n }\n}\n\ntorch::Tensor pairwise_cuda(torch::Tensor coords) {\n TORCH_CHECK(coords.is_cuda(), \"coords must be a CUDA tensor\");\n TORCH_CHECK(coords.scalar_type() == at::kFloat, \"coords must be float32\");\n TORCH_CHECK(coords.dim() == 3 && coords.size(2) == 3, \"coords must have shape (B,N,3)\");\n TORCH_CHECK(coords.is_contiguous(), \"coords must be contiguous\");\n\n const int B = static_cast<int>(coords.size(0));\n const int N = static_cast<int>(coords.size(1));\n auto out = torch::empty({B, N, N}, coords.options());\n\n const dim3 block(TILE, TILE, 1);\n const dim3 grid((N + TILE - 1) / TILE, (N + TILE - 1) / TILE, B);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n pairwise_kernel_3d<<<grid, block, 0, stream>>>(coords.data_ptr<float>(), out.data_ptr<float>(), N);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"pairwise_dist_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"pairwise_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\"],\n with_cuda=True,\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n\n def forward(self, coords: torch.Tensor) -> torch.Tensor:\n return _ext.pairwise_forward(coords)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 0.01 μs
Runtime stats: mean=0.01μs median=?μs std=0.00μs
Numerical precision: max_abs_err=4.77e-07 mean_abs_err=2.69e-08 max_rel_err=1.60e-07
Memory: 8.05 MB peak (ref: 56.05 MB, ratio: 0.1436x)
Kernel launches: 1 (ref: 12, fusion ratio: 12.0)
SOL score: 0.2004
final submitted kernel (94 lines, 2,773 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
_cpp_src = r"""
#include <torch/extension.h>
torch::Tensor pairwise_cuda(torch::Tensor coords);
torch::Tensor pairwise_forward(torch::Tensor coords) {
return pairwise_cuda(coords);
}
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
#define TILE 16
__global__ __launch_bounds__(256) void pairwise_kernel_3d(
const float* __restrict__ coords,
float* __restrict__ out,
const int N)
{
const int tx = threadIdx.x;
const int ty = threadIdx.y;
const int i = blockIdx.y * TILE + ty;
const int j = blockIdx.x * TILE + tx;
const int b = blockIdx.z;
__shared__ float ci[TILE][3];
__shared__ float cj[TILE][3];
const int tid = ty * TILE + tx;
if (tid < TILE * 3) {
const int r = tid / 3;
const int c = tid - r * 3;
const int gi = blockIdx.y * TILE + r;
const int gj = blockIdx.x * TILE + r;
if (gi < N) ci[r][c] = __ldg(coords + ((b * N + gi) * 3 + c));
if (gj < N) cj[r][c] = __ldg(coords + ((b * N + gj) * 3 + c));
}
__syncthreads();
if (i < N && j < N) {
const float dx = ci[ty][0] - cj[tx][0];
const float dy = ci[ty][1] - cj[tx][1];
const float dz = ci[ty][2] - cj[tx][2];
const float s = fmaf(dx, dx, fmaf(dy, dy, dz * dz)) + 1.0e-8f;
out[(static_cast<long long>(b) * N + i) * N + j] = sqrtf(s);
}
}
torch::Tensor pairwise_cuda(torch::Tensor coords) {
TORCH_CHECK(coords.is_cuda(), "coords must be a CUDA tensor");
TORCH_CHECK(coords.scalar_type() == at::kFloat, "coords must be float32");
TORCH_CHECK(coords.dim() == 3 && coords.size(2) == 3, "coords must have shape (B,N,3)");
TORCH_CHECK(coords.is_contiguous(), "coords must be contiguous");
const int B = static_cast<int>(coords.size(0));
const int N = static_cast<int>(coords.size(1));
auto out = torch::empty({B, N, N}, coords.options());
const dim3 block(TILE, TILE, 1);
const dim3 grid((N + TILE - 1) / TILE, (N + TILE - 1) / TILE, B);
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
pairwise_kernel_3d<<<grid, block, 0, stream>>>(coords.data_ptr<float>(), out.data_ptr<float>(), N);
return out;
}
"""
_ext = load_inline(
name="pairwise_dist_ext_v1",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["pairwise_forward"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3"],
with_cuda=True,
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self):
super().__init__()
def forward(self, coords: torch.Tensor) -> torch.Tensor:
return _ext.pairwise_forward(coords)