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