Skip to content
KernelIndex
Search⌘K

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
NVIDIA B200
121.8ms
#444 of 515
2026-06-22

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