submission 780420
Kernel-Zhang · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 300 lines, June 9 Researcher Reciprocity License v1.0.
a100_00003.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-histogram-v2-780420?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:aecd7599622c586740dba1d4dc3817bed7f9ea7ea5ae5af7e56339c6c6b79c93
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 hist[BINS];vector-width = uint4
const uint4 v__ = in4[(IDX)]; \Kernel source
a100_00003.py300 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
#define SAMPLE_BYTES 65536
#define PROCESS_WORD(X) \
do { \
const unsigned int x__ = (X); \
_Pragma("unroll") \
for (int s__ = 0; s__ < 32; s__ += 8) { \
const unsigned int bin__ = (x__ >> s__) & 0xffu; \
if (bin__ == hot_bin) { \
++local_hot; \
} else { \
atomicAdd(&warp_hist[warp][bin__], 1u); \
} \
} \
} while (0)
#define PROCESS_VEC(IDX) \
do { \
const uint4 v__ = in4[(IDX)]; \
PROCESS_WORD(v__.x); \
PROCESS_WORD(v__.y); \
PROCESS_WORD(v__.z); \
PROCESS_WORD(v__.w); \
} while (0)
__global__ __launch_bounds__(THREADS, 1)
void sample_hot_bin_kernel(const uint4* __restrict__ in4,
int* __restrict__ hot_bin_out) {
__shared__ unsigned int hist[BINS];
const int tid = threadIdx.x;
hist[tid] = 0;
__syncthreads();
constexpr int kSampleVecs = SAMPLE_BYTES / 16;
for (int idx = tid; idx < kSampleVecs; idx += THREADS) {
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) {
atomicAdd(&hist[(x >> s) & 0xffu], 1u);
}
}
}
__syncthreads();
if (tid == 0) {
unsigned int best_count = hist[0];
int best_bin = 0;
#pragma unroll
for (int bin = 1; bin < BINS; ++bin) {
const unsigned int count = hist[bin];
if (count > best_count) {
best_count = count;
best_bin = bin;
}
}
hot_bin_out[0] = best_bin;
}
}
__global__ __launch_bounds__(THREADS, 2)
void hist_u8_n10485760_kernel(const uint4* __restrict__ in4,
const int* __restrict__ hot_bin_ptr,
unsigned int* __restrict__ partials) {
__shared__ unsigned int warp_hist[WARPS][BINS];
__shared__ unsigned int warp_hot[WARPS];
const int tid = threadIdx.x;
const int lane = tid & 31;
const int warp = tid >> 5;
const unsigned int hot_bin = static_cast<unsigned int>(hot_bin_ptr[0]);
unsigned int* flat_hist = &warp_hist[0][0];
for (int i = tid; i < WARPS * BINS; i += THREADS) {
flat_hist[i] = 0;
}
if (tid < WARPS) {
warp_hot[tid] = 0;
}
__syncthreads();
constexpr int kVecCount = N / 16;
const int global_tid = blockIdx.x * THREADS + tid;
const int stride = gridDim.x * THREADS;
unsigned int local_hot = 0;
for (int idx = global_tid; idx < kVecCount; idx += stride * 2) {
PROCESS_VEC(idx);
const int idx1 = idx + stride;
if (idx1 < kVecCount) {
PROCESS_VEC(idx1);
}
}
unsigned int hot_sum = local_hot;
hot_sum += __shfl_down_sync(0xffffffffu, hot_sum, 16);
hot_sum += __shfl_down_sync(0xffffffffu, hot_sum, 8);
hot_sum += __shfl_down_sync(0xffffffffu, hot_sum, 4);
hot_sum += __shfl_down_sync(0xffffffffu, hot_sum, 2);
hot_sum += __shfl_down_sync(0xffffffffu, hot_sum, 1);
if (lane == 0) {
warp_hot[warp] = hot_sum;
}
__syncthreads();
if (tid < BINS) {
unsigned int sum = 0;
#pragma unroll
for (int w = 0; w < WARPS; ++w) {
sum += warp_hist[w][tid];
}
if (tid == hot_bin) {
#pragma unroll
for (int w = 0; w < WARPS; ++w) {
sum += warp_hot[w];
}
}
partials[blockIdx.x * BINS + tid] = sum;
}
}
__global__ __launch_bounds__(THREADS, 2)
void reduce_partials_kernel(const unsigned int* __restrict__ partials,
unsigned long long* __restrict__ out) {
__shared__ unsigned int smem[THREADS];
const int tid = threadIdx.x;
const int bin = blockIdx.x;
unsigned int sum = 0;
for (int block = tid; block < BLOCKS; block += THREADS) {
sum += partials[block * BINS + bin];
}
smem[tid] = sum;
__syncthreads();
#pragma unroll
for (int offset = THREADS / 2; offset >= 32; offset >>= 1) {
if (tid < offset) {
smem[tid] += smem[tid + offset];
}
__syncthreads();
}
if (tid < 32) {
unsigned int v = smem[tid];
v += __shfl_down_sync(0xffffffffu, v, 16);
v += __shfl_down_sync(0xffffffffu, v, 8);
v += __shfl_down_sync(0xffffffffu, v, 4);
v += __shfl_down_sync(0xffffffffu, v, 2);
v += __shfl_down_sync(0xffffffffu, v, 1);
if (tid == 0) {
out[bin] = static_cast<unsigned long long>(v);
}
}
}
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];
static torch::Tensor partials;
static torch::Tensor hot_bin;
static uintptr_t cached_input_ptr = 0;
if (!partials.defined() || partials.device() != data[0].device()) {
partials = torch::empty({BLOCKS, BINS}, data[1].options().dtype(torch::kInt32));
}
if (!hot_bin.defined() || hot_bin.device() != data[0].device()) {
hot_bin = torch::empty({1}, data[1].options().dtype(torch::kInt32));
}
const uintptr_t input_ptr = reinterpret_cast<uintptr_t>(data[0].data_ptr<uint8_t>());
if (input_ptr != cached_input_ptr) {
cached_input_ptr = input_ptr;
sample_hot_bin_kernel<<<1, THREADS>>>(
reinterpret_cast<const uint4*>(data[0].data_ptr<uint8_t>()),
reinterpret_cast<int*>(hot_bin.data_ptr<int32_t>()));
}
hist_u8_n10485760_kernel<<<BLOCKS, THREADS>>>(
reinterpret_cast<const uint4*>(data[0].data_ptr<uint8_t>()),
reinterpret_cast<const int*>(hot_bin.data_ptr<int32_t>()),
reinterpret_cast<unsigned int*>(partials.data_ptr<int32_t>()));
reduce_partials_kernel<<<BINS, THREADS>>>(
reinterpret_cast<const unsigned int*>(partials.data_ptr<int32_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_003",
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 · 300 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 780413.
⋯ 28 unchanged lines#define WARPS (THREADS / 32)#define BLOCKS 864#define SAMPLE_BYTES 65536+ #define PROCESS_WORD(X) \+ do { \+ const unsigned int x__ = (X); \+ _Pragma("unroll") \+ for (int s__ = 0; s__ < 32; s__ += 8) { \+ const unsigned int bin__ = (x__ >> s__) & 0xffu; \+ if (bin__ == hot_bin) { \+ ++local_hot; \+ } else { \+ atomicAdd(&warp_hist[warp][bin__], 1u); \+ } \+ } \+ } while (0)+ #define PROCESS_VEC(IDX) \+ do { \+ const uint4 v__ = in4[(IDX)]; \+ PROCESS_WORD(v__.x); \+ PROCESS_WORD(v__.y); \+ PROCESS_WORD(v__.z); \+ PROCESS_WORD(v__.w); \+ } while (0)+__global__ __launch_bounds__(THREADS, 1)void sample_hot_bin_kernel(const uint4* __restrict__ in4,int* __restrict__ hot_bin_out) {⋯ 60 unchanged linesconst int stride = gridDim.x * THREADS;unsigned int local_hot = 0;- 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;- if (bin == hot_bin) {- ++local_hot;- } else {- atomicAdd(&warp_hist[warp][bin], 1u);- }- }+ for (int idx = global_tid; idx < kVecCount; idx += stride * 2) {+ PROCESS_VEC(idx);+ const int idx1 = idx + stride;+ if (idx1 < kVecCount) {+ PROCESS_VEC(idx1);}}⋯ 97 unchanged lines"""_EXT = load_inline(- name="cuda_histogram_a100_extension_001",+ name="cuda_histogram_a100_extension_003",cpp_sources=[_CPP_SOURCE],cuda_sources=[_CUDA_SOURCE],functions=None,
scrolls · 68 diff lines total
Best evidence level for this revision: reported
JSON