Skip to content
KernelIndex
Search⌘K

submission 843903

techhelp · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

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

submission.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-eigh-843903?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
50.0ms
#174 of 286
2026-06-29

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:a37687a66511857f43de9bc4696c78fcf85927963557fa0d67b276b381d7eb76
license declaredunknown
license concludedunknown
authorstechhelp
imported2026-08-26

Kernel source

submission.py194 lines
#!POPCORN leaderboard eigh
#!POPCORN gpu B200

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

DBG = "DBG" in os.environ

CUDA_SRC = r"""
#include <torch/extension.h>
#include <cuda_runtime.h>
#include <cusolverDn.h>
#include <vector>
#include <mutex>

#define CUDA_CHECK(call) do {                                                      \
    cudaError_t err = call;                                                        \
    if (err != cudaSuccess) {                                                      \
        throw std::runtime_error(std::string("CUDA error: ") +                    \
                                 cudaGetErrorString(err));                         \
    }                                                                              \
} while(0)

#define CUSOLVER_CHECK(call) do {                                                  \
    cusolverStatus_t err = call;                                                   \
    if (err != CUSOLVER_STATUS_SUCCESS) {                                          \
        throw std::runtime_error("cuSOLVER error: " +                             \
                                 std::to_string((int)err));                        \
    }                                                                              \
} while(0)

extern "C" {
cusolverStatus_t CUSOLVERAPI cusolverDnXsyevBatched_bufferSize(
    cusolverDnHandle_t, cusolverDnParams_t, cusolverEigMode_t, cublasFillMode_t,
    int64_t, cudaDataType, const void*, int64_t, cudaDataType, const void*,
    cudaDataType, size_t*, size_t*, int64_t);

cusolverStatus_t CUSOLVERAPI cusolverDnXsyevBatched(
    cusolverDnHandle_t, cusolverDnParams_t, cusolverEigMode_t, cublasFillMode_t,
    int64_t, cudaDataType, void*, int64_t, cudaDataType, void*,
    cudaDataType, void*, size_t, void*, size_t, int*, int64_t);
}

static cusolverDnHandle_t g_handle = nullptr;
static cusolverDnParams_t g_params = nullptr;
static std::mutex g_mutex;

static void ensure_handle() {
    std::lock_guard<std::mutex> lock(g_mutex);
    if (!g_handle) {
        CUSOLVER_CHECK(cusolverDnCreate(&g_handle));
        CUSOLVER_CHECK(cusolverDnCreateParams(&g_params));
    }
}

template <typename scalar_t>
cudaDataType cuda_data_type();

template <>
cudaDataType cuda_data_type<double>() { return CUDA_R_64F; }

template <>
cudaDataType cuda_data_type<float>() { return CUDA_R_32F; }

static void* g_dev_work = nullptr;
static size_t g_dev_work_bytes = 0;
static void* g_host_work = nullptr;
static size_t g_host_work_bytes = 0;
static int* g_dev_info = nullptr;
static int g_dev_info_cap = 0;

static void ensure_workspace(size_t dev_bytes, size_t host_bytes, int batch) {
    if (dev_bytes > g_dev_work_bytes) {
        if (g_dev_work) cudaFree(g_dev_work);
        CUDA_CHECK(cudaMalloc(&g_dev_work, dev_bytes));
        g_dev_work_bytes = dev_bytes;
    }
    if (host_bytes > g_host_work_bytes) {
        free(g_host_work);
        g_host_work = malloc(host_bytes);
        g_host_work_bytes = host_bytes;
    }
    if (batch > g_dev_info_cap) {
        if (g_dev_info) cudaFree(g_dev_info);
        CUDA_CHECK(cudaMalloc(&g_dev_info, sizeof(int) * batch));
        g_dev_info_cap = batch;
    }
}

template <typename scalar_t>
void batched_syevd_kernel(cusolverDnHandle_t handle, cusolverDnParams_t params,
                           cusolverEigMode_t jobz, cublasFillMode_t uplo,
                           int64_t n, scalar_t* d_A, int64_t lda,
                           scalar_t* d_W, int64_t batchSize) {
    cudaDataType dt = cuda_data_type<scalar_t>();

    size_t dev_bytes = 0, host_bytes = 0;
    CUSOLVER_CHECK(cusolverDnXsyevBatched_bufferSize(
        handle, params, jobz, uplo, n, dt, d_A, lda, dt, d_W,
        dt, &dev_bytes, &host_bytes, batchSize));

    ensure_workspace(dev_bytes, host_bytes, batchSize);

    CUSOLVER_CHECK(cusolverDnXsyevBatched(
        handle, params, jobz, uplo, n, dt, d_A, lda, dt, d_W,
        dt, g_dev_work, dev_bytes, g_host_work, host_bytes,
        g_dev_info, batchSize));

    std::vector<int> h_info(batchSize);
    CUDA_CHECK(cudaMemcpy(h_info.data(), g_dev_info, sizeof(int) * batchSize,
                          cudaMemcpyDeviceToHost));
    for (int64_t i = 0; i < batchSize; i++) {
        if (h_info[i] != 0) {
            throw std::runtime_error("syevd batched failed at batch " +
                                     std::to_string(i) +
                                     " with info=" + std::to_string(h_info[i]));
        }
    }
}

std::vector<torch::Tensor> syevd_cuda(torch::Tensor A, bool compute_eigenvectors) {
    TORCH_CHECK(A.is_cuda(), "A must be a CUDA tensor");
    TORCH_CHECK(A.dim() == 2 || A.dim() == 3, "A must be 2 or 3-dimensional");
    TORCH_CHECK(A.size(-1) == A.size(-2), "A must be square");
    TORCH_CHECK(A.scalar_type() == torch::kFloat64 ||
                A.scalar_type() == torch::kFloat32,
                "A must be float32 or float64");

    auto A_contig = A.contiguous();
    int64_t n = A_contig.size(-1);
    int64_t lda = n;
    int64_t batch = A_contig.dim() == 2 ? 1 : A_contig.size(0);

    ensure_handle();

    torch::Tensor eigenvectors = torch::empty_like(A_contig);
    eigenvectors.copy_(A_contig);
    torch::Tensor eigenvalues = torch::empty({batch, n}, A_contig.options());

    cusolverEigMode_t jobz = compute_eigenvectors
        ? CUSOLVER_EIG_MODE_VECTOR
        : CUSOLVER_EIG_MODE_NOVECTOR;
    cublasFillMode_t uplo = CUBLAS_FILL_MODE_LOWER;

    auto dtype = A_contig.scalar_type();

    AT_DISPATCH_FLOATING_TYPES(dtype, "syevd_cuda", [&] {
        batched_syevd_kernel<scalar_t>(
            g_handle, g_params, jobz, uplo, n,
            eigenvectors.data_ptr<scalar_t>(), lda,
            eigenvalues.data_ptr<scalar_t>(), batch);
    });

    return {eigenvectors.transpose(1, 2).contiguous(), eigenvalues};
}
"""

CPP_SRC = """
std::vector<torch::Tensor> syevd_cuda(torch::Tensor A, bool compute_eigenvectors);
"""

_syevd_module = load_inline(
    name="syevd_module",
    cpp_sources=[CPP_SRC],
    cuda_sources=[CUDA_SRC],
    functions=["syevd_cuda"],
    verbose=True,
    extra_ldflags=["-lcusolver", "-lcublas"],
)


def custom_kernel(data: input_t) -> output_t:
    result = _syevd_module.syevd_cuda(data, True)
    return (result[0], result[1])

if DBG:
    def custom_kernel(data: input_t) -> output_t:
        return torch.linalg.eigh(data)[::-1]


if DBG and __name__ == "__main__":
    from test_eigh import run_test_suite, solve_ref

    torch.set_default_dtype(torch.float32)
    print("\n=== cuSOLVER syevd kernel tests ===")

    def test_wrapper(unbatched_data):
        return custom_kernel(unbatched_data)

    run_test_suite(solver=test_wrapper, sizes=[64, 128], conds=[5, 10], rtol=5e-4)
    print("\nAll tests completed.")
scrolls · 194 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