Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
linalg/backends/cuda/conjugate_inplace.hpp
Go to the documentation of this file.
1#pragma once
2
10#include <uni20/core/math.hpp>
18
19#include <concepts>
20#include <cstddef>
21#include <limits>
22#include <memory>
23#include <tuple>
24#include <type_traits>
25#include <utility>
26
27namespace uni20::linalg
28{
29namespace detail::cuda_reference
30{
31
32template <class Mdspec> using conjugate_scalar_t = std::remove_cv_t<typename std::remove_cvref_t<Mdspec>::element_type>;
33
34template <class Mdspec>
35concept SupportedConjugateMdspec = uni20::MutableMdspecLike<Mdspec> && is_raw_mutable_cuda_mdspec<Mdspec> &&
37 (uni20::has_trivial_conj<conjugate_scalar_t<Mdspec>> ||
38 ((std::remove_cvref_t<Mdspec>::rank() == 0 || uni20::StridedMdspecLike<Mdspec>) &&
39 supports_elementwise_conjugate<conjugate_scalar_t<Mdspec>>));
40
41template <class Scalar> struct ConjugatePlan
42{
44 uni20::cuda::CudaBuffer<Scalar>* buffer = nullptr;
45 std::size_t element_offset = 0;
46 std::size_t required_span_size = 0;
47 LoweredElementwiseConjugatePlan elementwise_plan;
48 bool has_work = false;
49};
50
51template <uni20::MdspecLike Mdspec>
52 requires(std::remove_cvref_t<Mdspec>::rank() == 0 || uni20::StridedMdspecLike<Mdspec>)
53[[nodiscard]] bool try_make_elementwise_conjugate_plan(Mdspec const& mdspec, LoweredElementwiseConjugatePlan& plan)
54{
55 auto host_plan = make_multi_iteration_plan(std::tuple{mdspec.mapping()});
56 return try_lower_strided_elementwise_plan<elementwise_conjugate_maximum_rank>(host_plan, plan);
57}
58
59template <class Mdspec>
60 requires SupportedConjugateMdspec<Mdspec>
61[[nodiscard]] auto prepare_conjugate_inplace(Mdspec& mdspec)
62{
63 using scalar_type = conjugate_scalar_t<Mdspec>;
64 ConjugatePlan<scalar_type> plan;
65
66 if constexpr (uni20::has_trivial_conj<scalar_type>)
67 {
68 // Direct backend dispatch remains valid even when a higher-level conj view
69 // would normally erase this identity operation.
70 plan.attempt = KernelAttempt::success;
71 return plan;
72 }
73 else
74 {
75 if (!mdspec.mapping().is_unique() || !try_make_elementwise_conjugate_plan(mdspec, plan.elementwise_plan))
76 {
78 return plan;
79 }
80
81 plan.has_work = plan.elementwise_plan.element_count() != 0;
82 if (!plan.has_work)
83 {
84 plan.attempt = KernelAttempt::success;
85 return plan;
86 }
87
88 auto const required = mdspec.mapping().required_span_size();
89 if (std::cmp_less(required, 0) || std::cmp_greater(required, std::numeric_limits<std::size_t>::max()))
90 {
92 return plan;
93 }
94 plan.required_span_size = static_cast<std::size_t>(required);
95
96 auto descriptor = mdspec.data_descriptor();
97 plan.buffer = std::addressof(descriptor.buffer());
98 plan.element_offset = descriptor.element_offset();
99 CHECK(plan.element_offset <= plan.buffer->size() &&
100 plan.required_span_size <= plan.buffer->size() - plan.element_offset,
101 plan.element_offset, plan.required_span_size, plan.buffer->size());
102
103 plan.attempt = KernelAttempt::success;
104 return plan;
105 }
106}
107
108template <class Scalar> void execute_conjugate_inplace(ConjugatePlan<Scalar> const& plan)
109{
110 CHECK(kernel_attempt_succeeded(plan.attempt));
111 if (!plan.has_work) return;
112 CHECK(plan.buffer != nullptr);
113
114 auto stream = plan.buffer->resources().streams().acquire();
115 int const device = plan.buffer->device().ordinal();
116 CHECK_EQUAL(stream.device(), device);
117 uni20::cuda::ScopedDevice guard(device);
118 auto access = plan.buffer->write_synchronized_with(stream);
119 auto* output = access.data() + plan.element_offset;
120
121 if constexpr (supports_elementwise_conjugate<Scalar>)
122 {
123 plan.elementwise_plan.visit([&](auto const& elementwise_plan) {
124 enqueue_elementwise_conjugate(output, elementwise_plan, stream.native_handle(), device);
125 });
126 }
127 else
128 {
129 PANIC("unsupported scalar reached CUDA reference elementwise conjugation");
130 }
131}
132
134template <uni20::MutableMdspecLike Mdspec> consteval auto conjugate_acceptance()
135{
136 if constexpr (SupportedConjugateMdspec<Mdspec>)
137 return kernel_types_maybe;
138 else
139 return kernel_types_no;
140}
141
143template <class Mdspec>
144 requires SupportedConjugateMdspec<Mdspec>
145KernelAttempt conjugate_inplace(Mdspec& mdspec)
146{
147 auto preparation = prepare_conjugate_inplace(mdspec);
148 if (!kernel_attempt_succeeded(preparation.attempt)) return preparation.attempt;
149 execute_conjugate_inplace(preparation);
151}
152
153} // namespace detail::cuda_reference
154
156template <uni20::MutableMdspecLike Mdspec>
158{
159 constexpr auto acceptance = detail::cuda_reference::conjugate_acceptance<Mdspec>();
160 if constexpr (acceptance == KernelTypeAcceptance::maybe)
161 return kernel_types_maybe;
162 else
163 return kernel_types_no;
164}
165
167template <class Mdspec>
168 requires detail::cuda_reference::SupportedConjugateMdspec<Mdspec>
170{
171 return detail::cuda_reference::conjugate_inplace(mdspec);
172}
173
174} // namespace uni20::linalg
Typed CUDA device buffers and scoped stream access guards.
Move-only logical CUDA buffer and completion state.
Definition buffer.hpp:222
Temporarily select one CUDA device and restore the previous device on destruction.
Definition runtime.hpp:44
Store a data descriptor with the mapping and accessor for an eventual mdspan.
Definition mdspec.hpp:31
MdspecLike types whose eventual storage supports writes.
Definition mdspan/concepts.hpp:398
Concept for numeric scalar types (integer, real, or complex).
Definition scalar_concepts.hpp:81
An mdspec-like type whose mapping exposes multidimensional strides.
Definition mdspan/concepts.hpp:427
CUDA Tensor storage with deferred device-memory data descriptors.
Operation-tag backend dispatch over tensor-view operands.
Typed launch boundary for CUDA accessor-respecting in-place conjugation.
auto make_multi_iteration_plan(std::tuple< Mappings... > const &mappings)
Build a merged iteration plan for multiple tensors sharing the same extents.
Definition iteration_plan.hpp:263
Helpers for constructing merged iteration plans over strided tensors.
Scalar math helper utilities.
Mdspan concept and accessor extensions for Uni20.
Shared CUDA reference-backend traits for raw buffer mdspecs.
stream
Selects the ordinary display stream for a message.
Definition display.hpp:25
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
void conjugate_inplace(BackendSelector selector, async::Async< Tensor > &tensor)
Schedule eager in-place conjugation through an explicit selector.
Definition linalg/async/conjugate_inplace.hpp:44
Backend-independent operation values used with normalized kernel operands.
Backend value for generic CUDA runtime kernels and transfers.
Definition backend_selector.hpp:48
Accessor-respecting in-place scalar conjugation operation tag.
Definition operation_tags.hpp:39
#define CHECK(cond,...)
Definition trace.hpp:299
#define PANIC(...)
Definition trace.hpp:382
#define CHECK_EQUAL(a, b,...)
Definition trace.hpp:309