Skip to content
KernelIndex
Search⌘K

submission 66564

Saulane · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

No package. Vendor the mirrored source: 202 lines, June 9 Researcher Reciprocity License v1.0.

submission6.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-vectoradd-v2-66564?include=source"
interfacepython
Compatibility
measured onNVIDIA A100
declared hardwareNVIDIA A100
architecturessm_80
dtypesfp16

Benchmark evidence

1 measurement across 1 GPU, fastest first.

Operation / workload
Hardware
Latency
Rank
Observed
FP16 vector additionsuite of 5 cases
NVIDIA A100
916.2µs
#20 of 87
2025-11-04

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:8bf8cd0979e79a2a2621376a030322d43b3ff32168beabcdb978437b605a850a
license declaredunknown
license concludedunknown
authorsSaulane
imported2026-08-15

Techniques

Extracted from the mirrored source by pattern, never inferred. Each row cites its line.

vector-width = uint4const uint4* __restrict__ a4 = reinterpret_cast<const uint4*>(a);

Kernel source

submission6.py202 lines
import torch
from torch.utils.cpp_extension import load_inline

cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAGuard.h>

#include <cuda.h>
#include <cuda_runtime.h>
#include <cuda_fp16.h>
#include <stdint.h>

// Helpers --------------------------------------------------------------------
static inline int div_up_long(long long n, int d) {
    return (int)((n + d - 1) / d);
}

// Union to safely bit-cast between u32 and __half2
union u32_h2 {
    uint32_t u;
    __half2  h2;
};

// fast path: 128-bit vectorized (8 x fp16 per pack), requires 16B alignment
__global__ void add_fp16_vec8_kernel(const __half* __restrict__ a,
                                     const __half* __restrict__ b,
                                     __half* __restrict__ out,
                                     size_t n_packs /* number of 8-half packs */) {
    const uint4* __restrict__ a4 = reinterpret_cast<const uint4*>(a);
    const uint4* __restrict__ b4 = reinterpret_cast<const uint4*>(b);
    uint4* __restrict__ out4     = reinterpret_cast<uint4*>(out);

    const size_t tid    = blockIdx.x * blockDim.x + threadIdx.x;
    const size_t stride = (size_t)blockDim.x * gridDim.x;

    // ILP to increase memory-level parallelism per thread
    const int ILP = 4;
    size_t i = tid;

    for (; i + (size_t)(ILP - 1) * stride < n_packs; i += (size_t)ILP * stride) {
        #pragma unroll
        for (int k = 0; k < ILP; ++k) {
            size_t idx = i + (size_t)k * stride;
            uint4 av = a4[idx];
            uint4 bv = b4[idx];

            // Each uint4.{x,y,z,w} is 32-bit = __half2
            u32_h2 a0; a0.u = av.x; u32_h2 b0; b0.u = bv.x; u32_h2 r0; r0.h2 = __hadd2(a0.h2, b0.h2);
            u32_h2 a1; a1.u = av.y; u32_h2 b1; b1.u = bv.y; u32_h2 r1; r1.h2 = __hadd2(a1.h2, b1.h2);
            u32_h2 a2; a2.u = av.z; u32_h2 b2; b2.u = bv.z; u32_h2 r2; r2.h2 = __hadd2(a2.h2, b2.h2);
            u32_h2 a3; a3.u = av.w; u32_h2 b3; b3.u = bv.w; u32_h2 r3; r3.h2 = __hadd2(a3.h2, b3.h2);

            uint4 rv;
            rv.x = r0.u; rv.y = r1.u; rv.z = r2.u; rv.w = r3.u;
            out4[idx] = rv;
        }
    }
    for (; i < n_packs; i += stride) {
        uint4 av = a4[i];
        uint4 bv = b4[i];
        u32_h2 a0; a0.u = av.x; u32_h2 b0; b0.u = bv.x; u32_h2 r0; r0.h2 = __hadd2(a0.h2, b0.h2);
        u32_h2 a1; a1.u = av.y; u32_h2 b1; b1.u = bv.y; u32_h2 r1; r1.h2 = __hadd2(a1.h2, b1.h2);
        u32_h2 a2; a2.u = av.z; u32_h2 b2; b2.u = bv.z; u32_h2 r2; r2.h2 = __hadd2(a2.h2, b2.h2);
        u32_h2 a3; a3.u = av.w; u32_h2 b3; b3.u = bv.w; u32_h2 r3; r3.h2 = __hadd2(a3.h2, b3.h2);
        uint4 rv; rv.x = r0.u; rv.y = r1.u; rv.z = r2.u; rv.w = r3.u;
        out4[i] = rv;
    }
}

// medium path: __half2 (4B), requires 4B alignment; 2 x fp16 per element
__global__ void add_fp16_h2_kernel(const __half2* __restrict__ a,
                                   const __half2* __restrict__ b,
                                   __half2* __restrict__ out,
                                   size_t n_h2) {
    const size_t tid    = blockIdx.x * blockDim.x + threadIdx.x;
    const size_t stride = (size_t)blockDim.x * gridDim.x;
    for (size_t i = tid; i < n_h2; i += stride) {
        out[i] = __hadd2(a[i], b[i]);
    }
}

// tail / worst-case path: scalar half (handles misalignment + remainder)
__global__ void add_fp16_scalar_kernel(const __half* __restrict__ a,
                                       const __half* __restrict__ b,
                                       __half* __restrict__ out,
                                       size_t n) {
    const size_t tid    = blockIdx.x * blockDim.x + threadIdx.x;
    const size_t stride = (size_t)blockDim.x * gridDim.x;
    for (size_t i = tid; i < n; i += stride) {
        out[i] = __hadd(a[i], b[i]);
    }
}

