correct
51_Argmax_over_a_dimension.py
started
2026-05-02T04:40:20Z
timingkernelbench.timing
kernel mean / median / std
3.53 / — / 0.00 μs
ref mean / median / std
3.23 / — / 0.00 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
2.00x
energyNVML (pynvml)
ratio (ref / kernel)
1.00x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
2998.67 GB/s
warp stalls (top 5)nsight
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
class Model(nn.Module):
"""
Simple model that performs Argmax over a specified dimension.
"""
def __init__(self, dim: int):
"""
Initializes the model with the dimension to perform argmax.
Args:
dim (int): The dimension to perform argmax over.
"""
super(Model, self).__init__()
self.dim = dim
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Applies argmax over the specified dimension to the input tensor.
Args:
x (torch.Tensor): Input tensor.
Returns:
torch.Tensor: Output tensor with argmax applied, with the specified dimension removed.
"""
return torch.argmax(x, dim=self.dim)
batch_size = 128
dim1 = 4096
dim2 = 4095
def get_inputs():
x = torch.rand(batch_size, dim1, dim2)
return [x]
def get_init_inputs():
return [1]turn 016.0s turn · 16.0s LLM · 0.0s tools
call → get_gpu_specs
callget_gpu_specs
{}
result ← get_gpu_specs (ok)
okget_gpu_specs
GPU specs for NVIDIA H100 80GB HBM3:
total memory (runtime): 79.1 GB
spec entry: H100
GPU Architecture: Hopper
GPU Memory: 80GB
Memory Bandwidth: 3.35 TB/s
FP64 TFLOPS: 34
FP64 Tensor Core TFLOPS: 67
FP32 TFLOPS: 67
TF32 Tensor Core TFLOPS: 989 with sparsity
BFLOAT16 Tensore Core TFLOPS: 1979 with sparsity
FP16 Tensor Core TFLOPS: 1979 with sparsity
FP8 Tensor Core TFLOPS: 3958 with sparsity
INT8 Tensor Core TOPS: 3958 with sparsity
Register File Size: 64K 32-bit registers per SM
Maximum number of registers per thread: 255
Maximum number of thread blocks per SM: 32
Shared memory capacity per SM: 228 KB
Maximum shared memory per thread block: 227 KB
turn 1 · 1 tool call(s) · 50.5s turn · 50.5s LLM · 9,901 chars (click to expand)
turn 150.5s turn · 50.5s LLM · 0.0s tools
reasoning
**Considering optimization approaches**
I'm pondering whether I could optimize by transposing shared tile rows. But I'm not completely convinced that’s the best way. I wonder if it might be more effective to adjust the tile output columns with a block dimension of 256 or 512 instead. It's a bit unclear, so I’ll keep exploring these options to see which one truly leads to better performance! My goal is to get this optimization just right.
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>\n\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cstdint>\n#include <vector>\n\n__global__ void argmax_dim1_float4cols_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int b = blockIdx.y;\n int group = blockIdx.x * blockDim.x + threadIdx.x;\n int c = group * 4;\n if (c >= D2) return;\n\n const long long base = (long long)b * D1 * D2 + c;\n float m0 = x[base];\n float m1 = (c + 1 < D2) ? x[base + 1] : -CUDART_INF_F;\n float m2 = (c + 2 < D2) ? x[base + 2] : -CUDART_INF_F;\n float m3 = (c + 3 < D2) ? x[base + 3] : -CUDART_INF_F;\n int i0 = 0, i1 = 0, i2 = 0, i3 = 0;\n\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n long long off = base + (long long)k * D2;\n float v0 = x[off];\n float v1 = (c + 1 < D2) ? x[off + 1] : -CUDART_INF_F;\n float v2 = (c + 2 < D2) ? x[off + 2] : -CUDART_INF_F;\n float v3 = (c + 3 < D2) ? x[off + 3] : -CUDART_INF_F;\n if (v0 > m0) { m0 = v0; i0 = k; }\n if (v1 > m1) { m1 = v1; i1 = k; }\n if (v2 > m2) { m2 = v2; i2 = k; }\n if (v3 > m3) { m3 = v3; i3 = k; }\n }\n long long o = (long long)b * D2 + c;\n out[o] = (int64_t)i0;\n if (c + 1 < D2) out[o + 1] = (int64_t)i1;\n if (c + 2 < D2) out[o + 2] = (int64_t)i2;\n if (c + 3 < D2) out[o + 3] = (int64_t)i3;\n}\n\n__global__ void argmax_dim2_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int row = blockIdx.x;\n int b = row / D1;\n int d1 = row - b * D1;\n const float* p = x + ((long long)b * D1 + d1) * D2;\n float best = -CUDART_INF_F;\n int besti = 0;\n for (int c = threadIdx.x; c < D2; c += blockDim.x) {\n float v = p[c];\n if (v > best) { best = v; besti = c; }\n }\n __shared__ float svals[256];\n __shared__ int sidx[256];\n svals[threadIdx.x] = best;\n sidx[threadIdx.x] = besti;\n __syncthreads();\n for (int stride = blockDim.x/2; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) {\n float v = svals[threadIdx.x + stride];\n int idx = sidx[threadIdx.x + stride];\n if (v > svals[threadIdx.x] || (v == svals[threadIdx.x] && idx < sidx[threadIdx.x])) {\n svals[threadIdx.x] = v; sidx[threadIdx.x] = idx;\n }\n }\n __syncthreads();\n }\n if (threadIdx.x == 0) out[row] = (int64_t)sidx[0];\n}\n\n__global__ void argmax_dim0_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = D1 * D2;\n if (idx >= total) return;\n int d1 = idx / D2;\n int d2 = idx - d1 * D2;\n float best = x[(long long)d1 * D2 + d2];\n int besti = 0;\n for (int b = 1; b < B; ++b) {\n float v = x[((long long)b * D1 + d1) * D2 + d2];\n if (v > best) { best = v; besti = b; }\n }\n out[idx] = (int64_t)besti;\n}\n\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim) {\n dim = (dim % 3 + 3) % 3;\n const int B = (int)x.size(0);\n const int D1 = (int)x.size(1);\n const int D2 = (int)x.size(2);\n auto opts = torch::TensorOptions().device(x.device()).dtype(torch::kInt64);\n torch::Tensor out;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (dim == 1) {\n out = torch::empty({B, D2}, opts);\n const int threads = 128;\n dim3 block(threads);\n dim3 grid((D2 + threads * 4 - 1) / (threads * 4), B);\n argmax_dim1_float4cols_kernel<<<grid, block, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n } else if (dim == 2) {\n out = torch::empty({B, D1}, opts);\n argmax_dim2_float_kernel<<<B * D1, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n } else {\n out = torch::empty({D1, D2}, opts);\n int total = D1 * D2;\n argmax_dim0_float_kernel<<<(total + 255) / 256, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n }\n return out;\n}\n'''\n\n_ext = load_inline(name='argmax_ext_v1', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['argmax_forward'], verbose=False,\n extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int):\n super(ModelNew, self).__init__()\n self.dim = dim\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.argmax_forward(x.contiguous(), self.dim)\n"
}
result ← compile_kernel (fail)
failcompile_kernel
compile_kernel FAILED: RuntimeError.
RuntimeError: Error building extension 'argmax_ext_v1': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=argmax_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -fPIC -std=c++17 -O3 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_1_problem_51_cache/k_56dac8b635db/argmax_ext_v1/main.cpp -o main.o
[2/3] /usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=argmax_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -O3 --use_fast_math -std=c++17 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_1_problem_51_cache/k_56dac8b635db/argmax_ext_v1/cuda.cu -o cuda.cuda.o
FAILED: [code=2] cuda.cuda.o
/usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=argmax_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -O3 --use_fast_math -std=c++17 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_1_problem_51_cache/k_56dac8b635db/argmax_ext_v1/cuda.cu -o cuda.cuda.o
nvcc warning : incompatible redefinition for option 'compiler-bindir', the last value of this option was used
/scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_1_problem_51_cache/k_56dac8b635db/argmax_ext_v1/cuda.cu(19): error: identifier "CUDART_INF_F" is undefined
float m1 = (c + 1 < D2) ? x[base + 1] : -CUDART_INF_F;
^
/scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_1_problem_51_cache/k_56dac8b635db/argmax_ext_v1/cuda.cu(49): error: identifier "CUDART_INF_F" is undefined
float best = -CUDART_INF_F;
^
2 errors detected in the compilation of "/scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_1_problem_51_cache/k_56dac8b635db/argmax_ext_v1/cuda.cu".
ninja: build stopped: subcommand failed.
turn 2 · 1 tool call(s) · 12.8s turn · 12.8s LLM · 6,310 chars (click to expand)
turn 212.8s turn · 12.8s LLM · 0.0s tools
reasoning
**Considering CUDA adjustments**
I need to include cuda_runtime.h or use -INFINITY, so I'll probably add <cuda_runtime.h>. Also, I’m thinking about using -3.402823e38f. Additionally, I should remember that x.contiguous() might create a copy if the input isn’t already contiguous. Static might be lazy, which is something to consider. Alright, let’s see if I can compile and run this without any issues!
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 argmax_forward(torch::Tensor x, int64_t dim);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cstdint>\n\n#define NEG_INF_F (-3.4028234663852886e38f)\n\n__global__ void argmax_dim1_float4cols_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int b = blockIdx.y;\n int group = blockIdx.x * blockDim.x + threadIdx.x;\n int c = group * 4;\n if (c >= D2) return;\n\n const long long base = (long long)b * D1 * D2 + c;\n float m0 = x[base];\n float m1 = (c + 1 < D2) ? x[base + 1] : NEG_INF_F;\n float m2 = (c + 2 < D2) ? x[base + 2] : NEG_INF_F;\n float m3 = (c + 3 < D2) ? x[base + 3] : NEG_INF_F;\n int i0 = 0, i1 = 0, i2 = 0, i3 = 0;\n\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n long long off = base + (long long)k * D2;\n float v0 = x[off];\n float v1 = (c + 1 < D2) ? x[off + 1] : NEG_INF_F;\n float v2 = (c + 2 < D2) ? x[off + 2] : NEG_INF_F;\n float v3 = (c + 3 < D2) ? x[off + 3] : NEG_INF_F;\n if (v0 > m0) { m0 = v0; i0 = k; }\n if (v1 > m1) { m1 = v1; i1 = k; }\n if (v2 > m2) { m2 = v2; i2 = k; }\n if (v3 > m3) { m3 = v3; i3 = k; }\n }\n long long o = (long long)b * D2 + c;\n out[o] = (int64_t)i0;\n if (c + 1 < D2) out[o + 1] = (int64_t)i1;\n if (c + 2 < D2) out[o + 2] = (int64_t)i2;\n if (c + 3 < D2) out[o + 3] = (int64_t)i3;\n}\n\n__global__ void argmax_dim2_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int row = blockIdx.x;\n int b = row / D1;\n int d1 = row - b * D1;\n const float* p = x + ((long long)b * D1 + d1) * D2;\n float best = NEG_INF_F;\n int besti = 0;\n for (int c = threadIdx.x; c < D2; c += blockDim.x) {\n float v = p[c];\n if (v > best) { best = v; besti = c; }\n }\n __shared__ float svals[256];\n __shared__ int sidx[256];\n svals[threadIdx.x] = best;\n sidx[threadIdx.x] = besti;\n __syncthreads();\n for (int stride = 128; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) {\n float v = svals[threadIdx.x + stride];\n int idx = sidx[threadIdx.x + stride];\n if (v > svals[threadIdx.x] || (v == svals[threadIdx.x] && idx < sidx[threadIdx.x])) {\n svals[threadIdx.x] = v; sidx[threadIdx.x] = idx;\n }\n }\n __syncthreads();\n }\n if (threadIdx.x == 0) out[row] = (int64_t)sidx[0];\n}\n\n__global__ void argmax_dim0_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = D1 * D2;\n if (idx >= total) return;\n int d1 = idx / D2;\n int d2 = idx - d1 * D2;\n float best = x[(long long)d1 * D2 + d2];\n int besti = 0;\n for (int b = 1; b < B; ++b) {\n float v = x[((long long)b * D1 + d1) * D2 + d2];\n if (v > best) { best = v; besti = b; }\n }\n out[idx] = (int64_t)besti;\n}\n\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim) {\n dim = (dim % 3 + 3) % 3;\n const int B = (int)x.size(0);\n const int D1 = (int)x.size(1);\n const int D2 = (int)x.size(2);\n auto opts = torch::TensorOptions().device(x.device()).dtype(torch::kInt64);\n torch::Tensor out;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (dim == 1) {\n out = torch::empty({B, D2}, opts);\n const int threads = 128;\n dim3 grid((D2 + threads * 4 - 1) / (threads * 4), B);\n argmax_dim1_float4cols_kernel<<<grid, threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n } else if (dim == 2) {\n out = torch::empty({B, D1}, opts);\n argmax_dim2_float_kernel<<<B * D1, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n } else {\n out = torch::empty({D1, D2}, opts);\n int total = D1 * D2;\n argmax_dim0_float_kernel<<<(total + 255) / 256, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n }\n return out;\n}\n'''\n\n_ext = load_inline(name='argmax_ext_v2', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['argmax_forward'], verbose=False,\n extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int):\n super(ModelNew, self).__init__()\n self.dim = dim\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.argmax_forward(x.contiguous(), self.dim)\n"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 311.2s turn · 11.2s LLM · 0.0s tools
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>\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cstdint>\n\n#define NEG_INF_F (-3.4028234663852886e38f)\n\n__global__ void argmax_dim1_float4cols_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int b = blockIdx.y;\n int group = blockIdx.x * blockDim.x + threadIdx.x;\n int c = group * 4;\n if (c >= D2) return;\n\n const long long base = (long long)b * D1 * D2 + c;\n float m0 = x[base];\n float m1 = (c + 1 < D2) ? x[base + 1] : NEG_INF_F;\n float m2 = (c + 2 < D2) ? x[base + 2] : NEG_INF_F;\n float m3 = (c + 3 < D2) ? x[base + 3] : NEG_INF_F;\n int i0 = 0, i1 = 0, i2 = 0, i3 = 0;\n\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n long long off = base + (long long)k * D2;\n float v0 = x[off];\n float v1 = (c + 1 < D2) ? x[off + 1] : NEG_INF_F;\n float v2 = (c + 2 < D2) ? x[off + 2] : NEG_INF_F;\n float v3 = (c + 3 < D2) ? x[off + 3] : NEG_INF_F;\n if (v0 > m0) { m0 = v0; i0 = k; }\n if (v1 > m1) { m1 = v1; i1 = k; }\n if (v2 > m2) { m2 = v2; i2 = k; }\n if (v3 > m3) { m3 = v3; i3 = k; }\n }\n long long o = (long long)b * D2 + c;\n out[o] = (int64_t)i0;\n if (c + 1 < D2) out[o + 1] = (int64_t)i1;\n if (c + 2 < D2) out[o + 2] = (int64_t)i2;\n if (c + 3 < D2) out[o + 3] = (int64_t)i3;\n}\n\n__global__ void argmax_dim2_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int row = blockIdx.x;\n int b = row / D1;\n int d1 = row - b * D1;\n const float* p = x + ((long long)b * D1 + d1) * D2;\n float best = NEG_INF_F;\n int besti = 0;\n for (int c = threadIdx.x; c < D2; c += blockDim.x) {\n float v = p[c];\n if (v > best) { best = v; besti = c; }\n }\n __shared__ float svals[256];\n __shared__ int sidx[256];\n svals[threadIdx.x] = best;\n sidx[threadIdx.x] = besti;\n __syncthreads();\n for (int stride = 128; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) {\n float v = svals[threadIdx.x + stride];\n int idx = sidx[threadIdx.x + stride];\n if (v > svals[threadIdx.x] || (v == svals[threadIdx.x] && idx < sidx[threadIdx.x])) {\n svals[threadIdx.x] = v; sidx[threadIdx.x] = idx;\n }\n }\n __syncthreads();\n }\n if (threadIdx.x == 0) out[row] = (int64_t)sidx[0];\n}\n\n__global__ void argmax_dim0_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = D1 * D2;\n if (idx >= total) return;\n int d1 = idx / D2;\n int d2 = idx - d1 * D2;\n float best = x[(long long)d1 * D2 + d2];\n int besti = 0;\n for (int b = 1; b < B; ++b) {\n float v = x[((long long)b * D1 + d1) * D2 + d2];\n if (v > best) { best = v; besti = b; }\n }\n out[idx] = (int64_t)besti;\n}\n\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim) {\n dim = (dim % 3 + 3) % 3;\n const int B = (int)x.size(0);\n const int D1 = (int)x.size(1);\n const int D2 = (int)x.size(2);\n auto opts = torch::TensorOptions().device(x.device()).dtype(torch::kInt64);\n torch::Tensor out;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (dim == 1) {\n out = torch::empty({B, D2}, opts);\n const int threads = 128;\n dim3 grid((D2 + threads * 4 - 1) / (threads * 4), B);\n argmax_dim1_float4cols_kernel<<<grid, threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n } else if (dim == 2) {\n out = torch::empty({B, D1}, opts);\n argmax_dim2_float_kernel<<<B * D1, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n } else {\n out = torch::empty({D1, D2}, opts);\n int total = D1 * D2;\n argmax_dim0_float_kernel<<<(total + 255) / 256, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n }\n return out;\n}\n'''\n\n_ext = load_inline(name='argmax_ext_v2c', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['argmax_forward'], verbose=False,\n extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int):\n super(ModelNew, self).__init__()\n self.dim = dim\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.argmax_forward(x.contiguous(), self.dim)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00
turn 4 · 1 tool call(s) · 36.3s turn · 36.3s LLM · 8,389 chars (click to expand)
turn 436.3s turn · 36.3s LLM · 0.0s tools
reasoning
**Optimizing submission timing**
I need to optimize my final submission, starting with a static check first. However, the timing is uncertain, so I might have to experiment with different variants to find the fastest option before the final submission. Since I don’t have a timing tool, I should infer the best approach using compile options and static checks.
I notice that including `x.contiguous()` in the class makes it more efficient since it avoids extra copies if the input is contiguous. There are concerns about memory patterns and how they impact performance, particularly with threads accessing columns contiguously.
**Improving memory coalescing**
I’m noticing that coalescing for each scalar instruction isn’t efficient because the warp accesses 32 addresses spread out over 500 bytes. While four instructions might cover 128 contiguous bytes, having four columns per thread really harms coalescing. If I switch to one column per thread, each warp could access 32 contiguous floats, which is much better.
Ideally, I’d use a vectorized float4 load to maximize efficiency, but misalignment could cause issues, so I might consider custom loads for 16 bytes. I'll need to decide between these options for optimal performance.
**Examining warp load efficiency**
I’m analyzing the current warp load for `v0`, which accesses addresses based on `base + 4*tid`. This setup means I'm effectively loading 32 floats but every fourth access, resulting in only 128 bytes being useful. Actually, it spans nearly 125 floats, which is around 500 bytes. This translates to loading 16 sectors (which cover 512 bytes) for just 32 useful floats, leading to a disappointing efficiency of about 25%. I clearly need to rethink this approach for better performance.
**Ensuring correctness in pointer increment**
I'm focusing on how to handle pointer increments properly. I need the pointer `p` to point to a float type while handling a long long for iteration. I'll set `p` as `const float* p = x + base;` and then use a loop to increment `p` by `D2` while iterating `k` from 1 to `D1`. Now it’s important to double-check if this setup is correct before moving on to the next steps.
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>\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cstdint>\n#define NEG_INF_F (-3.4028234663852886e38f)\n\n__global__ void argmax_dim1_main4_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2, int groups4) {\n int b = blockIdx.y;\n int group = blockIdx.x * blockDim.x + threadIdx.x;\n if (group >= groups4) return;\n int c = group << 2;\n const float* p = x + (long long)b * D1 * D2 + c;\n float m0 = p[0], m1 = p[1], m2 = p[2], m3 = p[3];\n int i0 = 0, i1 = 0, i2 = 0, i3 = 0;\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n p += D2;\n float v0 = p[0];\n float v1 = p[1];\n float v2 = p[2];\n float v3 = p[3];\n if (v0 > m0) { m0 = v0; i0 = k; }\n if (v1 > m1) { m1 = v1; i1 = k; }\n if (v2 > m2) { m2 = v2; i2 = k; }\n if (v3 > m3) { m3 = v3; i3 = k; }\n }\n int64_t* o = out + (long long)b * D2 + c;\n o[0] = (int64_t)i0; o[1] = (int64_t)i1; o[2] = (int64_t)i2; o[3] = (int64_t)i3;\n}\n\n__global__ void argmax_dim1_tail_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2, int startc) {\n int b = blockIdx.x;\n int c = startc + threadIdx.x;\n if (c >= D2) return;\n const float* p = x + (long long)b * D1 * D2 + c;\n float m = p[0]; int mi = 0;\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n p += D2;\n float v = p[0];\n if (v > m) { m = v; mi = k; }\n }\n out[(long long)b * D2 + c] = (int64_t)mi;\n}\n\n__global__ void argmax_dim2_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int row = blockIdx.x;\n const float* p = x + (long long)row * D2;\n float best = NEG_INF_F; int besti = 0;\n for (int c = threadIdx.x; c < D2; c += blockDim.x) { float v = p[c]; if (v > best) { best = v; besti = c; } }\n __shared__ float svals[256]; __shared__ int sidx[256];\n svals[threadIdx.x] = best; sidx[threadIdx.x] = besti; __syncthreads();\n for (int stride = 128; stride > 0; stride >>= 1) { if (threadIdx.x < stride) { float v=svals[threadIdx.x+stride]; int idx=sidx[threadIdx.x+stride]; if (v>svals[threadIdx.x] || (v==svals[threadIdx.x] && idx<sidx[threadIdx.x])) { svals[threadIdx.x]=v; sidx[threadIdx.x]=idx; } } __syncthreads(); }\n if (threadIdx.x == 0) out[row] = (int64_t)sidx[0];\n}\n\n__global__ void argmax_dim0_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = D1 * D2; if (idx >= total) return;\n int d1 = idx / D2; int d2 = idx - d1 * D2;\n float best = x[(long long)d1 * D2 + d2]; int besti = 0;\n for (int b = 1; b < B; ++b) { float v = x[((long long)b * D1 + d1) * D2 + d2]; if (v > best) { best = v; besti = b; } }\n out[idx] = (int64_t)besti;\n}\n\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim) {\n dim = (dim % 3 + 3) % 3;\n int B=(int)x.size(0), D1=(int)x.size(1), D2=(int)x.size(2);\n auto opts = torch::TensorOptions().device(x.device()).dtype(torch::kInt64);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (dim == 1) {\n torch::Tensor out = torch::empty({B, D2}, opts);\n int groups4 = D2 >> 2;\n int threads = 128;\n if (groups4 > 0) argmax_dim1_main4_kernel<<<dim3((groups4 + threads - 1)/threads, B), threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2, groups4);\n int startc = groups4 << 2;\n if (startc < D2) argmax_dim1_tail_kernel<<<B, 32, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2, startc);\n return out;\n } else if (dim == 2) {\n torch::Tensor out = torch::empty({B, D1}, opts);\n argmax_dim2_float_kernel<<<B * D1, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n return out;\n } else {\n torch::Tensor out = torch::empty({D1, D2}, opts);\n int total = D1 * D2;\n argmax_dim0_float_kernel<<<(total + 255) / 256, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n return out;\n }\n}\n'''\n\n_ext = load_inline(name='argmax_ext_v3c', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['argmax_forward'], verbose=False,\n extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int):\n super(ModelNew, self).__init__()\n self.dim = dim\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.argmax_forward(x.contiguous(), self.dim)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00
turn 515.8s turn · 15.8s LLM · 0.0s tools
call → static_check
callstatic_check
{
"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 argmax_forward(torch::Tensor x, int64_t dim);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cstdint>\n#define NEG_INF_F (-3.4028234663852886e38f)\n\n__global__ void argmax_dim1_main4_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2, int groups4) {\n int b = blockIdx.y;\n int group = blockIdx.x * blockDim.x + threadIdx.x;\n if (group >= groups4) return;\n int c = group << 2;\n const float* p = x + (long long)b * D1 * D2 + c;\n float m0 = p[0], m1 = p[1], m2 = p[2], m3 = p[3];\n int i0 = 0, i1 = 0, i2 = 0, i3 = 0;\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n p += D2;\n float v0 = p[0];\n float v1 = p[1];\n float v2 = p[2];\n float v3 = p[3];\n if (v0 > m0) { m0 = v0; i0 = k; }\n if (v1 > m1) { m1 = v1; i1 = k; }\n if (v2 > m2) { m2 = v2; i2 = k; }\n if (v3 > m3) { m3 = v3; i3 = k; }\n }\n int64_t* o = out + (long long)b * D2 + c;\n o[0] = (int64_t)i0; o[1] = (int64_t)i1; o[2] = (int64_t)i2; o[3] = (int64_t)i3;\n}\n\n__global__ void argmax_dim1_tail_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2, int startc) {\n int b = blockIdx.x;\n int c = startc + threadIdx.x;\n if (c >= D2) return;\n const float* p = x + (long long)b * D1 * D2 + c;\n float m = p[0]; int mi = 0;\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n p += D2;\n float v = p[0];\n if (v > m) { m = v; mi = k; }\n }\n out[(long long)b * D2 + c] = (int64_t)mi;\n}\n\n__global__ void argmax_dim2_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int row = blockIdx.x;\n const float* p = x + (long long)row * D2;\n float best = NEG_INF_F; int besti = 0;\n for (int c = threadIdx.x; c < D2; c += blockDim.x) { float v = p[c]; if (v > best) { best = v; besti = c; } }\n __shared__ float svals[256]; __shared__ int sidx[256];\n svals[threadIdx.x] = best; sidx[threadIdx.x] = besti; __syncthreads();\n for (int stride = 128; stride > 0; stride >>= 1) { if (threadIdx.x < stride) { float v=svals[threadIdx.x+stride]; int idx=sidx[threadIdx.x+stride]; if (v>svals[threadIdx.x] || (v==svals[threadIdx.x] && idx<sidx[threadIdx.x])) { svals[threadIdx.x]=v; sidx[threadIdx.x]=idx; } } __syncthreads(); }\n if (threadIdx.x == 0) out[row] = (int64_t)sidx[0];\n}\n\n__global__ void argmax_dim0_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = D1 * D2; if (idx >= total) return;\n int d1 = idx / D2; int d2 = idx - d1 * D2;\n float best = x[(long long)d1 * D2 + d2]; int besti = 0;\n for (int b = 1; b < B; ++b) { float v = x[((long long)b * D1 + d1) * D2 + d2]; if (v > best) { best = v; besti = b; } }\n out[idx] = (int64_t)besti;\n}\n\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim) {\n dim = (dim % 3 + 3) % 3;\n int B=(int)x.size(0), D1=(int)x.size(1), D2=(int)x.size(2);\n auto opts = torch::TensorOptions().device(x.device()).dtype(torch::kInt64);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (dim == 1) {\n torch::Tensor out = torch::empty({B, D2}, opts);\n int groups4 = D2 >> 2;\n int threads = 128;\n if (groups4 > 0) argmax_dim1_main4_kernel<<<dim3((groups4 + threads - 1)/threads, B), threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2, groups4);\n int startc = groups4 << 2;\n if (startc < D2) argmax_dim1_tail_kernel<<<B, 32, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2, startc);\n return out;\n } else if (dim == 2) {\n torch::Tensor out = torch::empty({B, D1}, opts);\n argmax_dim2_float_kernel<<<B * D1, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n return out;\n } else {\n torch::Tensor out = torch::empty({D1, D2}, opts);\n int total = D1 * D2;\n argmax_dim0_float_kernel<<<(total + 255) / 256, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n return out;\n }\n}\n'''\n\n_ext = load_inline(name='argmax_ext_v3sc', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['argmax_forward'], verbose=False,\n extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int):\n super(ModelNew, self).__init__()\n self.dim = dim\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.argmax_forward(x.contiguous(), self.dim)\n"
}
result ← static_check (ok)
okstatic_check
static_check PASSED: no violations or warnings detected.
turn 6 · FINAL · 1 tool call(s) · 38.9s turn · 38.9s LLM · 7,087 chars (click to expand)
turn 638.9s turn · 38.9s LLM · 0.0s tools · FINAL
reasoning
**Evaluating memory sectors**
I’m thinking about how first v0 touches each of the 32 sectors exactly once per thread, which leads to 32 sectors total. Then, I'm curious whether v1 to v7 affect the same sectors or not. For float offsets within each sector, it seems every one of the 8 values should be accounted for. I'm also considering that DRAM handles this similarly. However, each thread has 16 registers, leading to reduced occupancy, which might be improved.
call → submit_kernel
callsubmit_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 argmax_forward(torch::Tensor x, int64_t dim);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cstdint>\n#define NEG_INF_F (-3.4028234663852886e38f)\n\n__global__ void argmax_dim1_main4_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2, int groups4) {\n int b = blockIdx.y;\n int group = blockIdx.x * blockDim.x + threadIdx.x;\n if (group >= groups4) return;\n int c = group << 2;\n const float* p = x + (long long)b * D1 * D2 + c;\n float m0 = p[0], m1 = p[1], m2 = p[2], m3 = p[3];\n int i0 = 0, i1 = 0, i2 = 0, i3 = 0;\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n p += D2;\n float v0 = p[0];\n float v1 = p[1];\n float v2 = p[2];\n float v3 = p[3];\n if (v0 > m0) { m0 = v0; i0 = k; }\n if (v1 > m1) { m1 = v1; i1 = k; }\n if (v2 > m2) { m2 = v2; i2 = k; }\n if (v3 > m3) { m3 = v3; i3 = k; }\n }\n int64_t* o = out + (long long)b * D2 + c;\n o[0] = (int64_t)i0; o[1] = (int64_t)i1; o[2] = (int64_t)i2; o[3] = (int64_t)i3;\n}\n\n__global__ void argmax_dim1_tail_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2, int startc) {\n int b = blockIdx.x;\n int c = startc + threadIdx.x;\n if (c >= D2) return;\n const float* p = x + (long long)b * D1 * D2 + c;\n float m = p[0]; int mi = 0;\n #pragma unroll 4\n for (int k = 1; k < D1; ++k) {\n p += D2;\n float v = p[0];\n if (v > m) { m = v; mi = k; }\n }\n out[(long long)b * D2 + c] = (int64_t)mi;\n}\n\n__global__ void argmax_dim2_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int row = blockIdx.x;\n const float* p = x + (long long)row * D2;\n float best = NEG_INF_F; int besti = 0;\n for (int c = threadIdx.x; c < D2; c += blockDim.x) { float v = p[c]; if (v > best) { best = v; besti = c; } }\n __shared__ float svals[256]; __shared__ int sidx[256];\n svals[threadIdx.x] = best; sidx[threadIdx.x] = besti; __syncthreads();\n for (int stride = 128; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) {\n float v = svals[threadIdx.x + stride]; int idx = sidx[threadIdx.x + stride];\n if (v > svals[threadIdx.x] || (v == svals[threadIdx.x] && idx < sidx[threadIdx.x])) { svals[threadIdx.x] = v; sidx[threadIdx.x] = idx; }\n }\n __syncthreads();\n }\n if (threadIdx.x == 0) out[row] = (int64_t)sidx[0];\n}\n\n__global__ void argmax_dim0_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,\n int B, int D1, int D2) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = D1 * D2; if (idx >= total) return;\n int d1 = idx / D2; int d2 = idx - d1 * D2;\n float best = x[(long long)d1 * D2 + d2]; int besti = 0;\n for (int b = 1; b < B; ++b) { float v = x[((long long)b * D1 + d1) * D2 + d2]; if (v > best) { best = v; besti = b; } }\n out[idx] = (int64_t)besti;\n}\n\ntorch::Tensor argmax_forward(torch::Tensor x, int64_t dim) {\n dim = (dim % 3 + 3) % 3;\n int B = (int)x.size(0), D1 = (int)x.size(1), D2 = (int)x.size(2);\n auto opts = torch::TensorOptions().device(x.device()).dtype(torch::kInt64);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (dim == 1) {\n torch::Tensor out = torch::empty({B, D2}, opts);\n int groups4 = D2 >> 2;\n const int threads = 128;\n if (groups4 > 0) {\n dim3 grid((groups4 + threads - 1) / threads, B);\n argmax_dim1_main4_kernel<<<grid, threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2, groups4);\n }\n int startc = groups4 << 2;\n if (startc < D2) {\n argmax_dim1_tail_kernel<<<B, 32, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2, startc);\n }\n return out;\n } else if (dim == 2) {\n torch::Tensor out = torch::empty({B, D1}, opts);\n argmax_dim2_float_kernel<<<B * D1, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n return out;\n } else {\n torch::Tensor out = torch::empty({D1, D2}, opts);\n int total = D1 * D2;\n argmax_dim0_float_kernel<<<(total + 255) / 256, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);\n return out;\n }\n}\n'''\n\n_ext = load_inline(name='argmax_ext_final', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['argmax_forward'], verbose=False,\n extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int):\n super(ModelNew, self).__init__()\n self.dim = dim\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.argmax_forward(x.contiguous(), self.dim)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 3.53 μs
Runtime stats: mean=3.53μs median=?μs std=0.00μs
Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00
Memory: 8227.0 MB peak (ref: 8235.0 MB, ratio: 0.999x)
Kernel launches: 1 (ref: 2, fusion ratio: 2.0)
Energy: 484.96 mJ/run (ref: 485.16 mJ, ratio: 1.0004x)
SOL score: 0.8951
final submitted kernel (126 lines, 5,159 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 argmax_forward(torch::Tensor x, int64_t dim);
'''
_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cstdint>
#define NEG_INF_F (-3.4028234663852886e38f)
__global__ void argmax_dim1_main4_kernel(const float* __restrict__ x, int64_t* __restrict__ out,
int B, int D1, int D2, int groups4) {
int b = blockIdx.y;
int group = blockIdx.x * blockDim.x + threadIdx.x;
if (group >= groups4) return;
int c = group << 2;
const float* p = x + (long long)b * D1 * D2 + c;
float m0 = p[0], m1 = p[1], m2 = p[2], m3 = p[3];
int i0 = 0, i1 = 0, i2 = 0, i3 = 0;
#pragma unroll 4
for (int k = 1; k < D1; ++k) {
p += D2;
float v0 = p[0];
float v1 = p[1];
float v2 = p[2];
float v3 = p[3];
if (v0 > m0) { m0 = v0; i0 = k; }
if (v1 > m1) { m1 = v1; i1 = k; }
if (v2 > m2) { m2 = v2; i2 = k; }
if (v3 > m3) { m3 = v3; i3 = k; }
}
int64_t* o = out + (long long)b * D2 + c;
o[0] = (int64_t)i0; o[1] = (int64_t)i1; o[2] = (int64_t)i2; o[3] = (int64_t)i3;
}
__global__ void argmax_dim1_tail_kernel(const float* __restrict__ x, int64_t* __restrict__ out,
int B, int D1, int D2, int startc) {
int b = blockIdx.x;
int c = startc + threadIdx.x;
if (c >= D2) return;
const float* p = x + (long long)b * D1 * D2 + c;
float m = p[0]; int mi = 0;
#pragma unroll 4
for (int k = 1; k < D1; ++k) {
p += D2;
float v = p[0];
if (v > m) { m = v; mi = k; }
}
out[(long long)b * D2 + c] = (int64_t)mi;
}
__global__ void argmax_dim2_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,
int B, int D1, int D2) {
int row = blockIdx.x;
const float* p = x + (long long)row * D2;
float best = NEG_INF_F; int besti = 0;
for (int c = threadIdx.x; c < D2; c += blockDim.x) { float v = p[c]; if (v > best) { best = v; besti = c; } }
__shared__ float svals[256]; __shared__ int sidx[256];
svals[threadIdx.x] = best; sidx[threadIdx.x] = besti; __syncthreads();
for (int stride = 128; stride > 0; stride >>= 1) {
if (threadIdx.x < stride) {
float v = svals[threadIdx.x + stride]; int idx = sidx[threadIdx.x + stride];
if (v > svals[threadIdx.x] || (v == svals[threadIdx.x] && idx < sidx[threadIdx.x])) { svals[threadIdx.x] = v; sidx[threadIdx.x] = idx; }
}
__syncthreads();
}
if (threadIdx.x == 0) out[row] = (int64_t)sidx[0];
}
__global__ void argmax_dim0_float_kernel(const float* __restrict__ x, int64_t* __restrict__ out,
int B, int D1, int D2) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int total = D1 * D2; if (idx >= total) return;
int d1 = idx / D2; int d2 = idx - d1 * D2;
float best = x[(long long)d1 * D2 + d2]; int besti = 0;
for (int b = 1; b < B; ++b) { float v = x[((long long)b * D1 + d1) * D2 + d2]; if (v > best) { best = v; besti = b; } }
out[idx] = (int64_t)besti;
}
torch::Tensor argmax_forward(torch::Tensor x, int64_t dim) {
dim = (dim % 3 + 3) % 3;
int B = (int)x.size(0), D1 = (int)x.size(1), D2 = (int)x.size(2);
auto opts = torch::TensorOptions().device(x.device()).dtype(torch::kInt64);
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
if (dim == 1) {
torch::Tensor out = torch::empty({B, D2}, opts);
int groups4 = D2 >> 2;
const int threads = 128;
if (groups4 > 0) {
dim3 grid((groups4 + threads - 1) / threads, B);
argmax_dim1_main4_kernel<<<grid, threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2, groups4);
}
int startc = groups4 << 2;
if (startc < D2) {
argmax_dim1_tail_kernel<<<B, 32, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2, startc);
}
return out;
} else if (dim == 2) {
torch::Tensor out = torch::empty({B, D1}, opts);
argmax_dim2_float_kernel<<<B * D1, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);
return out;
} else {
torch::Tensor out = torch::empty({D1, D2}, opts);
int total = D1 * D2;
argmax_dim0_float_kernel<<<(total + 255) / 256, 256, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<int64_t>(), B, D1, D2);
return out;
}
}
'''
_ext = load_inline(name='argmax_ext_final', cpp_sources=_cpp_src, cuda_sources=_cuda_src,
functions=['argmax_forward'], verbose=False,
extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])
class ModelNew(nn.Module):
def __init__(self, dim: int):
super(ModelNew, self).__init__()
self.dim = dim
def forward(self, x: torch.Tensor) -> torch.Tensor:
return _ext.argmax_forward(x.contiguous(), self.dim)