26template <
class Scalar>
27concept CublasScalar = std::same_as<Scalar, float> || std::same_as<Scalar, double> ||
28 std::same_as<Scalar, uni20::cfloat> || std::same_as<Scalar, uni20::cdouble>;
33inline cublasOperation_t operation(
char transform)
47 PANIC(
"invalid cuBLAS matrix transform", transform);
50template <CublasScalar Scalar>
51void gemm_call(cublasHandle_t
handle, cublasOperation_t transa, cublasOperation_t transb,
int rows,
int cols,
int inner,
53 int rhs_leading_dimension,
Scalar const&
beta,
Scalar* output,
int output_leading_dimension,
int device)
55 cublasStatus_t status = CUBLAS_STATUS_INTERNAL_ERROR;
56 if constexpr (std::same_as<Scalar, float>)
59 status = cublasSgemm(
handle, transa, transb, rows, cols, inner, &alpha, lhs, lhs_leading_dimension, rhs,
60 rhs_leading_dimension, &
beta, output, output_leading_dimension);
62 else if constexpr (std::same_as<Scalar, double>)
65 status = cublasDgemm(
handle, transa, transb, rows, cols, inner, &alpha, lhs, lhs_leading_dimension, rhs,
66 rhs_leading_dimension, &
beta, output, output_leading_dimension);
68 else if constexpr (std::same_as<Scalar, uni20::cfloat>)
70 static_assert(
sizeof(
Scalar) ==
sizeof(cuComplex));
71 cuComplex
const provider_alpha = make_cuComplex(alpha.real(), alpha.imag());
72 cuComplex
const provider_beta = make_cuComplex(
beta.real(),
beta.imag());
75 cublasCgemm(
handle, transa, transb, rows, cols, inner, &provider_alpha,
reinterpret_cast<cuComplex const*
>(lhs),
76 lhs_leading_dimension,
reinterpret_cast<cuComplex const*
>(rhs), rhs_leading_dimension,
77 &provider_beta,
reinterpret_cast<cuComplex*
>(output), output_leading_dimension);
81 static_assert(std::same_as<Scalar, uni20::cdouble>);
82 static_assert(
sizeof(
Scalar) ==
sizeof(cuDoubleComplex));
83 cuDoubleComplex
const provider_alpha = make_cuDoubleComplex(alpha.real(), alpha.imag());
84 cuDoubleComplex
const provider_beta = make_cuDoubleComplex(
beta.real(),
beta.imag());
86 status = cublasZgemm(
handle, transa, transb, rows, cols, inner, &provider_alpha,
87 reinterpret_cast<cuDoubleComplex const*
>(lhs), lhs_leading_dimension,
88 reinterpret_cast<cuDoubleComplex const*
>(rhs), rhs_leading_dimension, &provider_beta,
89 reinterpret_cast<cuDoubleComplex*
>(output), output_leading_dimension);
91 check(status,
"cublasGemm", device);
97template <CublasScalar Scalar>
98void gemm(
ExecutionLease& execution,
char lhs_transform,
char rhs_transform,
int rows,
int cols,
int inner,
99 Scalar alpha,
Scalar const* lhs,
int lhs_leading_dimension,
Scalar const* rhs,
int rhs_leading_dimension,
103 CHECK(rows >= 0 && cols >= 0 && inner >= 0, rows, cols, inner);
104 auto const transa = detail::operation(lhs_transform);
105 auto const transb = detail::operation(rhs_transform);
106 if (rows == 0 || cols == 0)
return;
108 int const minimum_lhs_leading_dimension = std::max(1, transa == CUBLAS_OP_N ? rows : inner);
109 int const minimum_rhs_leading_dimension = std::max(1, transb == CUBLAS_OP_N ? inner : cols);
110 int const minimum_output_leading_dimension = std::max(1, rows);
111 CHECK(lhs_leading_dimension >= minimum_lhs_leading_dimension, lhs_leading_dimension, minimum_lhs_leading_dimension);
112 CHECK(rhs_leading_dimension >= minimum_rhs_leading_dimension, rhs_leading_dimension, minimum_rhs_leading_dimension);
113 CHECK(output_leading_dimension >= minimum_output_leading_dimension, output_leading_dimension,
114 minimum_output_leading_dimension);
116 detail::gemm_call(execution.
handle().
native_handle(), transa, transb, rows, cols, inner, alpha, lhs,
117 lhs_leading_dimension, rhs, rhs_leading_dimension,
beta, output, output_leading_dimension,
Move-only dynamic pairing of one cuBLAS handle slot and one idle stream.
Definition cublas/execution.hpp:56
cuda::Stream const & stream() const noexcept
Access the dynamically selected CUDA stream.
Definition cublas/execution.hpp:77
HandleSlot & handle() const
Access the exclusively leased cuBLAS handle slot.
Definition cublas/execution.hpp:74
cublasHandle_t native_handle() const noexcept
Return the raw handle for narrow provider-wrapper use.
Definition cublas/execution.hpp:41
Temporarily select one CUDA device and restore the previous device on destruction.
Definition runtime.hpp:44
int device() const noexcept
Return the device that owns this stream.
Definition runtime.cpp:280
Concept for numeric scalar types (integer, real, or complex).
Definition scalar_concepts.hpp:81
Scalar types supported by the cuBLAS GEMM wrappers.
Definition backend/cublas/gemm.hpp:27
cuda::ResourceLease< HandleSlot > handle
Definition cublas/execution.cpp:33
cuBLAS handle slots and dynamically paired stream execution leases.
Structured cuBLAS failures and checked-call helpers.
#define UNI20_EXTERNAL_API_CALL(module, func,...)
Emits a trace log entry for an outgoing backend API call.
Definition backend.hpp:90
Definition cublas_error.cpp:11
void check(cublasStatus_t status, std::string_view operation, int device, std::source_location where)
Raise unless a cuBLAS call returned CUBLAS_STATUS_SUCCESS.
Definition cublas_error.cpp:52
void gemm(ExecutionLease &execution, char lhs_transform, char rhs_transform, int rows, int cols, int inner, Scalar alpha, Scalar const *lhs, int lhs_leading_dimension, Scalar const *rhs, int rhs_leading_dimension, Scalar beta, Scalar *output, int output_leading_dimension)
Enqueue column-major GEMM through an exclusive handle/stream lease.
Definition backend/cublas/gemm.hpp:98
mpreal beta(mpreal const &a, mpreal const &x)
Real Beta function; positive rational/integer pairs retain exact values.
Definition mpreal_special.hpp:164
#define CHECK(cond,...)
Definition trace.hpp:299
#define PANIC(...)
Definition trace.hpp:382