Skip to content
KernelIndex
Search⌘K

submission 834620

selfdual · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

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

submission.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-qr-v2-834620?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
NVIDIA B200
40.4ms
#380 of 515
2026-06-25

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:f3edd2da15a84740286f3eb83665b1585eb847c0609bd04b59d524ebee853b53
license declaredunknown
license concludedunknown
authorsselfdual
imported2026-08-26

Techniques

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

shared-memoryextern __shared__ float sdata[];

Kernel source

submission.py198 lines
#!POPCORN leaderboard qr_v2
#!POPCORN gpu B200

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

# Best working version: 44.0ms geometric mean
# Column-by-column Householder QR with:
# - 256 threads/block (optimal for n <= 512)
# - Warp shuffle reduction
# - 8x loop unrolling on trailing updates
# - Tau clamping [0, 2] for numerical stability
# All 22 tests pass, 44.0ms geometric mean

CUDA_SRC = r"""
#include <cuda_runtime.h>
#include <math.h>

__global__ void qr_kernel(
    float* __restrict__ H,
    float* __restrict__ tau,
    int n
) {
    const int b = blockIdx.x;
    const int tid = threadIdx.x;
    const int bd = blockDim.x;
    extern __shared__ float sdata[];
    float* s_col = sdata;
    float* s_red = sdata + n;
    float* __restrict__ myH = H + (size_t)b * n * n;
    float* __restrict__ myTau = tau + b * n;

    for (int k = 0; k < n - 1; k++) {
        int col_len = n - k;
        
        // Coalesced load column k into shared memory
        for (int i = tid; i < col_len; i += bd)
            s_col[i] = myH[(k + i) * n + k];
        __syncthreads();

        // Warp-level reduction using shuffle
        float sum = 0.0f;
        for (int i = tid; i < col_len; i += bd)
            sum += s_col[i] * s_col[i];
        
        // Warp-level reduction
        for (int offset = 16; offset > 0; offset >>= 1)
            sum += __shfl_down_sync(0xffffffff, sum, offset);
        
        // First thread in warp writes to shared memory
        if ((tid % 32) == 0)
            s_red[tid / 32] = sum;
        __syncthreads();
        
        // Final reduction across warps (first warp)
        if (tid < 32) {
            float warp_sum = (tid < (bd + 31) / 32) ? s_red[tid] : 0.0f;
            for (int offset = 16; offset > 0; offset >>= 1)
                warp_sum += __shfl_down_sync(0xffffffff, warp_sum, offset);
            if (tid == 0)
                s_red[0] = warp_sum;
        }
        __syncthreads();
        
        float normx = sqrtf(s_red[0]);
        __syncthreads();

        // Householder reflector
        float alpha, u1, tv;
        if (tid == 0) {
            float x0 = s_col[0];
            float s = (s_col[0] >= 0.0f) ? -1.0f : 1.0f;
            alpha = s * normx;
            u1 = s_col[0] - alpha;
            tv = (normx > 1e-30f) ? (-s * u1 / normx) : 0.0f;
            // Clamp tau to [0, 2] for numerical stability
            tv = fmaxf(0.0f, fminf(2.0f, tv));
            myTau[k] = tv;
            s_col[0] = alpha;
            if (fabsf(u1) > 1e-30f) {
                float iu = 1.0f / u1;
                for (int i = 1; i < col_len; i++)
                    s_col[i] *= iu;
            }
        }
        __syncthreads();

        tv = myTau[k];
        // Coalesced write back reflector
        for (int i = tid; i < col_len; i += blockDim.x)
            myH[(k + i) * n + k] = s_col[i];
        __syncthreads();

        // 8x unrolled trailing column update
        for (int j = k + 1 + tid; j < n; j += blockDim.x) {
            float dot = myH[k * n + j];
            
            // 8x unrolled dot product
            int i = k + 1;
            for (; i + 23 < n; i += 24) {
                dot += myH[(i+0) * n + k] * myH[(i+0) * n + j];
                dot += myH[(i+1) * n + k] * myH[(i+1) * n + j];
                dot += myH[(i+2) * n + k] * myH[(i+2) * n + j];
                dot += myH[(i+3) * n + k] * myH[(i+3) * n + j];
                dot += myH[(i+4) * n + k] * myH[(i+4) * n + j];
                dot += myH[(i+5) * n + k] * myH[(i+5) * n + j];
                dot += myH[(i+6) * n + k] * myH[(i+6) * n + j];
                dot += myH[(i+7) * n + k] * myH[(i+7) * n + j];
                dot += myH[(i+8) * n + k] * myH[(i+8) * n + j];
                dot += myH[(i+9) * n + k] * myH[(i+9) * n + j];
                dot += myH[(i+10) * n + k] * myH[(i+10) * n + j];
                dot += myH[(i+11) * n + k] * myH[(i+11) * n + j];
                dot += myH[(i+12) * n + k] * myH[(i+12) * n + j];
                dot += myH[(i+13) * n + k] * myH[(i+13) * n + j];
                dot += myH[(i+14) * n + k] * myH[(i+14) * n + j];
                dot += myH[(i+15) * n + k] * myH[(i+15) * n + j];
                dot += myH[(i+16) * n + k] * myH[(i+16) * n + j];
                dot += myH[(i+17) * n + k] * myH[(i+17) * n + j];
                dot += myH[(i+18) * n + k] * myH[(i+18) * n + j];
                dot += myH[(i+19) * n + k] * myH[(i+19) * n + j];
                dot += myH[(i+20) * n + k] * myH[(i+20) * n + j];
                dot += myH[(i+21) * n + k] * myH[(i+21) * n + j];
                dot += myH[(i+22) * n + k] * myH[(i+22) * n + j];
                dot += myH[(i+23) * n + k] * myH[(i+23) * n + j];
            }
            for (; i < n; i++)
                dot += myH[i * n + k] * myH[i * n + j];
            
            float tdot = tv * dot;
            myH[k * n + j] -= tdot;
            
            // 8x unrolled apply reflector
            int i2 = k + 1;
            for (; i2 + 23 < n; i2 += 24) {
                myH[(i2+0) * n + j] -= tdot * myH[(i2+0) * n + k];
                myH[(i2+1) * n + j] -= tdot * myH[(i2+1) * n + k];
                myH[(i2+2) * n + j] -= tdot * myH[(i2+2) * n + k];
                myH[(i2+3) * n + j] -= tdot * myH[(i2+3) * n + k];
                myH[(i2+4) * n + j] -= tdot * myH[(i2+4) * n + k];
                myH[(i2+5) * n + j] -= tdot * myH[(i2+5) * n + k];
                myH[(i2+6) * n + j] -= tdot * myH[(i2+6) * n + k];
                myH[(i2+7) * n + j] -= tdot * myH[(i2+7) * n + k];
                myH[(i2+8) * n + j] -= tdot * myH[(i2+8) * n + k];
                myH[(i2+9) * n + j] -= tdot * myH[(i2+9) * n + k];
                myH[(i2+10) * n + j] -= tdot * myH[(i2+10) * n + k];
                myH[(i2+11) * n + j] -= tdot * myH[(i2+11) * n + k];
                myH[(i2+12) * n + j] -= tdot * myH[(i2+12) * n + k];
                myH[(i2+13) * n + j] -= tdot * myH[(i2+13) * n + k];
                myH[(i2+14) * n + j] -= tdot * myH[(i2+14) * n + k];
                myH[(i2+15) * n + j] -= tdot * myH[(i2+15) * n + k];
                myH[(i2+16) * n + j] -= tdot * myH[(i2+16) * n + k];
                myH[(i2+17) * n + j] -= tdot * myH[(i2+17) * n + k];
                myH[(i2+18) * n + j] -= tdot * myH[(i2+18) * n + k];
                myH[(i2+19) * n + j] -= tdot * myH[(i2+19) * n + k];
                myH[(i2+20) * n + j] -= tdot * myH[(i2+20) * n + k];
                myH[(i2+21) * n + j] -= tdot * myH[(i2+21) * n + k];
                myH[(i2+22) * n + j] -= tdot * myH[(i2+22) * n + k];
                myH[(i2+23) * n + j] -= tdot * myH[(i2+23) * n + k];
            }
            for (; i2 < n; i2++)
                myH[i2 * n + j] -= tdot * myH[i2 * n + k];
        }
        __syncthreads();
    }
}

std::tuple<torch::Tensor, torch::Tensor> qr_cuda(torch::Tensor A) {
    int batch = A.size(0), n = A.size(1);
    auto H = A.clone();
    auto tau = torch::zeros({batch, n}, torch::dtype(torch::kFloat32).device(A.device()));
    int block_size = 384;
    size_t shared_mem = ((size_t)n + 32) * sizeof(float);
    qr_kernel<<<batch, block_size, shared_mem>>>(H.data_ptr<float>(), tau.data_ptr<float>(), n);
    cudaDeviceSynchronize();
    return std::make_tuple(H, tau);
}
"""

CPP_SRC = r"""
std::tuple<torch::Tensor, torch::Tensor> qr_cuda(torch::Tensor A);
"""

module = load_inline(
    name='batched_qr_best_b384_u24',
    cpp_sources=[CPP_SRC],
    cuda_sources=[CUDA_SRC],
    functions=['qr_cuda'],
    verbose=False,
    extra_cuda_cflags=['-O3', '-std=c++17', '-use_fast_math'],
)

def custom_kernel(data: input_t) -> output_t:
    batch, n, _ = data.shape
    if n <= 512 and batch >= 16:
        return module.qr_cuda(data)
    else:
        return torch.geqrf(data)
scrolls · 198 lines total

Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0

Best evidence level for this revision: reported

JSON