Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
cuda_access.hpp
Go to the documentation of this file.
1
7#pragma once
8
12
13#include <concepts>
14#include <cstddef>
15#include <type_traits>
16#include <utility>
17
18namespace uni20
19{
20namespace detail
21{
22
23template <class Accessor> [[nodiscard]] constexpr auto lower_cuda_accessor(Accessor const& accessor)
24{
25 return accessor;
26}
27
28template <class Real>
29[[nodiscard]] constexpr auto
30lower_cuda_accessor(conjugated_accessor<cuda::CudaPointerAccessor<standard_complex<Real> const>> const&)
31{
32 return cuda::CudaConjugatingPointerAccessor<Real>{};
33}
34
35template <class Pointer> [[nodiscard]] Pointer offset_cuda_pointer(Pointer pointer, std::size_t offset) noexcept
36{
37 if (offset == 0) return pointer;
38 CHECK(pointer != nullptr, "cannot offset an empty CUDA data handle", offset);
39 return pointer + offset;
40}
41
42template <class Mdspec> void validate_cuda_descriptor_range(Mdspec const& span)
43{
44 auto const& descriptor = span.data_descriptor();
45 auto const required = span.mapping().required_span_size();
46 CHECK(std::cmp_greater_equal(required, 0), required);
47 CHECK(std::cmp_less_equal(required, descriptor.buffer().size()), required, descriptor.buffer().size());
48 auto const count = static_cast<std::size_t>(required);
49 auto const offset = descriptor.element_offset();
50 CHECK(offset <= descriptor.buffer().size() && count <= descriptor.buffer().size() - offset, offset, count,
51 descriptor.buffer().size());
52}
53
54template <class Mdspec, class Pointer> [[nodiscard]] auto resolve_cuda_mdspan(Mdspec const& span, Pointer pointer)
55{
56 using span_type = std::remove_cvref_t<Mdspec>;
57 auto accessor = lower_cuda_accessor(span.accessor());
58 using accessor_type = decltype(accessor);
59 static_assert(std::same_as<typename accessor_type::element_type, typename span_type::element_type>);
60 using mdspan_type = stdex::mdspan<typename accessor_type::element_type, typename span_type::extents_type,
61 typename span_type::layout_type, accessor_type>;
62 return mdspan_type{pointer, span.mapping(), std::move(accessor)};
63}
64
65template <class Mdspec, class AccessState>
66[[nodiscard]] auto make_cuda_read_mdspan_lease(Mdspec mdspec, std::size_t element_offset, AccessState state)
67{
68 auto const pointer = offset_cuda_pointer(state.data(), element_offset);
69 auto mdspan = resolve_cuda_mdspan(mdspec, pointer);
70 return read_mdspan_lease<decltype(mdspan), AccessState>{std::move(state), std::move(mdspan)};
71}
72
73template <class Mdspec, class AccessState>
74[[nodiscard]] auto make_cuda_write_mdspan_lease(Mdspec mdspec, AccessState state)
75{
76 auto const offset = static_cast<std::size_t>(mdspec.data_descriptor().element_offset());
77 auto pointer = offset_cuda_pointer(state.data(), offset);
78 auto mdspan = resolve_cuda_mdspan(mdspec, pointer);
79 return write_mdspan_lease<decltype(mdspan), AccessState>{std::move(state), std::move(mdspan)};
80}
81
82template <class StoragePolicy, class Mdspec, class AccessState, class BackendSelector>
83[[nodiscard]] auto make_cuda_read_tensor_lease(Mdspec mdspec, std::size_t element_offset, AccessState state,
84 BackendSelector selector)
85{
86 auto const pointer = offset_cuda_pointer(state.data(), element_offset);
87 auto mdspan = resolve_cuda_mdspan(mdspec, pointer);
88
89 using mdspan_type = decltype(mdspan);
90 using selector_type = std::remove_cvref_t<BackendSelector>;
91 return read_tensor_lease<mdspan_type, AccessState, selector_type, StoragePolicy>{std::move(state), std::move(mdspan),
92 std::move(selector)};
93}
94
95template <class StoragePolicy, class Mdspec, class ConstMdspec, class AccessState, class BackendSelector>
96[[nodiscard]] auto make_cuda_write_tensor_lease(Mdspec mdspec, ConstMdspec const_mdspec, AccessState state,
97 BackendSelector selector)
98{
99 CHECK(mdspec.data_descriptor().element_offset() == const_mdspec.data_descriptor().element_offset());
100
101 auto const offset = static_cast<std::size_t>(mdspec.data_descriptor().element_offset());
102 auto pointer = offset_cuda_pointer(state.data(), offset);
103 auto mdspan = resolve_cuda_mdspan(mdspec, pointer);
104 auto const_mdspan = resolve_cuda_mdspan(const_mdspec, pointer);
105
106 using mdspan_type = decltype(mdspan);
107 using const_mdspan_type = decltype(const_mdspan);
108 using selector_type = std::remove_cvref_t<BackendSelector>;
109 return write_tensor_lease<mdspan_type, const_mdspan_type, AccessState, selector_type, StoragePolicy>{
110 std::move(state), std::move(mdspan), std::move(const_mdspan), std::move(selector)};
111}
112
113} // namespace detail
114
118template <cuda::BufferMdspec Mdspec>
119 requires std::is_const_v<typename std::remove_cvref_t<Mdspec>::element_type>
120[[nodiscard]] auto acquire_cuda_read_access_sync(Mdspec const& mdspec)
121{
122 detail::validate_cuda_descriptor_range(mdspec);
123 auto const element_offset = static_cast<std::size_t>(mdspec.data_descriptor().element_offset());
124 auto state = mdspec.data_descriptor().buffer().blocking_read_access();
125 return detail::make_cuda_read_mdspan_lease(mdspec, element_offset, std::move(state));
126}
127
131template <class Mdspec>
132 requires cuda::BufferMdspec<Mdspec> && MutableMdspecLike<Mdspec>
133[[nodiscard]] auto acquire_cuda_write_access_sync(Mdspec& mdspec)
134{
135 detail::validate_cuda_descriptor_range(mdspec);
136 auto state = mdspec.data_descriptor().buffer().blocking_write_access();
137 return detail::make_cuda_write_mdspan_lease(mdspec, std::move(state));
138}
139
142template <class Tensor>
143 requires TensorView<Tensor> && (!ImmediateTensorView<Tensor>) && cuda::BufferMdspec<tensor_mdspec_t<Tensor>>
144[[nodiscard]] auto acquire_cuda_read_access_sync(Tensor& tensor)
145{
146 auto mdspec = mdspec_of(std::as_const(tensor));
147 detail::validate_cuda_descriptor_range(mdspec);
148 auto const element_offset = static_cast<std::size_t>(mdspec.data_descriptor().element_offset());
149 auto state = mdspec.data_descriptor().buffer().blocking_read_access();
150 return detail::make_cuda_read_tensor_lease<tensor_storage_policy_t<Tensor>>(
151 std::move(mdspec), element_offset, std::move(state), tensor.backend_selector());
152}
153
155template <class Tensor>
156 requires(!std::is_lvalue_reference_v<Tensor>) && TensorView<std::remove_cvref_t<Tensor>> &&
157 (!ImmediateTensorView<std::remove_cvref_t<Tensor>>) && OwningTensor<std::remove_cvref_t<Tensor>> &&
158 cuda::BufferMdspec<tensor_mdspec_t<std::remove_cvref_t<Tensor>>> && requires(Tensor&& tensor) {
159 { std::move(tensor).release_storage() } -> std::same_as<typename std::remove_cvref_t<Tensor>::storage_type>;
160 }
161[[nodiscard]] auto acquire_cuda_read_access_sync(Tensor&& tensor)
162{
163 auto mdspec = mdspec_of(std::as_const(tensor));
164 detail::validate_cuda_descriptor_range(mdspec);
165 auto const element_offset = static_cast<std::size_t>(mdspec.data_descriptor().element_offset());
166 auto selector = tensor.backend_selector();
167 auto storage = std::move(tensor).release_storage();
168 auto state = std::move(storage).into_blocking_read_access();
169 return detail::make_cuda_read_tensor_lease<tensor_storage_policy_t<Tensor>>(std::move(mdspec), element_offset,
170 std::move(state), std::move(selector));
171}
172
175template <class Tensor>
176 requires MutableTensorView<Tensor> && (!MutableImmediateTensorView<Tensor>) &&
177 cuda::BufferMdspec<tensor_mdspec_t<Tensor>> && cuda::BufferMdspec<mutable_tensor_mdspec_t<Tensor>>
178[[nodiscard]] auto acquire_cuda_write_access_sync(Tensor& tensor)
179{
180 auto mdspec = mdspec_of(tensor);
181 auto const_mdspec = mdspec_of(std::as_const(tensor));
182 detail::validate_cuda_descriptor_range(mdspec);
183 detail::validate_cuda_descriptor_range(const_mdspec);
184 auto state = mdspec.data_descriptor().buffer().blocking_write_access();
185 return detail::make_cuda_write_tensor_lease<tensor_storage_policy_t<Tensor>>(
186 std::move(mdspec), std::move(const_mdspec), std::move(state), tensor.backend_selector());
187}
188
190template <cuda::BufferMdspec Mdspec>
191 requires std::is_const_v<typename std::remove_cvref_t<Mdspec>::element_type>
192[[nodiscard]] auto acquire_cuda_read_access_async(Mdspec const& mdspec, cuda::Stream const& stream)
193{
194 detail::validate_cuda_descriptor_range(mdspec);
195 auto const element_offset = static_cast<std::size_t>(mdspec.data_descriptor().element_offset());
196 auto state = mdspec.data_descriptor().buffer().read_synchronized_with(stream);
197 return ready_access{detail::make_cuda_read_mdspan_lease(mdspec, element_offset, std::move(state))};
198}
199
201template <class Mdspec>
202 requires cuda::BufferMdspec<Mdspec> && MutableMdspecLike<Mdspec>
203[[nodiscard]] auto acquire_cuda_write_access_async(Mdspec& mdspec, cuda::Stream const& stream)
204{
205 detail::validate_cuda_descriptor_range(mdspec);
206 auto state = mdspec.data_descriptor().buffer().write_synchronized_with(stream);
207 return ready_access{detail::make_cuda_write_mdspan_lease(mdspec, std::move(state))};
208}
209
214template <class Tensor>
215 requires TensorView<Tensor> && (!ImmediateTensorView<Tensor>) && cuda::BufferMdspec<tensor_mdspec_t<Tensor>>
216[[nodiscard]] auto acquire_cuda_read_access_async(Tensor& tensor, cuda::Stream const& stream)
217{
218 auto mdspec = mdspec_of(std::as_const(tensor));
219 detail::validate_cuda_descriptor_range(mdspec);
220 auto const element_offset = static_cast<std::size_t>(mdspec.data_descriptor().element_offset());
221 auto state = mdspec.data_descriptor().buffer().read_synchronized_with(stream);
222 return ready_access{detail::make_cuda_read_tensor_lease<tensor_storage_policy_t<Tensor>>(
223 std::move(mdspec), element_offset, std::move(state), tensor.backend_selector())};
224}
225
227template <class Tensor>
228 requires(!std::is_lvalue_reference_v<Tensor>) && TensorView<std::remove_cvref_t<Tensor>> &&
229 (!ImmediateTensorView<std::remove_cvref_t<Tensor>>) && OwningTensor<std::remove_cvref_t<Tensor>> &&
230 cuda::BufferMdspec<tensor_mdspec_t<std::remove_cvref_t<Tensor>>> && requires(Tensor&& tensor) {
231 { std::move(tensor).release_storage() } -> std::same_as<typename std::remove_cvref_t<Tensor>::storage_type>;
232 }
233[[nodiscard]] auto acquire_cuda_read_access_async(Tensor&& tensor, cuda::Stream const& stream)
234{
235 auto mdspec = mdspec_of(std::as_const(tensor));
236 detail::validate_cuda_descriptor_range(mdspec);
237 auto const element_offset = static_cast<std::size_t>(mdspec.data_descriptor().element_offset());
238 auto selector = tensor.backend_selector();
239 auto storage = std::move(tensor).release_storage();
240 auto state = std::move(storage).into_read_synchronized_with(stream);
241 return ready_access{detail::make_cuda_read_tensor_lease<tensor_storage_policy_t<Tensor>>(
242 std::move(mdspec), element_offset, std::move(state), std::move(selector))};
243}
244
246template <class Tensor>
247 requires MutableTensorView<Tensor> && (!MutableImmediateTensorView<Tensor>) &&
248 cuda::BufferMdspec<tensor_mdspec_t<Tensor>> && cuda::BufferMdspec<mutable_tensor_mdspec_t<Tensor>>
249[[nodiscard]] auto acquire_cuda_write_access_async(Tensor& tensor, cuda::Stream const& stream)
250{
251 auto mdspec = mdspec_of(tensor);
252 auto const_mdspec = mdspec_of(std::as_const(tensor));
253 detail::validate_cuda_descriptor_range(mdspec);
254 detail::validate_cuda_descriptor_range(const_mdspec);
255 auto state = mdspec.data_descriptor().buffer().write_synchronized_with(stream);
256 return ready_access{detail::make_cuda_write_tensor_lease<tensor_storage_policy_t<Tensor>>(
257 std::move(mdspec), std::move(const_mdspec), std::move(state), tensor.backend_selector())};
258}
259
260} // namespace uni20
RAII leases that resolve device descriptors and tensor views to mdspans.
General-purpose owning tensor with immediate or deferred mdspan metadata.
Definition basic_tensor.hpp:109
static constexpr auto backend_selector() noexcept -> backend_selector_type
Return the default backend selector associated with this tensor's storage.
Definition basic_tensor.hpp:602
Reference-counted lease of one CUDA stream-pool slot.
Definition runtime.hpp:65
Store a data descriptor with the mapping and accessor for an eventual mdspan.
Definition mdspec.hpp:31
constexpr auto data_descriptor() noexcept -> data_descriptor_type &
Return the descriptor used to acquire writable data access.
Definition mdspec.hpp:77
Always-ready awaitable that transfers one access lease.
Definition access.hpp:592
Mdspan accessor adaptor for lazy complex conjugation.
CUDA Tensor storage with deferred device-memory data descriptors.
Definition async/async.hpp:26
auto acquire_cuda_read_access_async(Mdspec const &mdspec, cuda::Stream const &stream)
Resolve borrowed CUDA read access synchronized with an operation stream.
Definition cuda_access.hpp:192
auto acquire_cuda_write_access_sync(Mdspec &mdspec)
Host-wait for prior CUDA work and resolve a borrowed write descriptor.
Definition cuda_access.hpp:133
auto acquire_cuda_write_access_async(Mdspec &mdspec, cuda::Stream const &stream)
Resolve borrowed CUDA write access synchronized with an operation stream.
Definition cuda_access.hpp:203
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
auto acquire_cuda_read_access_sync(Mdspec const &mdspec)
Host-wait for prior CUDA work and resolve a borrowed read descriptor.
Definition cuda_access.hpp:120
std::size_t span
Definition presentation.cpp:2017
#define CHECK(cond,...)
Definition trace.hpp:299