submission 800261
graphdynamic · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 277 lines, June 9 Researcher Reciprocity License v1.0.
submission.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-qr-v2-800261?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
Reported · How evidence levels are derived →
Source and license
sourceavailable
revision digestsha256:4f9b60335f24de41ccf2b68002c8bf24356ac9794ee5c63af20ba7f6586698a4
license declaredunknown
license concludedunknown
authorsgraphdynamic
imported2026-08-26
Techniques
Extracted from the mirrored source by pattern, never inferred. Each row cites its line.
shared-memory
extern __shared__ float sm[];Kernel source
submission.py277 lines
"""v42 = v41 + baddbmm-fused trailing subtract + in-place V diag. v41 = v40 + allow_tf32(tensor-core GEMMs) + hoist eye + drop redundant self-assign. v40 = v35 + COLUMN-MAJOR shared panel (kills 16-way bank conflicts in norm/apply). v35 = v34 + alpha/beta diagonal RACE FIX (missing syncthreads). v34 — packing-4 (race-fixed) + DOUBLE reductions (fast AND accurate for high-cond). v31: with RACE FIX (compute all w_k -> sync -> update; found via compute-sanitizer on A100). v27/v29: apply (4 cols/reduction via separate registers; 4x fewer syncs). v27:+T moved to bmm + build_T kernel (removes in-kernel VtV reductions). v24: with per-size nb dispatch: nb=16 (n<=1024), nb=8 (n=2048,
where Householder beats geqrf), geqrf (n=4096). v20/v21 base: v15 (fewer per-panel reductions). v20 base: v15 (per-column apply, in-kernel VtV+T) with WARP-shuffle block reductions (no shared tree).
Isolates whether warp reductions are safe; if so -> correct faster Householder.
v15 base: batched blocked Householder QR with a SHARED-MEMORY panel kernel (B200 specialization).
The whole column-panel (rows [kk,n) x nb cols) is staged in the 228 KB shared memory; all the
reflector norms / within-panel applies / VtV / compact-WY T are computed against shared memory
(fast reductions, no global re-reads). Trailing update = 2 cuBLAS batched GEMMs. Panel fits in
shared for n<=1024 (m*nb*4 <= ~131 KB); n>=2048 -> geqrf fallback.
"""
import torch
from torch.utils.cpp_extension import load_inline
torch.backends.cuda.matmul.allow_tf32 = False
_CUDA_SRC = r"""
#include <torch/extension.h>
#include <cuda_runtime.h>
__device__ __forceinline__ float blkReduceSum(float v, float* s, int t, int nt) {
for (int o = 16; o > 0; o >>= 1) v += __shfl_down_sync(0xffffffff, v, o);
int warp = t >> 5, lane = t & 31, nwarps = nt >> 5;
if (lane == 0) s[warp] = v;
__syncthreads();
if (t == 0) { float r = 0.f; for (int w = 0; w < nwarps; ++w) r += s[w]; s[0] = r; }
__syncthreads();
float r = s[0]; __syncthreads(); return r;
}
__device__ __forceinline__ void blkReduceSum4(float& a, float& b_, float& c, float& d, float* s, int t, int nt) {
for (int o = 16; o > 0; o >>= 1) { a += __shfl_down_sync(0xffffffff, a, o); b_ += __shfl_down_sync(0xffffffff, b_, o);
c += __shfl_down_sync(0xffffffff, c, o); d += __shfl_down_sync(0xffffffff, d, o); }
int warp = t >> 5, lane = t & 31, nw = nt >> 5;
if (lane == 0) { s[warp*4+0]=a; s[warp*4+1]=b_; s[warp*4+2]=c; s[warp*4+3]=d; }
__syncthreads();
if (t == 0) { double r0=0,r1=0,r2=0,r3=0; for (int w=0;w<nw;++w){ r0+=s[w*4+0]; r1+=s[w*4+1]; r2+=s[w*4+2]; r3+=s[w*4+3]; }
s[0]=r0; s[1]=r1; s[2]=r2; s[3]=r3; }
__syncthreads();
a=s[0]; b_=s[1]; c=s[2]; d=s[3]; __syncthreads();
}
// One block per matrix. Panel = rows [kk,n) (m of them) x cols [kk,kk+nb). Staged in shared sP
// (row-major sP[r*nb + j], r in [0,m), j in [0,nb)). Emits V (back into M's lower), R diag, tau, T.
extern "C" __global__ void panel_qr_sh(float* __restrict__ Q, float* __restrict__ tau,
int n, int kk, int nb) {
const int b = blockIdx.x;
float* M = Q + (long)b * n * n;
float* tb = tau + (long)b * n;
const int t = threadIdx.x, nt = blockDim.x;
const int m = n - kk;
extern __shared__ float sm[];
float* sP = sm; // m*nb
float* red = sP + (long)m * nb;
float* staus = (float*)(red + nt); // nb
// load panel
for (long idx = t; idx < (long)m * nb; idx += nt) {
int r = idx / nb, j = idx % nb;
sP[(long)j * m + r] = M[(long)(kk + r) * n + (kk + j)];
}
__syncthreads();
for (int jc = 0; jc < nb; ++jc) {
// norm of sP[r,jc] for r>jc
float part = 0.f;
for (int r = jc + 1 + t; r < m; r += nt) { float v = sP[(long)jc * m + r]; part += v * v; }
const float ssq = blkReduceSum(part, red, t, nt);
const float alpha = sP[(long)jc * m + jc];
float beta, tau_c, inv_denom;
if (ssq == 0.f) { beta = alpha; tau_c = 0.f; inv_denom = 0.f; }
else { float nrm = sqrtf(alpha * alpha + ssq); float bd = (alpha > 0.f) ? -nrm : nrm;
beta = bd; tau_c = (bd - alpha) / bd; inv_denom = 1.f / (alpha - bd); }
if (t == 0) { tb[kk + jc] = tau_c; staus[jc] = tau_c; }
for (int r = jc + 1 + t; r < m; r += nt) if (ssq != 0.f) sP[(long)jc * m + r] *= inv_denom;
__syncthreads(); // RACE FIX: all threads must finish reading alpha=sP[jc,jc] before t0 overwrites it with beta
if (t == 0) sP[(long)jc * m + jc] = beta;
__syncthreads();
// apply reflector to panel cols (jc, nb): 4 columns per reduction (separate registers)
for (int jp = jc + 1; jp < nb; jp += 4) {
const bool h1 = jp + 1 < nb, h2 = jp + 2 < nb, h3 = jp + 3 < nb;
float p0 = 0.f, p1 = 0.f, p2 = 0.f, p3 = 0.f;
for (int r = jc + 1 + t; r < m; r += nt) {
float vr = sP[(long)jc * m + r];
p0 += vr * sP[(long)jp * m + r];
if (h1) p1 += vr * sP[(long)(jp + 1) * m + r];
if (h2) p2 += vr * sP[(long)(jp + 2) * m + r];
if (h3) p3 += vr * sP[(long)(jp + 3) * m + r];
}
blkReduceSum4(p0, p1, p2, p3, red, t, nt);
// READ phase: all w_k while threads aligned (post-reduction); then sync; then write.
float w0 = p0 + sP[(long)jp * m + jc];
float w1 = h1 ? p1 + sP[(long)(jp + 1) * m + jc] : 0.f;
float w2 = h2 ? p2 + sP[(long)(jp + 2) * m + jc] : 0.f;
float w3 = h3 ? p3 + sP[(long)(jp + 3) * m + jc] : 0.f;
__syncthreads();
if (t == 0) { sP[(long)jp * m + jc] -= tau_c * w0;
if (h1) sP[(long)(jp + 1) * m + jc] -= tau_c * w1;
if (h2) sP[(long)(jp + 2) * m + jc] -= tau_c * w2;
if (h3) sP[(long)(jp + 3) * m + jc] -= tau_c * w3; }
for (int r = jc + 1 + t; r < m; r += nt) { float vr = sP[(long)jc * m + r];
sP[(long)jp * m + r] -= tau_c * vr * w0;
if (h1) sP[(long)(jp + 1) * m + r] -= tau_c * vr * w1;
if (h2) sP[(long)(jp + 2) * m + r] -= tau_c * vr * w2;
if (h3) sP[(long)(jp + 3) * m + r] -= tau_c * vr * w3; }
__syncthreads();
}
}
// write panel back (VtV+T computed on host via bmm + build_T)
for (long idx = t; idx < (long)m * nb; idx += nt) {
int r = idx / nb, j = idx % nb;
M[(long)(kk + r) * n + (kk + j)] = sP[(long)j * m + r];
}
}
extern "C" __global__ void build_T(const float* __restrict__ VtV, const float* __restrict__ tau,
float* __restrict__ Tout, int n, int kk, int nb) {
// Parallel across ROWS of T: each row a is independent (T[a,i] depends only on T[a,l], l<i, same row).
const int b = blockIdx.x;
const float* G = VtV + (long)b * nb * nb;
const float* tb = tau + (long)b * n + kk;
float* Tb = Tout + (long)b * nb * nb;
extern __shared__ float sm[];
float* sg = sm; // VtV : nb*nb
float* sT = sm + nb * nb; // T : nb*nb
const int a = threadIdx.x, nt = blockDim.x;
for (int idx = a; idx < nb * nb; idx += nt) sg[idx] = G[idx];
__syncthreads();
if (a < nb) {
for (int i = 0; i < a; ++i) sT[a * nb + i] = 0.f;
sT[a * nb + a] = tb[a];
for (int i = a + 1; i < nb; ++i) {
float acc = 0.f;
const float ti = -tb[i];
for (int l = a; l < i; ++l) acc += sT[a * nb + l] * (ti * sg[l * nb + i]);
sT[a * nb + i] = acc;
}
}
__syncthreads();
for (int idx = a; idx < nb * nb; idx += nt) Tb[idx] = sT[idx];
}
void build_T_launch(torch::Tensor VtV, torch::Tensor tau, torch::Tensor Tout, int kk, int nb) {
const int B = VtV.size(0);
int thr = nb < 32 ? 32 : nb;
build_T<<<B, thr, (size_t)2*nb*nb*sizeof(float)>>>(VtV.data_ptr<float>(), tau.data_ptr<float>(), Tout.data_ptr<float>(), tau.size(1), kk, nb);
}
void panel_qr_sh_launch(torch::Tensor Q, torch::Tensor tau, int kk, int nb) {
const int B = Q.size(0), n = Q.size(1);
const int m = n - kk;
int threads = 256;
size_t shmem = ((size_t)m * nb + threads + nb) * sizeof(float);
cudaFuncSetAttribute(panel_qr_sh, cudaFuncAttributeMaxDynamicSharedMemorySize, (int)shmem);
panel_qr_sh<<<B, threads, shmem>>>(Q.data_ptr<float>(), tau.data_ptr<float>(), n, kk, nb);
}
"""
_mod = load_inline(
name="hh_v55",
cpp_sources="void panel_qr_sh_launch(torch::Tensor Q, torch::Tensor tau, int kk, int nb);\nvoid build_T_launch(torch::Tensor VtV, torch::Tensor tau, torch::Tensor Tout, int kk, int nb);",
cuda_sources=_CUDA_SRC,
functions=["panel_qr_sh_launch","build_T_launch"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
verbose=False,
)
_NB = 16
def _householder_qr(A, _NB):
B, n, _ = A.shape
M = A.clone()
tau = torch.zeros(B, n, device=A.device, dtype=torch.float32)
Tfull = torch.empty(B, _NB, _NB, device=A.device, dtype=torch.float32)
eye = torch.eye(_NB, device=A.device, dtype=torch.float32)
for kk in range(0, n, _NB):
nb = min(_NB, n - kk)
_mod.panel_qr_sh_launch(M, tau, kk, nb)
hi = kk + nb
if hi < n:
V = M[:, kk:, kk:hi].clone()
Vblk = V[:, :nb, :nb]
Vblk.tril_(-1)
Vblk.diagonal(dim1=-2, dim2=-1).fill_(1.0)
VtV = V.transpose(-1, -2) @ V
Tk = Tfull if nb == _NB else torch.empty(B, nb, nb, device=A.device, dtype=torch.float32)
_mod.build_T_launch(VtV, tau, Tk, kk, nb)
Atrail = M[:, kk:, hi:]
W = V.transpose(-1, -2) @ Atrail
Y = Tk.transpose(-1, -2) @ W
Atrail.baddbmm_(V, Y, beta=1.0, alpha=-1.0)
return M, tau
_MM = torch.backends.cuda.matmul
_eye_cache = {}
def _eye(k, dev):
e = _eye_cache.get((k, dev))
if e is None:
e = torch.eye(k, device=dev, dtype=torch.float32); _eye_cache[(k, dev)] = e
return e
def _bounded_apply(M, V, T, r0, c0, c1, tf32):
# M[:, r0:, c0:c1] -= V @ (T^T @ (V^T @ M[:, r0:, c0:c1]))
if c0 >= c1:
return
At = M[:, r0:, c0:c1]
_MM.allow_tf32 = tf32
W = V.transpose(-1, -2) @ At
Y = T.transpose(-1, -2) @ W
At.baddbmm_(V, Y, beta=1.0, alpha=-1.0)
_MM.allow_tf32 = False
def _make_V(M, r0, c0, c1):
w = c1 - c0
V = M[:, r0:, c0:c1].clone()
Vb = V[:, :w, :w]; Vb.tril_(-1); Vb.diagonal(dim1=-2, dim2=-1).fill_(1.0)
return V
def _householder_2level(A, nb, NB, tf32_big):
B, n, _ = A.shape
M = A.clone()
tau = torch.zeros(B, n, device=A.device, dtype=torch.float32)
for K in range(0, n, NB):
NBk = min(NB, n - K); Kend = K + NBk
for kk in range(K, Kend, nb):
nbk = min(nb, Kend - kk); hi = kk + nbk
_mod.panel_qr_sh_launch(M, tau, kk, nbk)
if hi < Kend:
V = _make_V(M, kk, kk, hi)
VtV = V.transpose(-1, -2) @ V
T = torch.empty(B, nbk, nbk, device=A.device, dtype=torch.float32)
_mod.build_T_launch(VtV, tau, T, kk, nbk)
_bounded_apply(M, V, T, kk, hi, Kend, tf32_big) # within-block, tf32 when safe
if Kend < n:
Vb = _make_V(M, K, K, Kend)
VtVb = Vb.transpose(-1, -2) @ Vb
Tb = torch.empty(B, NBk, NBk, device=A.device, dtype=torch.float32)
_mod.build_T_launch(VtVb, tau, Tb, K, NBk)
_bounded_apply(M, Vb, Tb, K, Kend, n, tf32_big) # block trailing, tf32
return M, tau
def _tf32_unsafe(A):
n = A.shape[-1]
rn = A.norm(dim=-1)
rng = rn.amax(dim=-1) / rn.amin(dim=-1).clamp_min(1e-30)
if float(rng.amax()) > 1.0e3:
return True
if n >= 16:
q = n // 4
if float(A[:, :q, 3 * q:].abs().amax()) < 1.0e-6 * float(A.abs().amax()):
return True
return False
def custom_kernel(data):
A = data
n = A.shape[-1]
if n > 2048:
return torch.geqrf(A)
Af = A.float()
if n <= 256:
H, tau = _householder_qr(Af, 16)
else:
use_tf32 = not _tf32_unsafe(Af)
H, tau = _householder_2level(Af, 16, 64, use_tf32)
if not torch.isfinite(H).all():
return torch.geqrf(A)
return H.to(A.dtype), tau.to(A.dtype)
scrolls · 277 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