Skip to content
KernelIndex
Search⌘K

submission 682865

ngolhn · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

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

submission.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-sort-v2-682865?include=source"
interfacepython
Compatibility
measured onNVIDIA B200
declared hardwareNVIDIA B200
architecturessm_100
dtypesfp32

Benchmark evidence

1 measurement across 1 GPU, fastest first.

Operation / workload
Hardware
Latency
Rank
Observed
Sortsuite of 5 cases
NVIDIA B200
1.68ms
#2 of 23
2026-03-31

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:4a8d8d4d97a86b68b5dba84b9b8f2dd3b067c18b9ab1cae311987adbf90dc3dc
license declaredunknown
license concludedunknown
authorsngolhn
imported2026-08-15

Kernel source

submission.py107 lines
#!POPCORN leaderboard sort_v2
#!POPCORN gpu B200

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

# Download libcusort.cuh from GitHub if not present
_header_path = "/tmp/libcusort.cuh"
if not os.path.exists(_header_path) or os.path.getsize(_header_path) < 170000:
    import urllib.request, json, base64
    url = "https://api.github.com/repos/IlyaGrebnov/libcusort/contents/libcusort.cuh"
    req = urllib.request.Request(url, headers={"Accept": "application/vnd.github.v3+json"})
    with urllib.request.urlopen(req, timeout=30) as resp:
        data = json.loads(resp.read())
    content = base64.b64decode(data["content"])
    with open(_header_path, "wb") as f:
        f.write(content)

cuda_src = r"""
#include <torch/extension.h>
#include <libcusort.cuh>

static void* d_temp = nullptr;
static size_t d_temp_size = 0;
static float* d_alt = nullptr;
static bool initialized = false;
static const long long MAX_N = 100000000;

void sort_init(long long max_n) {
    if (initialized) return;

    // Allocate alternate buffer for DoubleBuffer
    cudaMalloc(&d_alt, max_n * sizeof(float));

    cusort::DoubleBuffer<float> d_keys((float*)nullptr, d_alt);
    d_temp_size = 0;
    cusort::DeviceRadixSort::SortKeys(
        nullptr, d_temp_size,
        d_keys, max_n, 0, 32);
    cudaMalloc(&d_temp, d_temp_size);
    initialized = true;
}

// DoubleBuffer sort: copy input to output first, then sort from output
// with alt as scratch. For 32-bit float (4 passes, even), result lands
// in buffer[0] which is output. No extra copy needed after sort.
void sort_raw(int64_t in_ptr, int64_t out_ptr, long long N) {
    float* input = reinterpret_cast<float*>(in_ptr);
    float* output = reinterpret_cast<float*>(out_ptr);

    // Copy input data into output buffer
    cudaMemcpyAsync(output, input, N * sizeof(float),
                    cudaMemcpyDeviceToDevice, 0);

    // DoubleBuffer: output is buf[0], alt is buf[1]
    cusort::DoubleBuffer<float> d_keys(output, d_alt);

    size_t temp_size = d_temp_size;
    cusort::DeviceRadixSort::SortKeys(
        d_temp, temp_size,
        d_keys, N, 0, 32);

    // For 4 passes (even), result should be in buf[0] = output
    // If selector != 0, copy from alt to output
    if (d_keys.selector != 0) {
        cudaMemcpyAsync(output, d_alt, N * sizeof(float),
                        cudaMemcpyDeviceToDevice, 0);
    }
}
"""

cpp_src = r"""
void sort_init(long long max_n);
void sort_raw(int64_t in_ptr, int64_t out_ptr, long long N);
"""

_ext = load_inline(
    name="libcusort_db2",
    cpp_sources=cpp_src,
    cuda_sources=cuda_src,
    functions=["sort_init", "sort_raw"],
    with_cuda=True,
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3", "--use_fast_math", "-arch=sm_100a", "-I/tmp"],
    verbose=False,
)

# Pre-allocate for max size
_ext.sort_init(100_000_000)

# Aggressive warmup: 20 iterations to prime CUDA Graph cache
_wd = torch.randn(100_000_000, device="cuda", dtype=torch.float32)
_wo = torch.empty_like(_wd)
for _ in range(20):
    _ext.sort_raw(_wd.data_ptr(), _wo.data_ptr(), _wd.numel())
torch.cuda.synchronize()
del _wd, _wo
torch.cuda.empty_cache()


def custom_kernel(data: input_t) -> output_t:
    data_in, output = data
    _ext.sort_raw(data_in.data_ptr(), output.data_ptr(), data_in.numel())
    return output
scrolls · 107 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 682591.

