Skip to content
KernelIndex
Search⌘K

submission 772770

horizon52183 · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

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

submission_l4.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-vectorsum-v2-772770?include=source"
interfacepython
Compatibility
measured onNVIDIA L4
declared hardwareNVIDIA L4
architecturessm_89
dtypesfp32

Benchmark evidence

1 measurement across 1 GPU, fastest first.

Operation / workload
Hardware
Latency
Rank
Observed
Vector sum reductionsuite of 6 cases
NVIDIA L4
957.2µs
#15 of 26
2026-04-16

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:abdb7dc44529a699a59c14607dfd779ed40da30693a16d98910ae7579ea8e33d
license declaredunknown
license concludedunknown
authorshorizon52183
imported2026-08-15

Techniques

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

shared-memory__shared__ float smem[32];
vector-width = float4const float4* input4 = reinterpret_cast<const float4*>(input);

Kernel source

submission_l4.py182 lines
#!POPCORN leaderboard vectorsum_v2
#!POPCORN gpu L4

import torch
from torch.utils.cpp_extension import load_inline
from task import input_t, output_t

# Vector sum reduction tuned for NVIDIA L4 (Ada Lovelace, sm_89)
#
# L4 specs:
#   - 58 SMs, 128 CUDA cores/SM = 7424 cores
#   - ~300 GB/s GDDR6 bandwidth (similar to T4 but newer arch)
#   - 48 MB L2 cache (surprisingly large for the bandwidth)
#   - Max 1536 threads/SM, 48 warps/SM
#   - 72W TDP — efficiency-focused GPU
#
# Key tuning decisions:
#   - Bandwidth is the bottleneck (~300 GB/s), much lower than A100/H100
#   - 232 blocks (58 SMs × 4) for full occupancy
#   - 128 threads/block to keep register pressure low on Ada
#   - Large L2 helps with partial sum phase

cuda_source = r"""
#include <cuda_runtime.h>

__device__ __forceinline__ float warp_reduce_sum(float val) {
    #pragma unroll
    for (int offset = 16; offset > 0; offset >>= 1) {
        val += __shfl_down_sync(0xffffffff, val, offset);
    }
    return val;
}

__global__ void reduce_tiny(
    const float* __restrict__ input,
    float* __restrict__ output,
    int n
) {
    __shared__ float smem[32];
    const int tid = threadIdx.x;
    float sum = 0.0f;

    for (int i = tid; i < n; i += blockDim.x) {
        sum += input[i];
    }

    sum = warp_reduce_sum(sum);
    const int lane = tid & 31;
    const int warp_id = tid >> 5;

    if (lane == 0) smem[warp_id] = sum;
    __syncthreads();

    const int num_warps = (blockDim.x + 31) / 32;
    if (warp_id == 0) {
        sum = (lane < num_warps) ? smem[lane] : 0.0f;
        sum = warp_reduce_sum(sum);
    }
    if (tid == 0) output[0] = sum;
}

__global__ void reduce_phase1(
    const float* __restrict__ input,
    float* __restrict__ partial_sums,
    int n
) {
    __shared__ float smem[32];
    const int tid = threadIdx.x;
    const int bid = blockIdx.x;
    const int block_size = blockDim.x;
    const int grid_size = gridDim.x * block_size;

    float sum = 0.0f;

    const int n4 = n >> 2;
    const float4* input4 = reinterpret_cast<const float4*>(input);
    for (int i = bid * block_size + tid; i < n4; i += grid_size) {
        float4 v = input4[i];
        sum += v.x + v.y + v.z + v.w;
    }

    int tail_start = n4 << 2;
    for (int i = tail_start + bid * block_size + tid; i < n; i += grid_size) {
        sum += input[i];
    }

    sum = warp_reduce_sum(sum);
    const int lane = tid & 31;
    const int warp_id = tid >> 5;

    if (lane == 0) smem[warp_id] = sum;
    __syncthreads();

    const int num_warps = (block_size + 31) / 32;
    if (warp_id == 0) {
        sum = (lane < num_warps) ? smem[lane] : 0.0f;
        sum = warp_reduce_sum(sum);
    }
    if (tid == 0) partial_sums[bid] = sum;
}

__global__ void reduce_phase2(
    const float* __restrict__ partial_sums,
    float* __restrict__ output,
    int n
) {
    __shared__ float smem[32];
    const int tid = threadIdx.x;
    float sum = 0.0f;

    for (int i = tid; i < n; i += blockDim.x) {
        sum += partial_sums[i];
    }

    sum = warp_reduce_sum(sum);
    const int lane = tid & 31;
    const int warp_id = tid >> 5;

    if (lane == 0) smem[warp_id] = sum;
    __syncthreads();

    const int num_warps = (blockDim.x + 31) / 32;
    if (warp_id == 0) {
        sum = (lane < num_warps) ? smem[lane] : 0.0f;
        sum = warp_reduce_sum(sum);
    }
    if (tid == 0) output[0] = sum;
}

torch::Tensor vector_sum_cuda(torch::Tensor input, torch::Tensor output) {
    const int n = input.numel();

    if (n <= 1024) {
        reduce_tiny<<<1, 128>>>(
            input.data_ptr<float>(), output.data_ptr<float>(), n);
        return output;
    }

    // L4: 58 SMs, 128 threads/block
    const int threads = 128;
    int blocks;

    if (n <= 16384) {
        blocks = min(58, (n / 4 + threads - 1) / threads);
    } else {
        // 58 SMs × 4 blocks/SM = 232 blocks
        blocks = min(232, (n / 4 + threads - 1) / threads);
    }

    auto partial_sums = torch::empty({blocks}, input.options());

    reduce_phase1<<<blocks, threads>>>(
        input.data_ptr<float>(), partial_sums.data_ptr<float>(), n);

    int p2_threads = min(256, ((blocks + 31) / 32) * 32);
    reduce_phase2<<<1, p2_threads>>>(
        partial_sums.data_ptr<float>(), output.data_ptr<float>(), blocks);

    return output;
}
"""

