Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
gemm_task.hpp
Go to the documentation of this file.
1#pragma once
2
14
15#include <utility>
16
17namespace uni20::linalg
18{
19namespace detail::cublas_backend
20{
21
22template <uni20::cublas::CublasScalar Scalar>
23async::CudaTask co_gemm_submission(GemmPlan<Scalar> plan, Scalar alpha, Scalar beta)
24{
25 auto& resources = plan.resources();
26 co_await uni20::cuda::set_device(resources.device());
27 auto execution = co_await uni20::cublas::acquire_execution(uni20::cublas::execution_pool(resources));
28 execute_gemm(execution, plan, alpha, beta);
29 co_return;
30}
31
37template <uni20::cublas::CublasScalar Scalar, class OutputMdspan, class LhsMdspan, class RhsMdspan>
38 requires GemmMdspans<Scalar, OutputMdspan, LhsMdspan, RhsMdspan>
39auto try_make_gemm_task(OutputMdspan& output, Scalar const& alpha, LhsMdspan& lhs, RhsMdspan& rhs, Scalar const& beta)
40 -> KernelTaskAttempt<async::CudaTask>
41{
42 auto preparation = prepare_gemm<Scalar>(output, lhs, rhs);
43 if (!kernel_attempt_succeeded(preparation.attempt) || !preparation.plan.has_work)
44 {
45 return KernelTaskAttempt<async::CudaTask>{preparation.attempt};
46 }
47
48 int const device = preparation.plan.device;
49 auto task = co_gemm_submission(std::move(preparation.plan), alpha, beta);
50 async::cuda_promise(task.handle()).bind_device(device);
51 return KernelTaskAttempt<async::CudaTask>{std::move(task)};
52}
53} // namespace detail::cublas_backend
54
56template <uni20::cublas::CublasScalar Scalar, class OutputMdspan, class LhsMdspan, class RhsMdspan>
59auto try_make_kernel_task(CublasBackend, gemm_op const&, OutputMdspan& output, Scalar const& alpha, LhsMdspan& lhs,
60 RhsMdspan& rhs, Scalar const& beta) -> KernelTaskAttempt<async::CudaTask>
61{
62 return detail::cublas_backend::try_make_gemm_task(output, alpha, lhs, rhs, beta);
63}
64
66template <uni20::cublas::CublasScalar Scalar, class OutputTensor, class LhsMdspan, class RhsMdspan>
69auto try_make_kernel_task(CublasBackend, assign_product_op const&, OutputTensor& output, Scalar const& alpha,
70 LhsMdspan& lhs, RhsMdspan& rhs) -> KernelTaskAttempt<async::CudaTask>
71{
72 auto const shape = detail::matrix_product_shape(lhs, rhs);
73 bool const output_is_empty = detail::cublas_backend::product_output_is_empty(shape);
74 auto const lhs_device = detail::cublas_backend::span_device(lhs);
75 if (!output_is_empty && detail::cublas_backend::span_device(rhs) != lhs_device)
77
78 if constexpr (requires { uni20::prepare_output(output, shape, lhs_device); })
79 {
80 uni20::prepare_output(output, shape, lhs_device);
81 }
82 else if (!uni20::tensor_extents_equal(output.extents(), shape))
83 {
85 }
86
87 auto output_span = uni20::mdspec_of(output);
88 if (!output_is_empty && detail::cublas_backend::span_device(output_span) != lhs_device)
90 return detail::cublas_backend::try_make_gemm_task(output_span, alpha, lhs, rhs, Scalar{});
91}
92
94template <uni20::cublas::CublasScalar Scalar, uni20::MutableRankedTensorView<2> OutputTensor, class LhsMdspan,
95 class RhsMdspan>
97 requires(async::shared_storage<OutputTensor>& storage, detail::matrix_product_extents const& shape,
98 uni20::cuda::Device device) { uni20::prepare_output(storage, shape, device); }
100 Scalar const& alpha, LhsMdspan& lhs, RhsMdspan& rhs) -> KernelTaskAttempt<async::CudaTask>
101{
102 auto const shape = detail::matrix_product_shape(lhs, rhs);
103 bool const output_is_empty = detail::cublas_backend::product_output_is_empty(shape);
104 auto const lhs_device = detail::cublas_backend::span_device(lhs);
105 if (!output_is_empty && detail::cublas_backend::span_device(rhs) != lhs_device)
107
108 auto& output = uni20::prepare_output(output_storage, shape, lhs_device);
109 auto output_span = uni20::mdspec_of(output);
110 return detail::cublas_backend::try_make_gemm_task(output_span, alpha, lhs, rhs, Scalar{});
111}
112
113} // namespace uni20::linalg
void bind_device(int device)
Bind the CUDA device before the coroutine starts.
Definition async_task_promise.hpp:673
CUDA-constrained public task type used for typed initial admission.
Definition cuda_task.hpp:14
A lightweight, thread-safe, reference-counted storage for a single object.
Definition shared_storage.hpp:94
Validated CUDA device identity with cached immutable capabilities.
Definition device.hpp:105
Runtime backend attempt optionally carrying a deferred kernel task.
Definition kernel_task.hpp:31
Mutable mdspec-like type with a specified static rank.
Definition mdspan/concepts.hpp:487
MutableTensorView with a specified static rank.
Definition tensor/concepts.hpp:166
An mdspec-like type with a specified static rank.
Definition mdspan/concepts.hpp:454
Concept for numeric scalar types (integer, real, or complex).
Definition scalar_concepts.hpp:81
Non-blocking CUDA-task acquisition of cuBLAS execution resources.
CUDA-specific awaiters for device and runtime resource scheduling.
Defines the CUDA task admission type and scheduler interface.
Deferred task result for an optional coroutine kernel implementation.
cuBLAS backend adapter for provider-ready GEMM dispatch.
CudaTaskPromise & cuda_promise(TaskHandle handle) noexcept
Narrow an erased task promise after verifying that it is CUDA-specific.
Definition async_task_promise.hpp:707
ExecutionAcquireAwaiter acquire_execution(ExecutionPool &pool) noexcept
Acquire a cuBLAS handle and idle stream without blocking a CUDA task.
Definition cublas/task_awaiters.hpp:119
ExecutionPool & execution_pool(cuda::DeviceResources &resources)
Return the lazily constructed cuBLAS execution pool for one CUDA device.
Definition cublas/execution.cpp:215
Definition linalg/async.hpp:28
constexpr bool kernel_attempt_succeeded(KernelAttempt attempt) noexcept
Return whether a backend performed the operation.
Definition kernel_attempt.hpp:40
auto try_make_kernel_task(CublasBackend, gemm_op const &, OutputMdspan &output, Scalar const &alpha, LhsMdspan &lhs, RhsMdspan &rhs, Scalar const &beta) -> KernelTaskAttempt< async::CudaTask >
Prepare asynchronous cuBLAS work from normalized mdspecs.
Definition gemm_task.hpp:59
Output & prepare_output(Output &output, RequiredExtents const &required)
Prepare a mutable tensor output with the specified shape.
Definition tensor/output.hpp:104
constexpr decltype(auto) mdspec_of(Tensor &tensor) noexcept(noexcept(tensor.mdspec()))
Return a tensor's immediate or descriptor-backed multidimensional metadata.
Definition tensor/concepts.hpp:50
mpreal beta(mpreal const &a, mpreal const &x)
Real Beta function; positive rational/integer pairs retain exact values.
Definition mpreal_special.hpp:164
constexpr bool tensor_extents_equal(LhsExtents const &lhs, RhsExtents const &rhs) noexcept
Compare two tensor extent objects by rank and per-axis extent.
Definition tensor/output.hpp:31
Backend value for cuBLAS dense linalg kernels.
Definition backend_selector.hpp:34
Replaceable-output dense matrix product operation tag.
Definition operation_tags.hpp:75
Fixed-output dense matrix multiplication operation tag.
Definition operation_tags.hpp:84