Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
linalg/backends/blas/gemm.hpp
Go to the documentation of this file.
1#pragma once
2
9#include <uni20/config.hpp>
10#if UNI20_HAS_MPLAPACK_MPREAL
11#include "mpfr.hpp"
12#endif
13
14#if UNI20_BACKEND_BLAS
23
24#include <concepts>
25#include <type_traits>
26
27namespace uni20::linalg
28{
29namespace detail::blas_backend
30{
31
32template <class OutputTensor>
33using output_mdspec_t = std::remove_cvref_t<decltype(uni20::mdspec_of(std::declval<OutputTensor&>()))>;
34
35template <class OutputTensor> using output_mdspan_t = uni20::host_write_mdspan_t<output_mdspec_t<OutputTensor>>;
36
37template <class OutputTensor, class LhsMdspan, class RhsMdspan>
38concept HostAssignProductAccess = uni20::HostWritableMdspec<output_mdspec_t<OutputTensor>> &&
40
41template <class OutputMdspan, class Scalar, class LhsMdspan, class RhsMdspan>
42consteval bool gemm_mdspan_types_compatible()
43{
47 return requires(output_span& output, Scalar alpha, lhs_span& lhs, rhs_span& rhs) {
48 { uni20::linalg::blas::try_gemm(output, alpha, lhs, rhs, alpha) } -> std::same_as<KernelAttempt>;
49 };
50}
51
52template <class OutputTensor, class Scalar, class LhsMdspan, class RhsMdspan>
53consteval bool assign_product_types_compatible()
54{
55 using output_span = std::remove_cvref_t<decltype(uni20::mdspec_of(std::declval<OutputTensor&>()))>;
56 return gemm_mdspan_types_compatible<output_span, Scalar, LhsMdspan, RhsMdspan>();
57}
58
59template <uni20::MutableRankedMdspecLike<2> OutputMdspan, class Scalar, uni20::RankedMdspecLike<2> LhsMdspan,
60 uni20::RankedMdspecLike<2> RhsMdspan>
63KernelAttempt try_gemm(OutputMdspan& output, Scalar alpha, LhsMdspan& lhs, RhsMdspan& rhs, Scalar beta)
64{
65 auto output_access = acquire_host_write_access_sync(output);
66 auto lhs_access = acquire_host_read_access_sync(lhs);
67 auto rhs_access = acquire_host_read_access_sync(rhs);
68 auto output_span = output_access.mdspan();
69 auto lhs_span = lhs_access.mdspan();
70 auto rhs_span = rhs_access.mdspan();
71 return uni20::linalg::blas::try_gemm(output_span, alpha, lhs_span, rhs_span, beta);
72}
73
74template <class OutputTensor>
75auto prepared_output_mapping(typename output_mdspan_t<OutputTensor>::extents_type const& extents) ->
76 typename output_mdspan_t<OutputTensor>::mapping_type
77{
78 using output_span = output_mdspan_t<OutputTensor>;
80 if constexpr (!std::is_void_v<storage_policy>)
81 {
82 if constexpr (requires { typename storage_policy::default_mapping_builder; })
83 {
84 using builder_type = typename storage_policy::default_mapping_builder;
85 if constexpr (uni20::layout::mapping_builder_for<builder_type, typename output_span::layout_type,
86 typename output_span::extents_type>)
87 {
88 return builder_type{}(extents);
89 }
90 }
91 }
92 return uni20::layout::make_mapping<typename output_span::layout_type>(extents);
93}
94
95template <class OutputTensor>
96concept PreparedOutputProbeAvailable =
97 std::default_initializable<typename output_mdspan_t<OutputTensor>::data_handle_type> &&
98 std::default_initializable<typename output_mdspan_t<OutputTensor>::accessor_type> &&
99 requires(typename output_mdspan_t<OutputTensor>::extents_type const& extents) {
100 {
101 prepared_output_mapping<OutputTensor>(extents)
102 } -> std::same_as<typename output_mdspan_t<OutputTensor>::mapping_type>;
103 output_mdspan_t<OutputTensor>{typename output_mdspan_t<OutputTensor>::data_handle_type{},
104 prepared_output_mapping<OutputTensor>(extents),
105 typename output_mdspan_t<OutputTensor>::accessor_type{}};
106 };
107
108template <class OutputTensor>
109 requires PreparedOutputProbeAvailable<OutputTensor>
110auto prepared_output_probe(matrix_product_extents const& shape) -> output_mdspan_t<OutputTensor>
111{
112 using output_span = output_mdspan_t<OutputTensor>;
113 auto const extents = uni20::convert_tensor_extents<typename output_span::extents_type>(shape);
114 return output_span{typename output_span::data_handle_type{}, prepared_output_mapping<OutputTensor>(extents),
115 typename output_span::accessor_type{}};
116}
117
118template <class OutputTensor, class Scalar, class LhsMdspan, class RhsMdspan>
119KernelAttempt probe_assign_product(matrix_product_extents const& shape, LhsMdspan& lhs, RhsMdspan& rhs)
120{
121 if constexpr (!PreparedOutputProbeAvailable<OutputTensor>)
122 {
124 }
125 else
126 {
127 auto output_span = prepared_output_probe<OutputTensor>(shape);
128 return uni20::linalg::blas::probe_gemm<Scalar>(output_span, lhs, rhs);
129 }
130}
131
132} // namespace detail::blas_backend
133
135template <uni20::MutableRankedMdspecLike<2> OutputMdspan, class Scalar, uni20::RankedMdspecLike<2> LhsMdspan,
136 uni20::RankedMdspecLike<2> RhsMdspan>
139consteval auto kernel_accepts_types(BlasBackend const&, gemm_op const&, OutputMdspan&, Scalar const&, LhsMdspan&,
140 RhsMdspan&, Scalar const&)
141{
142 if constexpr (detail::blas_backend::gemm_mdspan_types_compatible<OutputMdspan, Scalar, LhsMdspan, RhsMdspan>())
143 return kernel_types_maybe;
144 else
145 return kernel_types_no;
146}
147
149template <uni20::MutableRankedMdspecLike<2> OutputMdspan, class Scalar, uni20::RankedMdspecLike<2> LhsMdspan,
150 uni20::RankedMdspecLike<2> RhsMdspan>
153KernelAttempt try_kernel(BlasBackend, gemm_op const&, OutputMdspan& output, Scalar alpha, LhsMdspan& lhs,
154 RhsMdspan& rhs, Scalar beta)
155{
156 return detail::blas_backend::try_gemm(output, alpha, lhs, rhs, beta);
157}
158
160template <uni20::MutableRankedTensorView<2> OutputTensor, class Scalar, uni20::RankedMdspecLike<2> LhsMdspan,
161 uni20::RankedMdspecLike<2> RhsMdspan>
162 requires BlasScalar<Scalar> && detail::blas_backend::HostAssignProductAccess<OutputTensor, LhsMdspan, RhsMdspan>
163consteval auto kernel_accepts_types(BlasBackend const&, assign_product_op const&, OutputTensor&, Scalar const&,
164 LhsMdspan&, RhsMdspan&)
165{
166 if constexpr (detail::blas_backend::assign_product_types_compatible<OutputTensor, Scalar, LhsMdspan, RhsMdspan>())
167 return kernel_types_maybe;
168 else
169 return kernel_types_no;
170}
171
177template <uni20::MutableRankedTensorView<2> OutputTensor, class Scalar, uni20::RankedMdspecLike<2> LhsMdspan,
178 uni20::RankedMdspecLike<2> RhsMdspan>
179 requires BlasScalar<Scalar> && detail::blas_backend::HostAssignProductAccess<OutputTensor, LhsMdspan, RhsMdspan>
180KernelAttempt try_kernel(BlasBackend, assign_product_op const&, OutputTensor& output, Scalar alpha, LhsMdspan& lhs,
181 RhsMdspan& rhs)
182{
183 auto const shape = detail::matrix_product_shape(lhs, rhs);
184 if (uni20::tensor_extents_equal(output.extents(), shape))
185 {
186 auto output_span = uni20::mdspec_of(output);
187 return detail::blas_backend::try_gemm(output_span, alpha, lhs, rhs, Scalar{});
188 }
189
191 {
193 }
194
195 KernelAttempt const probe = detail::blas_backend::probe_assign_product<OutputTensor, Scalar>(shape, lhs, rhs);
196 if (!kernel_attempt_succeeded(probe)) return probe;
197
198 uni20::prepare_output(output, shape);
199 auto output_span = uni20::mdspec_of(output);
200 KernelAttempt const attempt = detail::blas_backend::try_gemm(output_span, alpha, lhs, rhs, Scalar{});
202 return attempt;
203}
204
206template <uni20::MutableRankedTensorView<2> OutputTensor, class Scalar, uni20::RankedMdspecLike<2> LhsMdspan,
207 uni20::RankedMdspecLike<2> RhsMdspan>
208 requires BlasScalar<Scalar> && detail::blas_backend::HostAssignProductAccess<OutputTensor, LhsMdspan, RhsMdspan>
209consteval auto kernel_accepts_types(BlasBackend const&, assign_product_op const&, async::shared_storage<OutputTensor>&,
210 Scalar const&, LhsMdspan&, RhsMdspan&)
211{
212 if constexpr (detail::blas_backend::assign_product_types_compatible<OutputTensor, Scalar, LhsMdspan, RhsMdspan>())
213 return kernel_types_maybe;
214 else
215 return kernel_types_no;
216}
217
219template <uni20::MutableRankedTensorView<2> OutputTensor, class Scalar, uni20::RankedMdspecLike<2> LhsMdspan,
220 uni20::RankedMdspecLike<2> RhsMdspan>
221 requires BlasScalar<Scalar> && detail::blas_backend::HostAssignProductAccess<OutputTensor, LhsMdspan, RhsMdspan> &&
222 requires(async::shared_storage<OutputTensor>& storage, detail::matrix_product_extents const& shape) {
223 uni20::prepare_output(storage, shape);
224 }
225KernelAttempt try_kernel(BlasBackend backend, assign_product_op const&,
226 async::shared_storage<OutputTensor>& output_storage, Scalar alpha, LhsMdspan& lhs,
227 RhsMdspan& rhs)
228{
229 if (output_storage.constructed()) return try_kernel(backend, assign_product_op{}, *output_storage, alpha, lhs, rhs);
230
231 auto const shape = detail::matrix_product_shape(lhs, rhs);
232 KernelAttempt const probe = detail::blas_backend::probe_assign_product<OutputTensor, Scalar>(shape, lhs, rhs);
233 if (!kernel_attempt_succeeded(probe)) return probe;
234
235 auto& output = uni20::prepare_output(output_storage, shape);
236 auto output_span = uni20::mdspec_of(output);
237 KernelAttempt const attempt = detail::blas_backend::try_gemm(output_span, alpha, lhs, rhs, Scalar{});
239 return attempt;
240}
241
242} // namespace uni20::linalg
243
244#endif // UNI20_BACKEND_BLAS
RAII leases that resolve device descriptors and tensor views to mdspans.
A lightweight, thread-safe, reference-counted storage for a single object.
Definition shared_storage.hpp:94
bool constructed() const noexcept
Reports whether a value is currently constructed.
Definition shared_storage.hpp:234
Mdspec metadata supporting host read acquisition.
Definition access.hpp:688
Mutable mdspec metadata supporting host write acquisition.
Definition access.hpp:694
Mutable tensor output that can replace its shape and storage.
Definition tensor/output.hpp:76
Definition layout.hpp:18
Operation-tag backend dispatch over tensor-view operands.
Direct mdspan GEMM wrappers over the configured BLAS provider.
Backend-independent dense matrix-product shape validation.
KernelAttempt try_gemm(OutputMdspan &&output, Scalar alpha, LhsMdspan &&lhs, RhsMdspan &&rhs, Scalar beta)
Try a direct no-copy BLAS GEMM from mdspan-like operands.
Definition linalg/blas/gemm.hpp:255
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
KernelAttempt try_kernel(BlasBackend, gemm_op const &, C &c, S const &alpha, A &a, B &b, S const &beta)
Pack logical host values and execute GEMM through value-preserving provider conversion.
Definition linalg/backends/blas/binary80.hpp:30
KernelAttempt
Result of one runtime kernel backend attempt.
Definition kernel_attempt.hpp:27
constexpr KernelAcceptance< KernelTypeAcceptance::no > kernel_types_no
Report that a backend rejects the argument types.
Definition dispatch_error.hpp:34
consteval auto kernel_accepts_types(BlasBackend, gemm_op const &, C &, S const &, A &, B &, S const &)
Accept host-readable native binary80 operands, including transforming accessors.
Definition linalg/backends/blas/binary80.hpp:19
constexpr KernelAcceptance< KernelTypeAcceptance::maybe > kernel_types_maybe
Report that runtime operand values determine backend acceptance.
Definition dispatch_error.hpp:37
typename detail::TensorStoragePolicy< std::remove_cvref_t< Tensor > >::type tensor_storage_policy_t
Storage-policy type exposed by a tensor-level object, or void.
Definition tensor/concepts.hpp:40
std::remove_cvref_t< decltype(std::declval< detail::host_read_mdspan_lease_t< Mdspec > & >().mdspan())> host_read_mdspan_t
Read-only mdspan type resolved by host descriptor acquisition.
Definition access.hpp:679
Output & prepare_output(Output &output, RequiredExtents const &required)
Prepare a mutable tensor output with the specified shape.
Definition tensor/output.hpp:104
auto acquire_host_read_access_sync(Mdspan const &mdspan)
Acquire a directly host-accessible read-only mdspan.
Definition access.hpp:616
std::remove_cvref_t< decltype(std::declval< detail::host_write_mdspan_lease_t< Mdspec > & >().mdspan())> host_write_mdspan_t
Writable mdspan type resolved by host descriptor acquisition.
Definition access.hpp:684
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
auto acquire_host_write_access_sync(Mdspan &mdspan)
Acquire a directly host-accessible writable mdspan.
Definition access.hpp:626
Backend-independent operation values used with normalized kernel operands.
Concepts for tensor-level objects that resolve mdspan kernel operands.
Shape preparation contracts for tensor operation outputs.
#define CHECK(cond,...)
Definition trace.hpp:299