submission 780413
Kernel-Zhang · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 290 lines, June 9 Researcher Reciprocity License v1.0.
a100_00002.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-histogram-v2-780413?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:ff0dcb664d41979765ea4fab59a995b6cfcd6d165f87c76cc88d7187283468d4
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
void sample_hot_bin_kernel(const uint4* __restrict__ in4,Kernel source
a100_00002.py290 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
__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) {
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);
}
}
}
}
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_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 · 290 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 780297.
⋯ 27 unchanged lines#define THREADS 256#define WARPS (THREADS / 32)#define BLOCKS 864+ #define SAMPLE_BYTES 65536- __global__ void zero_bins_kernel(unsigned long long* __restrict__ out) {+ __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;- if (tid < BINS) {- out[tid] = 0;+ 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,- unsigned long long* __restrict__ out) {+ 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) {const uint4 v = in4[idx];⋯ 6 unchanged lines#pragma unrollfor (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));+ if (bin == hot_bin) {+ ++local_hot;+ } else {+ atomicAdd(&warp_hist[warp][bin], 1u);}}}}+ 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) {⋯ 2 unchanged linesfor (int w = 0; w < WARPS; ++w) {sum += warp_hist[w][tid];}- atomicAdd(out + tid, static_cast<unsigned long long>(sum));+ 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];- zero_bins_kernel<<<1, BINS>>>(- reinterpret_cast<unsigned long long*>(output.data_ptr<int64_t>()));+ 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 {
scrolls · 190 diff lines total
Best evidence level for this revision: reported
JSON