cpp_source = r"""
#include <torch/extension.h>
torch::Tensor vector_sum_cuda(torch::Tensor input, torch::Tensor output);
"""

module = load_inline(
    name="vector_sum_l4",
    cpp_sources=cpp_source,
    cuda_sources=cuda_source,
    functions=["vector_sum_cuda"],
    verbose=False,
    extra_cuda_cflags=["-O3", "--use_fast_math"],
)


def custom_kernel(data: input_t) -> output_t:
    data, output = data
    module.vector_sum_cuda(data, output)
    return output[0]
scrolls · 182 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 772765.

#!POPCORN leaderboard vectorsum_v2
- #!POPCORN gpu H100
+ #!POPCORN gpu L4
import torch
from torch.utils.cpp_extension import load_inline
from task import input_t, output_t
- # Vector sum reduction tuned for NVIDIA H100 (Hopper, sm_90)
+ # Vector sum reduction tuned for NVIDIA L4 (Ada Lovelace, sm_89)
#
- # H100 SXM specs:
- # - 132 SMs, 128 CUDA cores/SM = 16896 cores
- # - ~3.35 TB/s HBM3 bandwidth
- # - 50 MB L2 cache
- # - Max 2048 threads/SM, 64 warps/SM
+ # L4 specs:
+ # - 58 SMs, 128 CUDA cores/SM = 7424 cores
+ # - ~300 GB/s GDDR6 bandwidth (similar to T4 but newer arch)
+ # - 48 MB L2 cache (surprisingly large for the bandwidth)
+ # - Max 1536 threads/SM, 48 warps/SM
+ # - 72W TDP — efficiency-focused GPU
#
- # Key tuning decisions vs A100:
- # - More blocks (528 = 132 SMs × 4) to saturate the larger GPU
- # - 256 threads/block, high occupancy
- # - H100's massive bandwidth means we're even more memory-bound
- # - Larger L2 cache helps with phase 2 partial sum reads
+ # Key tuning decisions:
+ # - Bandwidth is the bottleneck (~300 GB/s), much lower than A100/H100
+ # - 232 blocks (58 SMs × 4) for full occupancy
+ # - 128 threads/block to keep register pressure low on Ada
+ # - Large L2 helps with partial sum phase
cuda_source = r"""
#include <cuda_runtime.h>
⋯ 47 unchanged lines
float sum = 0.0f;
- // float4 vectorized loads with grid-stride loop
const int n4 = n >> 2;
const float4* input4 = reinterpret_cast<const float4*>(input);
for (int i = bid * block_size + tid; i < n4; i += grid_size) {
⋯ 1 unchanged lines
sum += v.x + v.y + v.z + v.w;
}
- // Tail
int tail_start = n4 << 2;
for (int i = tail_start + bid * block_size + tid; i < n; i += grid_size) {
sum += input[i];
⋯ 46 unchanged lines
const int n = input.numel();
if (n <= 1024) {
- reduce_tiny<<<1, 256>>>(
+ reduce_tiny<<<1, 128>>>(
input.data_ptr<float>(), output.data_ptr<float>(), n);
return output;
}
- // H100: 132 SMs, 256 threads/block
- const int threads = 256;
+ // L4: 58 SMs, 128 threads/block
+ const int threads = 128;
int blocks;
- if (n <= 32768) {
- blocks = min(132, (n / 4 + threads - 1) / threads);
+ if (n <= 16384) {
+ blocks = min(58, (n / 4 + threads - 1) / threads);
} else {
- // 132 SMs × 4 blocks/SM = 528 blocks for full occupancy
- blocks = min(528, (n / 4 + threads - 1) / threads);
+ // 58 SMs × 4 blocks/SM = 232 blocks
+ blocks = min(232, (n / 4 + threads - 1) / threads);
}
auto partial_sums = torch::empty({blocks}, input.options());
⋯ 15 unchanged lines
"""
module = load_inline(
- name="vector_sum_h100",
+ name="vector_sum_l4",
cpp_sources=cpp_source,
cuda_sources=cuda_source,
functions=["vector_sum_cuda"],
scrolls · 89 diff lines total

Best evidence level for this revision: reported

JSON