ImpactX
Loading...
Searching...
No Matches
TrackedVector.H
Go to the documentation of this file.
1/* Copyright 2022-2023 The Regents of the University of California, through Lawrence
2* Berkeley National Laboratory (subject to receipt of any required
3 * approvals from the U.S. Dept. of Energy). All rights reserved.
4 *
5 * This file is part of ImpactX.
6 *
7 * FIXME: SHOULD BE REPLACED WITH amrex::Gpu::TrackedVector in v26.05+, see
8 * https://github.com/AMReX-Codes/amrex/pull/5253
9 *
10 * Authors: Axel Huebl
11 * License: BSD-3-Clause-LBNL
12 */
13#ifndef IMPACTX_TRACKED_VECTOR_H
14#define IMPACTX_TRACKED_VECTOR_H
15
16#include <AMReX.H>
17#include <AMReX_GpuContainers.H>
18
19#include <memory>
20#include <type_traits>
21#include <utility>
22#include <vector>
23
24
26{
47 template <class T>
49 {
50 static_assert(std::is_trivially_copyable<T>(), "TrackedVector can only hold trivially copyable types");
51 using value_type = T;
52 using size_type = std::size_t;
53
54 private:
56#ifdef AMREX_USE_GPU
57 if (*m_finalize_registered) { return; }
58 *m_finalize_registered = true;
59
60 std::weak_ptr<std::vector<T>> weak_host = m_host;
61 std::weak_ptr<amrex::Gpu::DeviceVector<T>> weak_device = m_device;
62 std::weak_ptr<Status> weak_status = m_status;
63 std::weak_ptr<bool> weak_registered = m_finalize_registered;
64
65 amrex::ExecOnFinalize([weak_host, weak_device, weak_status, weak_registered]() {
66 // see: release_gpu()
67 auto host = weak_host.lock();
68 auto device = weak_device.lock();
69 auto status = weak_status.lock();
70 if (host && device && status
72 && !device->empty())
73 {
74 // see: to_host()
75 host->resize(device->size());
77 device->begin(), device->end(), host->begin());
78 }
79 if (device) {
80 device->clear();
81 device->shrink_to_fit();
82 }
83 if (status) {
85 }
86 if (auto reg = weak_registered.lock()) {
87 *reg = false;
88 }
89 });
90#endif
91 }
92 public:
93
94 TrackedVector () = default;
95
96 explicit TrackedVector (size_type a_size)
97 : m_host(std::make_shared<std::vector<T>>(a_size))
98 {
99#ifdef AMREX_USE_GPU
101#endif
102 }
103
104 TrackedVector (size_type a_size, value_type const & a_value)
105 : m_host(std::make_shared<std::vector<T>>(a_size, a_value))
106 {
107#ifdef AMREX_USE_GPU
109#endif
110 }
111
112 TrackedVector (std::initializer_list<T> a_initializer_list)
113 : m_host(std::make_shared<std::vector<T>>(a_initializer_list))
114 {
115#ifdef AMREX_USE_GPU
117#endif
118 }
119
120 TrackedVector (std::vector<T> a_vector)
121 : m_host(std::make_shared<std::vector<T>>(std::move(a_vector)))
122 {
123#ifdef AMREX_USE_GPU
125#endif
126 }
127
128 TrackedVector (TrackedVector const & a_vector)
129 : m_host(std::make_shared<std::vector<T>>(*a_vector.m_host))
130 {
131 *m_status = *a_vector.m_status;
132#ifdef AMREX_USE_GPU
133 *m_device = *a_vector.m_device;
134#endif
135 }
136
138 TrackedVector (TrackedVector && a_vector) noexcept
139 {
140 std::swap(m_status, a_vector.m_status);
141 std::swap(m_host, a_vector.m_host);
142#ifdef AMREX_USE_GPU
143 std::swap(m_device, a_vector.m_device);
144 std::swap(m_finalize_registered, a_vector.m_finalize_registered);
145#endif
146 }
147
149 if (this != &a_vector) {
150 *m_status = *a_vector.m_status;
151 *m_host = *a_vector.m_host;
152#ifdef AMREX_USE_GPU
153 *m_device = *a_vector.m_device;
154#endif
155 }
156 return *this;
157 }
158
160 TrackedVector& operator= (TrackedVector && a_vector) noexcept {
161 if (this != &a_vector) {
162 std::swap(m_host, a_vector.m_host);
163 std::swap(m_status, a_vector.m_status);
164#ifdef AMREX_USE_GPU
165 std::swap(m_device, a_vector.m_device);
166 std::swap(m_finalize_registered, a_vector.m_finalize_registered);
167#endif
168 }
169 return *this;
170 }
171
172 ~TrackedVector () = default;
173
179
180 [[nodiscard]] Status status () const { return *m_status; }
181
187 [[nodiscard]] std::vector<T> &
188 host () {
189#ifdef AMREX_USE_GPU
191 to_host();
192 }
194#endif
195 return *m_host;
196 }
197
202 [[nodiscard]] std::vector<T> const &
203 host_const () const {
204#ifdef AMREX_USE_GPU
206 to_host();
207 }
208#endif
209 return *m_host;
210 }
211
212#ifdef AMREX_USE_GPU
218 [[nodiscard]] amrex::Gpu::DeviceVector<T> &
219 device () {
220 if (!amrex::Initialized()) {
221 throw std::runtime_error("TrackedVector::device() called before AMReX initialize/after AMReX finalize");
222 }
225 to_device();
226 }
228 return *m_device;
229 }
230
235 [[nodiscard]] amrex::Gpu::DeviceVector<T> const &
236 device_const () const {
237 if (!amrex::Initialized()) {
238 throw std::runtime_error("TrackedVector::device_const() called before AMReX initialize/after AMReX finalize");
239 }
240 const_cast<TrackedVector*>(this)->register_finalize();
242 to_device();
243 }
244 return *m_device;
245 }
246#else
248 [[nodiscard]] std::vector<T> &
249 device () { return *m_host; }
250
252 [[nodiscard]] std::vector<T> const &
253 device_const () const { return *m_host; }
254#endif
255
264 {
265#ifdef AMREX_USE_GPU
267 to_host();
268 }
269 m_device->clear();
270 m_device->shrink_to_fit();
272#endif
273 }
274
275 private:
276
278 void to_device () const {
279#ifdef AMREX_USE_GPU
280 if (!amrex::Initialized()) {
281 throw std::runtime_error("TrackedVector::to_device() called outside of AMReX initialize/finalize");
282 }
283 auto const size = m_host->size();
284 if (size > 0U) {
285 m_device->resize(size);
287 m_host->begin(), m_host->end(), m_device->begin());
288 } else {
289 m_device->clear();
290 }
292#endif
293 }
294
296 void to_host () const {
297#ifdef AMREX_USE_GPU
298 if (!amrex::Initialized()) {
299 throw std::runtime_error("TrackedVector::to_host() called outside of AMReX initialize/finalize");
300 }
301 m_host->resize(m_device->size());
303 m_device->begin(), m_device->end(), m_host->begin());
305#endif
306 }
307
308 mutable std::shared_ptr<Status> m_status = std::make_shared<Status>();
309 mutable std::shared_ptr<std::vector<T>> m_host = std::make_shared<std::vector<T>>();
310#ifdef AMREX_USE_GPU
311 mutable std::shared_ptr<amrex::Gpu::DeviceVector<T>> m_device = std::make_shared<amrex::Gpu::DeviceVector<T>>();
312 mutable std::shared_ptr<bool> m_finalize_registered = std::make_shared<bool>(false);
313#endif
314 };
315
316}
317
318#endif
PODVector< T, ArenaAllocator< T > > DeviceVector
void copy(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
static constexpr DeviceToHost deviceToHost
static constexpr HostToDevice hostToDevice
void ExecOnFinalize(std::function< void()>)
bool Initialized()
Definition alignment.H:23
std::size_t size_type
Definition TrackedVector.H:52
TrackedVector & operator=(TrackedVector const &a_vector)
Definition TrackedVector.H:148
std::vector< T > const & device_const() const
Definition TrackedVector.H:253
Status
Definition TrackedVector.H:174
@ host_dirty
device data needs an update
Definition TrackedVector.H:177
@ up_to_date
host and device data are in sync
Definition TrackedVector.H:175
@ device_dirty
host data needs an update
Definition TrackedVector.H:176
T value_type
Definition TrackedVector.H:51
void release_gpu()
Definition TrackedVector.H:263
TrackedVector(std::vector< T > a_vector)
Definition TrackedVector.H:120
std::shared_ptr< std::vector< T > > m_host
Definition TrackedVector.H:309
void to_host() const
Definition TrackedVector.H:296
std::vector< T > const & host_const() const
Definition TrackedVector.H:203
void to_device() const
Definition TrackedVector.H:278
TrackedVector(size_type a_size)
Definition TrackedVector.H:96
TrackedVector(TrackedVector &&a_vector) noexcept
Definition TrackedVector.H:138
Status status() const
Definition TrackedVector.H:180
std::shared_ptr< Status > m_status
Definition TrackedVector.H:308
void register_finalize()
Definition TrackedVector.H:55
std::vector< T > & device()
Definition TrackedVector.H:249
TrackedVector(TrackedVector const &a_vector)
Definition TrackedVector.H:128
std::vector< T > & host()
Definition TrackedVector.H:188
TrackedVector(size_type a_size, value_type const &a_value)
Definition TrackedVector.H:104
TrackedVector(std::initializer_list< T > a_initializer_list)
Definition TrackedVector.H:112