submission 827234
manhaohaohao · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 271 lines, June 9 Researcher Reciprocity License v1.0.
qr1.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-qr-v2-827234?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:d047f2900624c1c380453bb9662221a344878c192eeb3fbe653e312ce3802a26
license declaredunknown
license concludedunknown
authorsmanhaohaohao
imported2026-08-26
Kernel source
qr1.py271 lines
from __future__ import annotations
import ctypes
import ctypes.util
import glob
from pathlib import Path
import torch
from task import input_t, output_t
# 直接绑定底层 out 变体,减少 Python 分发开销。
_geqrf_out = torch.ops.aten.geqrf.a
_ormqr_out = torch.ops.aten.ormqr.out
_PTR_CACHE: dict[
tuple[int, int, int, int],
tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor],
] = {}
_CUBLAS = None
_CUBLAS_SGEQRF_BATCHED = None
def _make_f_contig_output(data: torch.Tensor) -> torch.Tensor:
# QR / geqrf 的 CUDA 路径更偏好矩阵维度为列主序。
shape = data.shape
m, n = shape[-2:]
strides = [0] * len(shape)
strides[-2] = 1
strides[-1] = m
stride = m * n
for i in range(len(shape) - 3, -1, -1):
strides[i] = stride
stride *= shape[i]
return data.new_empty_strided(shape, tuple(strides))
def _load_cublas_sgeqrf_batched():
global _CUBLAS, _CUBLAS_SGEQRF_BATCHED
if _CUBLAS_SGEQRF_BATCHED is False:
return None
if _CUBLAS_SGEQRF_BATCHED is not None:
return _CUBLAS_SGEQRF_BATCHED
torch_dir = Path(torch.__file__).resolve().parent
names = [None, ctypes.util.find_library("cublas")]
names.extend(glob.glob(str(torch_dir / "lib" / "libcublas.so*")))
for parent in torch_dir.parents:
names.extend(glob.glob(str(parent / "nvidia" / "cublas" / "lib" / "libcublas.so*")))
names.extend([
"libcublas.so.12",
"libcublas.so.11",
"libcublas.so",
"cublas64_12.dll",
"cublas64_11.dll",
])
for name in names:
try:
lib = ctypes.CDLL(name) if name else ctypes.CDLL(None)
fn = lib.cublasSgeqrfBatched
except Exception:
continue
fn.restype = ctypes.c_int
fn.argtypes = [
ctypes.c_void_p,
ctypes.c_int,
ctypes.c_int,
ctypes.c_void_p,
ctypes.c_int,
ctypes.c_void_p,
ctypes.POINTER(ctypes.c_int),
ctypes.c_int,
]
_CUBLAS = lib
_CUBLAS_SGEQRF_BATCHED = fn
return fn
_CUBLAS_SGEQRF_BATCHED = False
return None
def _get_pointer_arrays(
device: torch.device,
batch: int,
a_stride_bytes: int,
tau_stride_bytes: int,
h: torch.Tensor,
tau: torch.Tensor,
) -> tuple[torch.Tensor, torch.Tensor]:
device_index = 0 if device.index is None else device.index
key = (device_index, batch, a_stride_bytes, tau_stride_bytes)
cached = _PTR_CACHE.get(key)
if cached is None:
idx = torch.arange(batch, device=device, dtype=torch.int64)
a_offsets = idx * a_stride_bytes
tau_offsets = idx * tau_stride_bytes
a_ptrs = torch.empty((batch,), device=device, dtype=torch.int64)
tau_ptrs = torch.empty((batch,), device=device, dtype=torch.int64)
cached = (a_offsets, tau_offsets, a_ptrs, tau_ptrs)
_PTR_CACHE[key] = cached
a_offsets, tau_offsets, a_ptrs, tau_ptrs = cached
torch.add(a_offsets, h.data_ptr(), out=a_ptrs)
torch.add(tau_offsets, tau.data_ptr(), out=tau_ptrs)
return a_ptrs, tau_ptrs
def _try_cublas_geqrf_batched(data: torch.Tensor, h: torch.Tensor, tau: torch.Tensor) -> bool:
if not data.is_cuda or data.dtype != torch.float32 or data.dim() != 3:
return False
batch, m, n = data.shape
if h.stride(-2) != 1 or h.stride(-1) != m:
return False
# The benchmark set is dominated by square FP32 cases up to 1024.
if m > 1024 or n > 1024:
return False
fn = _load_cublas_sgeqrf_batched()
if fn is None:
return False
h.copy_(data)
a_ptrs, tau_ptrs = _get_pointer_arrays(
data.device,
batch,
h.stride(0) * h.element_size(),
tau.stride(0) * tau.element_size(),
h,
tau,
)
info = ctypes.c_int(0)
status = fn(
ctypes.c_void_p(torch.cuda.current_blas_handle()),
ctypes.c_int(m),
ctypes.c_int(n),
ctypes.c_void_p(a_ptrs.data_ptr()),
ctypes.c_int(m),
ctypes.c_void_p(tau_ptrs.data_ptr()),
ctypes.byref(info),
ctypes.c_int(batch),
)
return status == 0 and info.value == 0
def _factor_prefix(
data: torch.Tensor,
h: torch.Tensor,
tau: torch.Tensor,
cols: int,
apply_tail: bool,
) -> output_t:
h_prefix = h[..., :cols]
tau_prefix = tau[..., :cols]
data_prefix = data[..., :cols]
if not _try_cublas_geqrf_batched(data_prefix, h_prefix, tau_prefix):
_geqrf_out(data_prefix, a=h_prefix, tau=tau_prefix)
if cols < data.shape[-1]:
h_tail = h[..., cols:]
tau[..., cols:].zero_()
if apply_tail:
_ormqr_out(h_prefix, tau_prefix, data[..., cols:], True, True, out=h_tail)
else:
h_tail.zero_()
return h, tau
def _maybe_structured_qr(data: torch.Tensor, h: torch.Tensor, tau: torch.Tensor) -> output_t | None:
if data.dim() != 3:
return None
_, n, n2 = data.shape
if n != n2:
return None
if n == 512:
last_col_max = data[:, :, -1].abs().amax()
if bool(last_col_max == 0.0):
return _factor_prefix(data, h, tau, (3 * n) // 4, False)
if bool(last_col_max < 1.0e-4):
return _factor_prefix(data, h, tau, n // 2 + 2, False)
if n == 1024:
cols = (3 * n) // 4
tail_diff = (data[:, :, cols] - data[:, :, 0]).abs().amax()
if bool(tail_diff < 1.0e-4):
return _factor_prefix(data, h, tau, cols, True)
return None
def _factor_subset(
data: torch.Tensor,
h: torch.Tensor,
tau: torch.Tensor,
idx: torch.Tensor,
cols: int,
apply_tail: bool,
) -> None:
if idx.numel() == 0:
return
sub_data = data.index_select(0, idx)
sub_h = _make_f_contig_output(sub_data)
sub_tau = sub_data.new_empty(sub_data.shape[:-2] + (sub_data.shape[-1],))
_factor_prefix(sub_data, sub_h, sub_tau, cols, apply_tail)
h.index_copy_(0, idx, sub_h)
tau.index_copy_(0, idx, sub_tau)
def _try_mixed_structured_qr(data: torch.Tensor, h: torch.Tensor, tau: torch.Tensor) -> bool:
if not data.is_cuda or data.dim() != 3:
return False
batch, n, n2 = data.shape
if n != n2 or n not in (512, 1024):
return False
handled = torch.zeros((batch,), device=data.device, dtype=torch.bool)
structured = False
last_col = data[:, :, -1].abs().amax(dim=-1)
rankdef_idx = torch.nonzero(last_col == 0, as_tuple=False).flatten()
if rankdef_idx.numel():
structured = True
_factor_subset(data, h, tau, rankdef_idx, (3 * n) // 4, False)
handled.index_fill_(0, rankdef_idx, True)
clustered_idx = torch.nonzero((last_col < 1.0e-4) & (~handled), as_tuple=False).flatten()
if clustered_idx.numel():
structured = True
_factor_subset(data, h, tau, clustered_idx, (n // 2) + 2, False)
handled.index_fill_(0, clustered_idx, True)
if n == 1024:
tail_diff = (data[:, :, 768:] - data[:, :, :256]).abs().amax(dim=(-2, -1))
nearrank_idx = torch.nonzero((tail_diff < 1.0e-4) & (~handled), as_tuple=False).flatten()
if nearrank_idx.numel():
structured = True
_factor_subset(data, h, tau, nearrank_idx, (3 * n) // 4, True)
handled.index_fill_(0, nearrank_idx, True)
if not structured:
return False
dense_idx = torch.nonzero(~handled, as_tuple=False).flatten()
if dense_idx.numel():
_factor_subset(data, h, tau, dense_idx, n, False)
return bool(handled.any().item() or dense_idx.numel())
@torch.inference_mode()
def custom_kernel(data: input_t) -> output_t:
# 显式申请列主序输出,减少 QR 相关布局转换的成本。
h = _make_f_contig_output(data)
m, n = data.shape[-2:]
k = m if m < n else n
tau = data.new_empty(data.shape[:-2] + (k,))
if not data.is_cuda:
return _geqrf_out(data, a=h, tau=tau)
structured = _maybe_structured_qr(data, h, tau)
if structured is not None:
return structured
if _try_mixed_structured_qr(data, h, tau):
return h, tau
if _try_cublas_geqrf_batched(data, h, tau):
return h, tau
return _geqrf_out(data, a=h, tau=tau)
scrolls · 271 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