ttg 1.0.0
Template Task Graph (TTG): flowgraph-based programming model for high-performance distributed-memory algorithms
Loading...
Searching...
No Matches
buffer.h
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2#ifndef TTG_MADNESS_BUFFER_H
3#define TTG_MADNESS_BUFFER_H
4
6
7#include "ttg/device/device.h"
8#include <memory>
9
10namespace ttg_madness {
11
13template<typename T, typename Allocator>
14struct Buffer : private Allocator {
15
16 using element_type = std::decay_t<T>;
17
18 using allocator_traits = std::allocator_traits<Allocator>;
19 using allocator_type = typename allocator_traits::allocator_type;
20
21 static_assert(std::is_trivially_copyable_v<element_type>,
22 "Only trivially copyable types are supported for devices.");
23 static_assert(std::is_default_constructible_v<element_type>,
24 "Only default constructible types are supported for devices.");
25
26private:
27 using delete_fn_t = std::function<void(element_type*)>;
28 using host_data_ptr = std::add_pointer_t<element_type>;
29 std::shared_ptr<element_type[]> m_sptr; // to capture smart pointers
30 host_data_ptr m_host_data = nullptr;
31 std::size_t m_count = 0;
32 bool m_owned= false;
33
34 static void delete_non_owned(element_type *ptr) {
35 // nothing to be done, we don't own the memory
36 }
37
38 allocator_type& get_allocator_reference() { return static_cast<allocator_type&>(*this); }
39
40 element_type* allocate(std::size_t n) {
41 return allocator_traits::allocate(get_allocator_reference(), n);
42 }
43
44 void deallocate() {
45 allocator_traits::deallocate(get_allocator_reference(), m_host_data, m_count);
46 }
47
48public:
49
50 Buffer() : Buffer(nullptr, 0)
51 { }
52
53 Buffer(std::size_t n, ttg::scope scope = ttg::scope::SyncIn)
55 , m_host_data(allocate(n))
56 , m_count(n)
57 , m_owned(true)
58 { }
59
60 /* Constructing a buffer using application-managed memory.
61 * The memory pointed to by ptr must be accessible during
62 * the life-time of the buffer. */
63 template<typename Deleter>
64 Buffer(std::unique_ptr<element_type[], Deleter> ptr, std::size_t n, ttg::scope scope = ttg::scope::SyncIn)
66 , m_sptr(std::move(ptr))
67 , m_host_data(m_sptr.get())
68 , m_count(n)
69 , m_owned(false)
70 { }
71
72 /* Constructing a buffer using application-managed memory.
73 * The memory pointed to by ptr must be accessible during
74 * the life-time of the buffer. */
75 Buffer(std::shared_ptr<element_type[]> ptr, std::size_t n, ttg::scope scope = ttg::scope::SyncIn)
77 , m_sptr(std::move(ptr))
78 , m_host_data(m_sptr.get())
79 , m_count(n)
80 , m_owned(false)
81 { }
82
83 virtual ~Buffer() {
84 if (m_owned) {
85 deallocate();
86 m_owned = false;
87 }
88 unpin(); // make sure the copies are not pinned
89 }
90
91 /* allow moving device buffers */
93 : allocator_type(std::move(db))
94 , m_host_data(db.m_host_data)
95 , m_count(db.m_count)
96 , m_owned(db.m_owned)
97 {
98 db.m_host_data = nullptr;
99 db.m_count = 0;
100 db.m_owned = false;
101 }
102
103 /* explicitly disable copying of buffers
104 * TODO: should we allow this? What data to use?
105 */
106 Buffer(const Buffer& db) = delete;
107
108 /* allow moving device buffers */
110 allocator_type::operator=(std::move(db));
111 std::swap(m_host_data, db.m_host_data);
112 std::swap(m_count, db.m_count);
113 std::swap(m_owned, db.m_owned);
114 return *this;
115 }
116
117 /* explicitly disable copying of buffers
118 * TODO: should we allow this? What data to use?
119 */
120 Buffer& operator=(const Buffer& db) = delete;
121
122 /* set the current device, useful when a device
123 * buffer was modified outside of a TTG */
125 assert(is_valid());
126 if (!device.is_host()) throw std::runtime_error("MADNESS backend does not support non-host memory!");
127 /* no-op */
128 }
129
130
132 assert(is_valid());
133 return true;
134 }
135
136 /* Get the owner device ID, i.e., the last updated
137 * device buffer. */
139 assert(is_valid());
140 return {}; // host only
141 }
142
143 /* Get the pointer on the currently active device. */
145 assert(is_valid());
146 return m_host_data;
147 }
148
149 /* Get the pointer on the currently active device. */
151 assert(is_valid());
152 return m_host_data;
153 }
154
155 /* Get the pointer on the owning device.
156 * @note: This may not be the device assigned to the currently executing task.
157 * See \ref ttg::device::current_device for that. */
159 assert(is_valid());
160 return m_host_data;
161 }
162
163 /* get the current device pointer */
165 assert(is_valid());
166 return m_host_data;
167 }
168
169 /* get the device pointer at the given device
170 */
172 assert(is_valid());
173 if (device.is_device()) throw std::runtime_error("MADNESS missing support for non-host memory!");
174 return m_host_data;
175 }
176
177 /* get the device pointer at the given device
178 */
179 const element_type* device_ptr_on(const ttg::device::Device& device) const {
180 assert(is_valid());
181 if (device.is_device()) throw std::runtime_error("MADNESS missing support for non-host memory!");
182 return m_host_data;
183 }
184
186 return m_host_data;
187 }
188
189 const element_type* host_ptr() const {
190 return m_host_data;
191 }
192
193 bool is_valid_on(const ttg::device::Device& device) const {
194 assert(is_valid());
195 if (device.is_device()) throw std::runtime_error("MADNESS missing support for non-host memory!");
196 return true;
197 }
198
199 void allocate_on(const ttg::device::Device& device_id) {
200 /* TODO: need exposed PaRSEC memory allocator */
201 throw std::runtime_error("not implemented yet");
202 }
203
204 bool empty() const {
205 return (m_host_data == nullptr);
206 }
207
208 /* TODO: can we do this automatically?
209 * Pin the memory on all devices we currently track.
210 * Pinned memory won't be released by PaRSEC and can be used
211 * at any time.
212 */
213 void pin() {
214 // nothing to do
215 }
216
217 /* Unpin the memory on all devices we currently track. */
218 void unpin() {
219 // nothing to do
220 }
221
222 /* Pin the memory on a given device */
223 void pin_on(int device_id) {
224 /* TODO: how can we pin memory on a device? */
225 }
226
227 /* Pin the memory on a given device */
228 void unpin_on(int device_id) {
229 /* TODO: how can we unpin memory on a device? */
230 }
231
232 bool is_valid() const {
233 return true;
234 }
235
236 operator bool() const {
237 return true;
238 }
239
240 std::size_t size() const {
241 return m_count;
242 }
243
244 /* Reallocate the buffer with count elements */
245 void reset(std::size_t n, ttg::scope scope = ttg::scope::SyncIn) {
246
247 if (m_owned) {
248 deallocate();
249 m_owned = false;
250 }
251
252 if (n == 0) {
253 m_host_data = nullptr;
254 m_owned = false;
255 } else {
256 m_host_data = allocate(n);
257 m_owned = true;
258 }
259 m_count = n;
260 }
261
262 /* Reallocate the buffer with count elements */
263 void reset(std::shared_ptr<element_type[]> ptr, std::size_t n, ttg::scope scope = ttg::scope::SyncIn) {
264
265 if (m_owned) {
266 deallocate();
267 m_owned = false;
268 }
269
270 m_sptr = std::move(ptr);
271 m_host_data = m_sptr.get();
272 m_count = n;
273 }
274
279 /* nothing to do here */
280 }
281
282 /* serialization support */
283
284#if defined(TTG_SERIALIZATION_SUPPORTS_MADNESS)
285 template <typename Archive>
286 std::enable_if_t<std::is_base_of_v<madness::archive::BufferInputArchive, Archive> ||
287 std::is_base_of_v<madness::archive::BufferOutputArchive, Archive>>
288 serialize(Archive& ar) {
289 if constexpr (ttg::detail::is_output_archive_v<Archive>) {
290 std::size_t s = size();
291 ar& s;
292 ar << madness::archive::wrap(host_ptr(), s);
293 } else {
294 std::size_t s;
295 ar & s;
296 reset(s);
297 ar >> madness::archive::wrap(host_ptr(), s); // MatrixTile<T>(bm.rows(), bm.cols());
298 }
299 }
300#endif // TTG_SERIALIZATION_SUPPORTS_MADNESS
301
302
303};
304
305} // namespace ttg_madness
306
307#endif // TTG_MADNESS_BUFFER_H
Represents a device in a specific execution space.
Definition device.h:19
bool is_host() const
Definition device.h:56
bool is_device() const
Definition device.h:52
STL namespace.
this contains MADNESS-based TTG functionality
Definition fwd.h:17
A runtime-managed buffer mirrored between host and device memory.
Definition buffer.h:14
const element_type * host_ptr() const
Definition buffer.h:189
bool empty() const
Definition buffer.h:204
ttg::device::Device get_owner_device() const
Definition buffer.h:138
void reset(std::shared_ptr< element_type[]> ptr, std::size_t n, ttg::scope scope=ttg::scope::SyncIn)
Definition buffer.h:263
const element_type * owner_device_ptr() const
Definition buffer.h:164
Buffer & operator=(const Buffer &db)=delete
bool is_current_on(ttg::device::Device dev) const
Definition buffer.h:131
virtual ~Buffer()
Definition buffer.h:83
void unpin_on(int device_id)
Definition buffer.h:228
Buffer(Buffer &&db)
Definition buffer.h:92
std::decay_t< T > element_type
Definition buffer.h:16
void reset_scope(ttg::scope scope)
Definition buffer.h:278
void reset(std::size_t n, ttg::scope scope=ttg::scope::SyncIn)
Definition buffer.h:245
Buffer(const Buffer &db)=delete
Buffer(std::shared_ptr< element_type[]> ptr, std::size_t n, ttg::scope scope=ttg::scope::SyncIn)
Definition buffer.h:75
bool is_valid() const
Definition buffer.h:232
const element_type * device_ptr_on(const ttg::device::Device &device) const
Definition buffer.h:179
element_type * device_ptr_on(const ttg::device::Device &device)
Definition buffer.h:171
element_type * current_device_ptr()
Definition buffer.h:144
std::size_t size() const
Definition buffer.h:240
bool is_valid_on(const ttg::device::Device &device) const
Definition buffer.h:193
element_type * host_ptr()
Definition buffer.h:185
void allocate_on(const ttg::device::Device &device_id)
Definition buffer.h:199
typename allocator_traits::allocator_type allocator_type
Definition buffer.h:19
element_type * owner_device_ptr()
Definition buffer.h:158
void pin_on(int device_id)
Definition buffer.h:223
std::allocator_traits< Allocator > allocator_traits
Definition buffer.h:18
Buffer & operator=(Buffer &&db)
Definition buffer.h:109
Buffer(std::unique_ptr< element_type[], Deleter > ptr, std::size_t n, ttg::scope scope=ttg::scope::SyncIn)
Definition buffer.h:64
Buffer(std::size_t n, ttg::scope scope=ttg::scope::SyncIn)
Definition buffer.h:53
const element_type * current_device_ptr() const
Definition buffer.h:150
void set_current_device(const ttg::device::Device &device)
Definition buffer.h:124