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.
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 = uint4
void 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, DeterministicContextimport torchfrom 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 linesreturn 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