void add_fp16_out(torch::Tensor a, torch::Tensor b, torch::Tensor out) {
    TORCH_CHECK(a.is_cuda() && b.is_cuda() && out.is_cuda(), "Tensors must be CUDA");
    TORCH_CHECK(a.scalar_type() == torch::kHalf && b.scalar_type() == torch::kHalf && out.scalar_type() == torch::kHalf,
                "Tensors must be torch.float16");
    TORCH_CHECK(a.is_contiguous() && b.is_contiguous() && out.is_contiguous(), "Tensors must be contiguous");
    TORCH_CHECK(a.sizes() == b.sizes() && a.sizes() == out.sizes(), "Shapes must match");

    c10::cuda::CUDAGuard device_guard(a.get_device());
    auto* a_ptr = reinterpret_cast<const __half*>(a.data_ptr<at::Half>());
    auto* b_ptr = reinterpret_cast<const __half*>(b.data_ptr<at::Half>());
    auto* o_ptr = reinterpret_cast<__half*>(out.data_ptr<at::Half>());

    const size_t n = (size_t)out.numel();
    if (n == 0) return;

    cudaStream_t stream = at::cuda::getCurrentCUDAStream();

    // Choose launch geometry
    const int threads = 256;
    const int sm = at::cuda::getCurrentDeviceProperties()->multiProcessorCount;
    int blocks;

    // Check alignments
    uintptr_t a_addr = reinterpret_cast<uintptr_t>(a_ptr);
    uintptr_t b_addr = reinterpret_cast<uintptr_t>(b_ptr);
    uintptr_t o_addr = reinterpret_cast<uintptr_t>(o_ptr);

    const bool aligned16 = ((a_addr | b_addr | o_addr) & 0xF) == 0; // 16B
    const bool aligned4  = ((a_addr | b_addr | o_addr) & 0x3) == 0; // 4B

    if (aligned16) {
        const size_t n_packs = n / 8;  // 8 half per 128-bit pack
        if (n_packs) {
            blocks = std::min(div_up_long((long long)n_packs, threads), sm * 32);
            add_fp16_vec8_kernel<<<blocks, threads, 0, stream>>>(a_ptr, b_ptr, o_ptr, n_packs);
        }
        const size_t tail = n - n_packs * 8;
        if (tail) {
            const __half* a_tail = a_ptr + n_packs * 8;
            const __half* b_tail = b_ptr + n_packs * 8;
            __half*       o_tail = o_ptr + n_packs * 8;
            blocks = std::min(div_up_long((long long)tail, threads), sm * 4);
            add_fp16_scalar_kernel<<<blocks, threads, 0, stream>>>(a_tail, b_tail, o_tail, tail);
        }
    } else if (aligned4) {
        const size_t n_h2 = n / 2;
        if (n_h2) {
            blocks = std::min(div_up_long((long long)n_h2, threads), sm * 32);
            const __half2* a2 = reinterpret_cast<const __half2*>(a_ptr);
            const __half2* b2 = reinterpret_cast<const __half2*>(b_ptr);
            __half2*       o2 = reinterpret_cast<__half2*>(o_ptr);
            add_fp16_h2_kernel<<<blocks, threads, 0, stream>>>(a2, b2, o2, n_h2);
        }
        if (n & 1) {
            const __half* a_tail = a_ptr + (n_h2 * 2);
            const __half* b_tail = b_ptr + (n_h2 * 2);
            __half*       o_tail = o_ptr + (n_h2 * 2);
            add_fp16_scalar_kernel<<<1, 32, 0, stream>>>(a_tail, b_tail, o_tail, 1);
        }
    } else {
        blocks = std::min(div_up_long((long long)n, threads), sm * 32);
        add_fp16_scalar_kernel<<<blocks, threads, 0, stream>>>(a_ptr, b_ptr, o_ptr, n);
    }

    TORCH_CHECK(cudaGetLastError() == cudaSuccess, "CUDA kernel launch failed");
}

PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
    m.def("add_fp16_out", &add_fp16_out, "Vector add (fp16) into out (CUDA)");
}
"""

ext = load_inline(
    name="vecadd_fp16_inline",
    cpp_sources="",
    cuda_sources=cuda_src,
    extra_cflags=["-O3"],
    extra_cuda_cflags=[
        "-O3",
        "--use_fast_math",
        # Enable half/half2 intrinsics explicitly:
        "-U__CUDA_NO_HALF_OPERATORS__",
        "-U__CUDA_NO_HALF_CONVERSIONS__",
        "-U__CUDA_NO_HALF2_OPERATORS__",   # <-- added
        # "-maxrregcount=64",  # optional tuning
    ],
    verbose=False,
    with_cuda=True,
)

def add_cuda_(A: torch.Tensor, B: torch.Tensor, out: torch.Tensor):
    assert A.is_cuda and B.is_cuda and out.is_cuda
    assert A.dtype == torch.float16 and B.dtype == torch.float16 and out.dtype == torch.float16
    assert A.shape == B.shape == out.shape
    assert A.is_contiguous() and B.is_contiguous() and out.is_contiguous()
    ext.add_fp16_out(A, B, out)
    return out

def add_cuda(A: torch.Tensor, B: torch.Tensor) -> torch.Tensor:
    out = torch.empty_like(A)
    return add_cuda_(A, B, out)


def custom_kernel(data):
    A, B, output = data
    add_cuda_(A, B, output)   # writes directly into 'output'
    return output
scrolls · 202 lines total

Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0

Changes from previous submission

Against this author's previous submission submission 66563.

Best evidence level for this revision: reported

JSON