Skip to content
KernelIndex
Search⌘K

submission 780297

Kernel-Zhang · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

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

a100_00002.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-histogram-v2-780297?include=source"
interfacepython
Compatibility
measured onNVIDIA A100
declared hardwareNVIDIA A100
architecturessm_80
dtypesuint8

Benchmark evidence

1 measurement across 1 GPU, fastest first.

Operation / workload
Hardware
Latency
Rank
Observed
Histogramsuite of 6 cases
NVIDIA A100
135.9µs
#12 of 24
2026-04-27

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:3b42c416f35a74010a701946b2028a8c8b7202e7bd5e7d6d98a250deabf07dcd
license declaredunknown
license concludedunknown
authorsKernel-Zhang
imported2026-08-15

Techniques

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

shared-memory__shared__ unsigned int warp_hist[WARPS][BINS];
vector-width = uint4void hist_u8_n10485760_kernel(const uint4* __restrict__ in4,

Kernel source

a100_00002.py179 lines
from utils import make_match_reference, DeterministicContext
import torch
from task import input_t, output_t
import sys
from torch.utils.cpp_extension import load_inline

_CPP_SOURCE = r"""
#include <torch/extension.h>
#include <vector>

torch::Tensor cuda_histogram_a100(std::vector<torch::Tensor> data);

PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
    m.def("cuda_histogram_a100", &cuda_histogram_a100, "Compute histogram with custom CUDA kernel");
}
"""

_CUDA_SOURCE = r"""
#include <torch/extension.h>
#include <c10/cuda/CUDAGuard.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <stdio.h>
#include <stdint.h>

#define N           10485760
#define BINS        256
#define THREADS     256
#define WARPS       (THREADS / 32)
#define BLOCKS      864

__global__ void zero_bins_kernel(unsigned long long* __restrict__ out) {
    const int tid = threadIdx.x;
    if (tid < BINS) {
        out[tid] = 0;
    }
}

__global__ __launch_bounds__(THREADS, 2)
void hist_u8_n10485760_kernel(const uint4* __restrict__ in4,
                              unsigned long long* __restrict__ out) {
    __shared__ unsigned int warp_hist[WARPS][BINS];

    const int tid = threadIdx.x;
    const int lane = tid & 31;
    const int warp = tid >> 5;
    unsigned int* flat_hist = &warp_hist[0][0];

    for (int i = tid; i < WARPS * BINS; i += THREADS) {
        flat_hist[i] = 0;
    }
    __syncthreads();

    constexpr int kVecCount = N / 16;
    const int global_tid = blockIdx.x * THREADS + tid;
    const int stride = gridDim.x * THREADS;

    for (int idx = global_tid; idx < kVecCount; idx += stride) {
        const uint4 v = in4[idx];
        unsigned int words[4] = {v.x, v.y, v.z, v.w};

        #pragma unroll
        for (int w = 0; w < 4; ++w) {
            const unsigned int x = words[w];

            #pragma unroll
            for (int s = 0; s < 32; s += 8) {
                const unsigned int bin = (x >> s) & 0xffu;
                const unsigned int active = __activemask();
                const unsigned int mask = __match_any_sync(active, bin);
                if (lane == (__ffs(mask) - 1)) {
                    atomicAdd(&warp_hist[warp][bin], __popc(mask));
                }
            }
        }
    }

    __syncthreads();

    if (tid < BINS) {
        unsigned int sum = 0;
        #pragma unroll
        for (int w = 0; w < WARPS; ++w) {
            sum += warp_hist[w][tid];
        }
        atomicAdd(out + tid, static_cast<unsigned long long>(sum));
    }
}

torch::Tensor cuda_histogram_a100(std::vector<torch::Tensor> data) {
    if (data[0].numel() == N) {
        const c10::cuda::CUDAGuard device_guard(data[0].device());
        auto output = data[1];
        zero_bins_kernel<<<1, BINS>>>(
            reinterpret_cast<unsigned long long*>(output.data_ptr<int64_t>()));
        hist_u8_n10485760_kernel<<<BLOCKS, THREADS>>>(
            reinterpret_cast<const uint4*>(data[0].data_ptr<uint8_t>()),
            reinterpret_cast<unsigned long long*>(output.data_ptr<int64_t>()));
        return output;
    } else { 
        auto result = torch::bincount(data[0], torch::Tensor(), 256);
        return result;
    }
}
"""

_EXT = load_inline(
    name="cuda_histogram_a100_extension_001",
    cpp_sources=[_CPP_SOURCE],
    cuda_sources=[_CUDA_SOURCE],
    functions=None,
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3 -use_fast_math"],
    with_cuda=True,
    verbose=False,
)

custom_kernel = _EXT.cuda_histogram_a100


def ref_kernel(data: input_t) -> output_t:
    """
    Reference implementation of histogram using PyTorch.
    Args:
        data: tensor of shape (size,)
    Returns:
        Tensor containing bin counts
    """
    with DeterministicContext():
        data, output = data
        # Count values in each bin
        output[...] = torch.bincount(data, minlength=256)
        return output


def generate_input(size: int, contention: float, seed: int) -> input_t:
    """
    Generates random input tensor for histogram.

    Args:
        size: Size of the input tensor (must be multiple of 16)
        contention: float in [0, 100], specifying the percentage of identical values
        seed: Random seed
    Returns:
        The input tensor with values in [0, 255]
    """
    gen = torch.Generator(device='cuda')
    gen.manual_seed(seed)
    
    # Generate integer values between 0 and 256
    data = torch.randint(0, 256, (size,), device='cuda', dtype=torch.uint8, generator=gen)

    # make one value appear quite often, increasing the chance for atomic contention
    evil_value = torch.randint(0, 256, (), device='cuda', dtype=torch.uint8, generator=gen)
    evil_loc = torch.rand((size,), device='cuda', dtype=torch.float32, generator=gen) < (contention / 100.0)
    data[evil_loc] = evil_value

    output = torch.empty(256, device='cuda', dtype=torch.int64).contiguous()

    return data.contiguous(), output


def check_implementation(data, output):
    expected = ref_kernel(data)
    reasons = verbose_allequal(output, expected)

    if len(reasons) > 0:
        return False, "mismatch found! custom implementation doesn't match reference: " + " ".join(reasons)

    return True, ''

def warmup(fn, args, n_warmup=5):
    for _ in range(n_warmup):
        _ = fn(args)
        torch.cuda.synchronize()

N_ELEMENTS = 10485760
# warmup(custom_kernel, generate_input(N_ELEMENTS, 42))
scrolls · 179 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 780284.

- from utils import verbose_allequal, DeterministicContext
+ from utils import make_match_reference, DeterministicContext
import torch
from task import input_t, output_t
+ import sys
+ from torch.utils.cpp_extension import load_inline
- def custom_kernel(data: input_t) -> output_t:
- data, output = data
- # Count values in each bin
- output[...] = torch.bincount(data, minlength=256)
- return output
+ _CPP_SOURCE = r"""
+ #include <torch/extension.h>
+ #include <vector>
+ torch::Tensor cuda_histogram_a100(std::vector<torch::Tensor> data);
+
+ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
+ m.def("cuda_histogram_a100", &cuda_histogram_a100, "Compute histogram with custom CUDA kernel");
+ }
+ """
+
+ _CUDA_SOURCE = r"""
+ #include <torch/extension.h>
+ #include <c10/cuda/CUDAGuard.h>
+ #include <cuda_runtime.h>
+ #include <device_launch_parameters.h>
+ #include <stdio.h>
+ #include <stdint.h>
+
+ #define N 10485760
+ #define BINS 256
+ #define THREADS 256
+ #define WARPS (THREADS / 32)
+ #define BLOCKS 864
+
+ __global__ void zero_bins_kernel(unsigned long long* __restrict__ out) {
+ const int tid = threadIdx.x;
+ if (tid < BINS) {
+ out[tid] = 0;
+ }
+ }
+
+ __global__ __launch_bounds__(THREADS, 2)
+ void hist_u8_n10485760_kernel(const uint4* __restrict__ in4,
+ unsigned long long* __restrict__ out) {
+ __shared__ unsigned int warp_hist[WARPS][BINS];
+
+ const int tid = threadIdx.x;
+ const int lane = tid & 31;
+ const int warp = tid >> 5;
+ unsigned int* flat_hist = &warp_hist[0][0];
+
+ for (int i = tid; i < WARPS * BINS; i += THREADS) {
+ flat_hist[i] = 0;
+ }
+ __syncthreads();
+
+ constexpr int kVecCount = N / 16;
+ const int global_tid = blockIdx.x * THREADS + tid;
+ const int stride = gridDim.x * THREADS;
+
+ for (int idx = global_tid; idx < kVecCount; idx += stride) {
+ const uint4 v = in4[idx];
+ unsigned int words[4] = {v.x, v.y, v.z, v.w};
+
+ #pragma unroll
+ for (int w = 0; w < 4; ++w) {
+ const unsigned int x = words[w];
+
+ #pragma unroll
+ for (int s = 0; s < 32; s += 8) {
+ const unsigned int bin = (x >> s) & 0xffu;
+ const unsigned int active = __activemask();
+ const unsigned int mask = __match_any_sync(active, bin);
+ if (lane == (__ffs(mask) - 1)) {
+ atomicAdd(&warp_hist[warp][bin], __popc(mask));
+ }
+ }
+ }
+ }
+
+ __syncthreads();
+
+ if (tid < BINS) {
+ unsigned int sum = 0;
+ #pragma unroll
+ for (int w = 0; w < WARPS; ++w) {
+ sum += warp_hist[w][tid];
+ }
+ atomicAdd(out + tid, static_cast<unsigned long long>(sum));
+ }
+ }
+
+ torch::Tensor cuda_histogram_a100(std::vector<torch::Tensor> data) {
+ if (data[0].numel() == N) {
+ const c10::cuda::CUDAGuard device_guard(data[0].device());
+ auto output = data[1];
+ zero_bins_kernel<<<1, BINS>>>(
+ reinterpret_cast<unsigned long long*>(output.data_ptr<int64_t>()));
+ hist_u8_n10485760_kernel<<<BLOCKS, THREADS>>>(
+ reinterpret_cast<const uint4*>(data[0].data_ptr<uint8_t>()),
+ reinterpret_cast<unsigned long long*>(output.data_ptr<int64_t>()));
+ return output;
+ } else {
+ auto result = torch::bincount(data[0], torch::Tensor(), 256);
+ return result;
+ }
+ }
+ """
+
+ _EXT = load_inline(
+ name="cuda_histogram_a100_extension_001",
+ cpp_sources=[_CPP_SOURCE],
+ cuda_sources=[_CUDA_SOURCE],
+ functions=None,
+ extra_cflags=["-O3"],
+ extra_cuda_cflags=["-O3 -use_fast_math"],
+ with_cuda=True,
+ verbose=False,
+ )
+
+ custom_kernel = _EXT.cuda_histogram_a100
+
+
def ref_kernel(data: input_t) -> output_t:
"""
Reference implementation of histogram using PyTorch.
⋯ 45 unchanged lines
return True, ''
+ def warmup(fn, args, n_warmup=5):
+ for _ in range(n_warmup):
+ _ = fn(args)
+ torch.cuda.synchronize()
+ N_ELEMENTS = 10485760
+ # warmup(custom_kernel, generate_input(N_ELEMENTS, 42))
scrolls · 140 diff lines total

Best evidence level for this revision: reported

JSON