⋯ 3 unchanged lines
import torch
from torch.utils.cpp_extension import load_inline
from task import input_t, output_t
+ import os
+ # Download libcusort.cuh from GitHub if not present
+ _header_path = "/tmp/libcusort.cuh"
+ if not os.path.exists(_header_path) or os.path.getsize(_header_path) < 170000:
+ import urllib.request, json, base64
+ url = "https://api.github.com/repos/IlyaGrebnov/libcusort/contents/libcusort.cuh"
+ req = urllib.request.Request(url, headers={"Accept": "application/vnd.github.v3+json"})
+ with urllib.request.urlopen(req, timeout=30) as resp:
+ data = json.loads(resp.read())
+ content = base64.b64decode(data["content"])
+ with open(_header_path, "wb") as f:
+ f.write(content)
+
cuda_src = r"""
#include <torch/extension.h>
- #include <cub/cub.cuh>
+ #include <libcusort.cuh>
static void* d_temp = nullptr;
static size_t d_temp_size = 0;
+ static float* d_alt = nullptr;
+ static bool initialized = false;
+ static const long long MAX_N = 100000000;
void sort_init(long long max_n) {
- size_t needed = 0;
- // Use long long offset type for potentially faster CUB path
- cub::DeviceRadixSort::SortKeys(
- nullptr, needed,
- (const float*)nullptr, (float*)nullptr,
- max_n, 0, 32);
+ if (initialized) return;
- if (needed > d_temp_size) {
- if (d_temp) cudaFree(d_temp);
- d_temp_size = needed;
- cudaMalloc(&d_temp, d_temp_size);
- }
+ // Allocate alternate buffer for DoubleBuffer
+ cudaMalloc(&d_alt, max_n * sizeof(float));
+
+ cusort::DoubleBuffer<float> d_keys((float*)nullptr, d_alt);
+ d_temp_size = 0;
+ cusort::DeviceRadixSort::SortKeys(
+ nullptr, d_temp_size,
+ d_keys, max_n, 0, 32);
+ cudaMalloc(&d_temp, d_temp_size);
+ initialized = true;
}
+ // DoubleBuffer sort: copy input to output first, then sort from output
+ // with alt as scratch. For 32-bit float (4 passes, even), result lands
+ // in buffer[0] which is output. No extra copy needed after sort.
void sort_raw(int64_t in_ptr, int64_t out_ptr, long long N) {
+ float* input = reinterpret_cast<float*>(in_ptr);
+ float* output = reinterpret_cast<float*>(out_ptr);
+
+ // Copy input data into output buffer
+ cudaMemcpyAsync(output, input, N * sizeof(float),
+ cudaMemcpyDeviceToDevice, 0);
+
+ // DoubleBuffer: output is buf[0], alt is buf[1]
+ cusort::DoubleBuffer<float> d_keys(output, d_alt);
+
size_t temp_size = d_temp_size;
- cub::DeviceRadixSort::SortKeys(
+ cusort::DeviceRadixSort::SortKeys(
d_temp, temp_size,
- reinterpret_cast<const float*>(in_ptr),
- reinterpret_cast<float*>(out_ptr),
- N, 0, 32);
+ d_keys, N, 0, 32);
+
+ // For 4 passes (even), result should be in buf[0] = output
+ // If selector != 0, copy from alt to output
+ if (d_keys.selector != 0) {
+ cudaMemcpyAsync(output, d_alt, N * sizeof(float),
+ cudaMemcpyDeviceToDevice, 0);
+ }
}
"""
⋯ 3 unchanged lines
"""
_ext = load_inline(
- name="cub_sort_ll",
+ name="libcusort_db2",
cpp_sources=cpp_src,
cuda_sources=cuda_src,
functions=["sort_init", "sort_raw"],
with_cuda=True,
extra_cflags=["-O3"],
- extra_cuda_cflags=["-O3", "--use_fast_math", "-arch=sm_100a"],
+ extra_cuda_cflags=["-O3", "--use_fast_math", "-arch=sm_100a", "-I/tmp"],
verbose=False,
)
# Pre-allocate for max size
_ext.sort_init(100_000_000)
- # Warmup with full size
+ # Aggressive warmup: 20 iterations to prime CUDA Graph cache
_wd = torch.randn(100_000_000, device="cuda", dtype=torch.float32)
_wo = torch.empty_like(_wd)
- _ext.sort_raw(_wd.data_ptr(), _wo.data_ptr(), _wd.numel())
+ for _ in range(20):
+ _ext.sort_raw(_wd.data_ptr(), _wo.data_ptr(), _wd.numel())
torch.cuda.synchronize()
del _wd, _wo
torch.cuda.empty_cache()
scrolls · 116 diff lines total

Best evidence level for this revision: reported

JSON