MFEM  v4.5.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
mem_manager.hpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #ifndef MFEM_MEM_MANAGER_HPP
13 #define MFEM_MEM_MANAGER_HPP
14 
15 #include "globals.hpp"
16 #include "error.hpp"
17 #include <cstring> // std::memcpy
18 #include <type_traits> // std::is_const
19 #include <cstddef> // std::max_align_t
20 #ifdef MFEM_USE_MPI
21 #include <HYPRE_config.h> // HYPRE_USING_GPU
22 #endif
23 
24 namespace mfem
25 {
26 
27 // Implementation of MFEM's lightweight device/host memory manager designed to
28 // work seamlessly with the OCCA, RAJA, and other kernels supported by MFEM.
29 
30 /// Memory types supported by MFEM.
31 enum class MemoryType
32 {
33  HOST, ///< Host memory; using new[] and delete[]
34  HOST_32, ///< Host memory; aligned at 32 bytes
35  HOST_64, ///< Host memory; aligned at 64 bytes
36  HOST_DEBUG, ///< Host memory; allocated from a "host-debug" pool
37  HOST_UMPIRE, /**< Host memory; using an Umpire allocator which can be set
38  with MemoryManager::SetUmpireHostAllocatorName */
39  HOST_PINNED, ///< Host memory: pinned (page-locked)
40  MANAGED, /**< Managed memory; using CUDA or HIP *MallocManaged
41  and *Free */
42  DEVICE, ///< Device memory; using CUDA or HIP *Malloc and *Free
43  DEVICE_DEBUG, /**< Pseudo-device memory; allocated on host from a
44  "device-debug" pool */
45  DEVICE_UMPIRE, /**< Device memory; using an Umpire allocator which can be
46  set with MemoryManager::SetUmpireDeviceAllocatorName */
47  DEVICE_UMPIRE_2, /**< Device memory; using a second Umpire allocator settable
48  with MemoryManager::SetUmpireDevice2AllocatorName */
49  SIZE, ///< Number of host and device memory types
50 
51  PRESERVE, /**< Pseudo-MemoryType used as default value for MemoryType
52  parameters to request preservation of existing
53  MemoryType, e.g. in copy constructors. */
54  DEFAULT /**< Pseudo-MemoryType used as default value for MemoryType
55  parameters to request the use of the default host or
56  device MemoryType. */
57 };
58 
59 /// Static casts to 'int' and sizes of some useful memory types.
60 constexpr int MemoryTypeSize = static_cast<int>(MemoryType::SIZE);
61 constexpr int HostMemoryType = static_cast<int>(MemoryType::HOST);
62 constexpr int HostMemoryTypeSize = static_cast<int>(MemoryType::DEVICE);
63 constexpr int DeviceMemoryType = static_cast<int>(MemoryType::MANAGED);
65 
66 /// Memory type names, used during Device:: configuration.
67 extern const char *MemoryTypeName[MemoryTypeSize];
68 
69 /// Memory classes identify sets of memory types.
70 /** This type is used by kernels that can work with multiple MemoryType%s.
71  * For example, kernels that can use DEVICE or MANAGED memory types should
72  * use MemoryClass::DEVICE for their inputs. */
73 enum class MemoryClass
74 {
75  HOST, /**< Memory types: { HOST, HOST_32, HOST_64, HOST_DEBUG,
76  HOST_UMPIRE, HOST_PINNED, MANAGED } */
77  HOST_32, ///< Memory types: { HOST_32, HOST_64, HOST_DEBUG }
78  HOST_64, ///< Memory types: { HOST_64, HOST_DEBUG }
79  DEVICE, /**< Memory types: { DEVICE, DEVICE_DEBUG, DEVICE_UMPIRE,
80  DEVICE_UMPIRE_2, MANAGED } */
81  MANAGED ///< Memory types: { MANAGED }
82 };
83 
84 /// Return true if the given memory type is in MemoryClass::HOST.
85 inline bool IsHostMemory(MemoryType mt) { return mt <= MemoryType::MANAGED; }
86 
87 /// Return true if the given memory type is in MemoryClass::DEVICE
88 inline bool IsDeviceMemory(MemoryType mt)
89 {
90  return mt >= MemoryType::MANAGED && mt < MemoryType::SIZE;
91 }
92 
93 /// Return a suitable MemoryType for a given MemoryClass.
95 
96 /// Return true iff the MemoryType @a mt is contained in the MemoryClass @a mc.
98 
99 /// Return a suitable MemoryClass from a pair of MemoryClass%es.
100 /** Note: this operation is commutative, i.e. a*b = b*a, associative, i.e.
101  (a*b)*c = a*(b*c), and has an identity element: MemoryClass::HOST.
102 
103  Currently, the operation is defined as a*b := max(a,b) where the max
104  operation is based on the enumeration ordering:
105 
106  HOST < HOST_32 < HOST_64 < DEVICE < MANAGED. */
108 
109 /// Class used by MFEM to store pointers to host and/or device memory.
110 /** The template class parameter, T, must be a plain-old-data (POD) type.
111 
112  In many respects this class behaves like a pointer:
113  - When destroyed, a Memory object does NOT automatically delete any
114  allocated memory.
115  - Only the method Delete() will deallocate a Memory object.
116  - Other methods that modify the object (e.g. New(), Wrap(), etc) will
117  simply overwrite the old contents.
118  In other aspects this class differs from a pointer:
119  - Pointer arithmetic is not supported, MakeAlias() should be used instead.
120  - Const Memory object does not allow modification of the content
121  (unlike e.g. a const pointer).
122  - Move constructor and assignment will transfer ownership flags, and
123  Reset() the moved Memory object.
124  - Copy constructor and assignment copy flags. This may result in two Memory
125  objects owning the data which is an invalid state. This invalid state MUST
126  be resolved by users manually using SetHostPtrOwner(),
127  SetDevicePtrOwner(), or ClearOwnerFlags(). It is also possible to call
128  Delete() on only one of the two Memory objects, however this is
129  discouraged because it bypasses the internal ownership flags.
130  - When moving or copying (between host and device) alias Memory objects
131  and/or their base Memory objects, the consistency of memory flags have
132  to be manually taken care of using either Sync() or SyncAlias(). Failure
133  to do so will result in silent misuse of unsynchronized data.
134 
135  A Memory object stores up to two different pointers: one host pointer (with
136  MemoryType from MemoryClass::HOST) and one device pointer (currently one of
137  MemoryType: DEVICE, DEVICE_DEBUG, DEVICE_UMPIRE or MANAGED).
138 
139  A Memory object can hold (wrap) an externally allocated pointer with any
140  given MemoryType.
141 
142  Access to the content of the Memory object can be requested with any given
143  MemoryClass through the methods ReadWrite(), Read(), and Write().
144  Requesting such access may result in additional (internally handled)
145  memory allocation and/or memory copy.
146  - When ReadWrite() is called, the returned pointer becomes the only
147  valid pointer.
148  - When Read() is called, the returned pointer becomes valid, however
149  the other pointer (host or device) may remain valid as well.
150  - When Write() is called, the returned pointer becomes the only valid
151  pointer, however, unlike ReadWrite(), no memory copy will be performed.
152 
153  The host memory (pointer from MemoryClass::HOST) can be accessed through the
154  inline methods: `operator[]()`, `operator*()`, the implicit conversion
155  functions `operator T*()`, `operator const T*()`, and the explicit
156  conversion template functions `operator U*()`, `operator const U*()` (with
157  any suitable type U). In certain cases, using these methods may have
158  undefined behavior, e.g. if the host pointer is not currently valid. */
159 template <typename T>
160 class Memory
161 {
162 protected:
163  friend class MemoryManager;
164  friend void MemoryPrintFlags(unsigned flags);
165 
166  enum FlagMask: unsigned
167  {
168  REGISTERED = 1 << 0, /**< The host pointer is registered with the
169  MemoryManager */
170  OWNS_HOST = 1 << 1, ///< The host pointer will be deleted by Delete()
171  OWNS_DEVICE = 1 << 2, /**< The device pointer will be deleted by
172  Delete() */
173  OWNS_INTERNAL = 1 << 3, ///< Ownership flag for internal Memory data
174  VALID_HOST = 1 << 4, ///< Host pointer is valid
175  VALID_DEVICE = 1 << 5, ///< %Device pointer is valid
176  USE_DEVICE = 1 << 6, /**< Internal device flag, see e.g.
177  Vector::UseDevice() */
178  ALIAS = 1 << 7 ///< Pointer is an alias
179  };
180 
181  /// Pointer to host memory. Not owned.
182  /** The type of the pointer is given by the field #h_mt; it can be any type
183  from MemoryClass::HOST. */
184  T *h_ptr;
185  int capacity; ///< Size of the allocated memory
186  MemoryType h_mt; ///< Host memory type
187  mutable unsigned flags; ///< Bit flags defined from the #FlagMask enum
188  // 'flags' is mutable so that it can be modified in Set{Host,Device}PtrOwner,
189  // Copy{From,To}, {ReadWrite,Read,Write}.
190 
191 public:
192  /** Default constructor, sets the host pointer to nullptr and the metadata to
193  meaningful default values. */
194  Memory() { Reset(); }
195 
196  /// Copy constructor: default.
197  Memory(const Memory &orig) = default;
198 
199  /** Move constructor. Sets the pointers and associated ownership of validity
200  flags of @a *this to those of @a other. Resets @a other. */
201  Memory(Memory &&orig)
202  {
203  *this = orig;
204  orig.Reset();
205  }
206 
207  /// Copy-assignment operator: default.
208  Memory &operator=(const Memory &orig) = default;
209 
210  /** Move assignment operator. Sets the pointers and associated ownership of
211  validity flags of @a *this to those of @a other. Resets @a other. */
213  {
214  *this = orig;
215  orig.Reset();
216  return *this;
217  }
218 
219  /// Allocate host memory for @a size entries.
220  /** The allocation uses the current host memory type returned by
221  MemoryManager::GetHostMemoryType(). */
222  explicit Memory(int size) { New(size); }
223 
224  /** @brief Allocate memory for @a size entries with the given MemoryType
225  @a mt. */
226  /** The newly allocated memory is not initialized, however the given
227  MemoryType is still set as valid. */
228  Memory(int size, MemoryType mt) { New(size, mt); }
229 
230  /** @brief Allocate memory for @a size entries with the given host MemoryType
231  @a h_mt and device MemoryType @a d_mt. */
232  /** The newly allocated memory is not initialized. The host pointer is set as
233  valid. */
234  Memory(int size, MemoryType h_mt, MemoryType d_mt) { New(size, h_mt, d_mt); }
235 
236  /** @brief Wrap an externally allocated host pointer, @a ptr with the current
237  host memory type returned by MemoryManager::GetHostMemoryType(). */
238  /** The parameter @a own determines whether @a ptr will be deleted when the
239  method Delete() is called. */
240  explicit Memory(T *ptr, int size, bool own) { Wrap(ptr, size, own); }
241 
242  /// Wrap an externally allocated pointer, @a ptr, of the given MemoryType.
243  /** The new memory object will have the given MemoryType set as valid.
244 
245  The given @a ptr must be allocated appropriately for the given
246  MemoryType.
247 
248  The parameter @a own determines whether @a ptr will be deleted when the
249  method Delete() is called. */
250  Memory(T *ptr, int size, MemoryType mt, bool own)
251  { Wrap(ptr, size, mt, own); }
252 
253  /** @brief Alias constructor. Create a Memory object that points inside the
254  Memory object @a base. */
255  /** The new Memory object uses the same MemoryType(s) as @a base. */
256  Memory(const Memory &base, int offset, int size)
257  { MakeAlias(base, offset, size); }
258 
259  /// Destructor: default.
260  /** @note The destructor will NOT delete the current memory. */
261  ~Memory() = default;
262 
263  /** @brief Return true if the host pointer is owned. Ownership indicates
264  whether the pointer will be deleted by the method Delete(). */
265  bool OwnsHostPtr() const { return flags & OWNS_HOST; }
266 
267  /** @brief Set/clear the ownership flag for the host pointer. Ownership
268  indicates whether the pointer will be deleted by the method Delete(). */
269  void SetHostPtrOwner(bool own) const
270  { flags = own ? (flags | OWNS_HOST) : (flags & ~OWNS_HOST); }
271 
272  /** @brief Return true if the device pointer is owned. Ownership indicates
273  whether the pointer will be deleted by the method Delete(). */
274  bool OwnsDevicePtr() const { return flags & OWNS_DEVICE; }
275 
276  /** @brief Set/clear the ownership flag for the device pointer. Ownership
277  indicates whether the pointer will be deleted by the method Delete(). */
278  void SetDevicePtrOwner(bool own) const
279  { flags = own ? (flags | OWNS_DEVICE) : (flags & ~OWNS_DEVICE); }
280 
281  /** @brief Clear the ownership flags for the host and device pointers, as
282  well as any internal data allocated by the Memory object. */
283  void ClearOwnerFlags() const
285 
286  /// Read the internal device flag.
287  bool UseDevice() const { return flags & USE_DEVICE; }
288 
289  /// Set the internal device flag.
290  void UseDevice(bool use_dev) const
291  { flags = use_dev ? (flags | USE_DEVICE) : (flags & ~USE_DEVICE); }
292 
293  /// Return the size of the allocated memory.
294  int Capacity() const { return capacity; }
295 
296  /// Reset the memory to be empty, ensuring that Delete() will be a no-op.
297  /** This is the Memory class equivalent to setting a pointer to NULL, see
298  Empty().
299 
300  @note The current memory is NOT deleted by this method. */
301  void Reset();
302 
303  /// Reset the memory and set the host memory type.
304  void Reset(MemoryType host_mt);
305 
306  /// Return true if the Memory object is empty, see Reset().
307  /** Default-constructed objects are uninitialized, so they are not guaranteed
308  to be empty. */
309  bool Empty() const { return h_ptr == NULL; }
310 
311  /** @brief Allocate host memory for @a size entries with the current host
312  memory type returned by MemoryManager::GetHostMemoryType(). */
313  /** @note The current memory is NOT deleted by this method. */
314  inline void New(int size);
315 
316  /// Allocate memory for @a size entries with the given MemoryType.
317  /** The newly allocated memory is not initialized, however the given
318  MemoryType is still set as valid.
319 
320  When @a mt is a host type, the device MemoryType will be set later, if
321  requested, using the dual type of @a mt, see
322  MemoryManager::GetDualMemoryType().
323 
324  When @a mt is a device type, the host MemoryType will be set immediately
325  to be the dual of @a mt, see MemoryManager::GetDualMemoryType().
326 
327  @note The current memory is NOT deleted by this method. */
328  inline void New(int size, MemoryType mt);
329 
330  /** @brief Allocate memory for @a size entries with the given host MemoryType
331  @a h_mt and device MemoryType @a d_mt. */
332  /** The newly allocated memory is not initialized. The host pointer is set as
333  valid.
334 
335  @note The current memory is NOT deleted by this method. */
336  inline void New(int size, MemoryType h_mt, MemoryType d_mt);
337 
338  /** @brief Wrap an externally allocated host pointer, @a ptr with the current
339  host memory type returned by MemoryManager::GetHostMemoryType(). */
340  /** The parameter @a own determines whether @a ptr will be deleted when the
341  method Delete() is called.
342 
343  @note The current memory is NOT deleted by this method. */
344  inline void Wrap(T *ptr, int size, bool own);
345 
346  /// Wrap an externally allocated pointer, @a ptr, of the given MemoryType.
347  /** The new memory object will have the given MemoryType set as valid.
348 
349  The given @a ptr must be allocated appropriately for the given
350  MemoryType.
351 
352  The parameter @a own determines whether @a ptr will be deleted when the
353  method Delete() is called.
354 
355  @note The current memory is NOT deleted by this method. */
356  inline void Wrap(T *ptr, int size, MemoryType mt, bool own);
357 
358  /** Wrap an externally pair of allocated pointers, @a h_ptr and @a d_ptr,
359  of the given host MemoryType @a h_mt. */
360  /** The new memory object will have the device MemoryType set as valid.
361 
362  The given @a h_ptr and @a d_ptr must be allocated appropriately for the
363  given host MemoryType and its dual device MemoryType as defined by
364  MemoryManager::GetDualMemoryType().
365 
366  The parameter @a own determines whether both @a h_ptr and @a d_ptr will
367  be deleted when the method Delete() is called.
368 
369  @note Ownership can also be controlled by using the following methods:
370  - ClearOwnerFlags,
371  - SetHostPtrOwner,
372  - SetDevicePtrOwner.
373 
374  @note The current memory is NOT deleted by this method. */
375  inline void Wrap(T *h_ptr, T *d_ptr, int size, MemoryType h_mt, bool own);
376 
377  /// Create a memory object that points inside the memory object @a base.
378  /** The new Memory object uses the same MemoryType(s) as @a base.
379 
380  @note The current memory is NOT deleted by this method. */
381  inline void MakeAlias(const Memory &base, int offset, int size);
382 
383  /// Set the device MemoryType to be used by the Memory object.
384  /** If the specified @a d_mt is not a device MemoryType, i.e. not one of the
385  types in MemoryClass::DEVICE, then this method will return immediately.
386 
387  If the device MemoryType has been previously set to a different type and
388  the actual device memory has been allocated, this method will trigger an
389  error. This method will not perform the actual device memory allocation,
390  however, the allocation may already exist if the MemoryType is the same
391  as the current one.
392 
393  If the Memory is an alias Memory, the device MemoryType of its base will
394  be updated as described above. */
395  inline void SetDeviceMemoryType(MemoryType d_mt);
396 
397  /** @brief Delete the owned pointers and reset the Memory object. */
398  inline void Delete();
399 
400  /** @brief Delete the device pointer, if owned. If @a copy_to_host is true
401  and the data is valid only on device, move it to host before deleting.
402  Invalidates the device memory. */
403  inline void DeleteDevice(bool copy_to_host = true);
404 
405  /// Array subscript operator for host memory.
406  inline T &operator[](int idx);
407 
408  /// Array subscript operator for host memory, const version.
409  inline const T &operator[](int idx) const;
410 
411  /// Direct access to the host memory as T* (implicit conversion).
412  /** When the type T is const-qualified, this method can be used only if the
413  host pointer is currently valid (the device pointer may be valid or
414  invalid).
415 
416  When the type T is not const-qualified, this method can be used only if
417  the host pointer is the only valid pointer.
418 
419  When the Memory is empty, this method can be used and it returns NULL. */
420  inline operator T*();
421 
422  /// Direct access to the host memory as const T* (implicit conversion).
423  /** This method can be used only if the host pointer is currently valid (the
424  device pointer may be valid or invalid).
425 
426  When the Memory is empty, this method can be used and it returns NULL. */
427  inline operator const T*() const;
428 
429  /// Direct access to the host memory via explicit typecast.
430  /** A pointer to type T must be reinterpret_cast-able to a pointer to type U.
431  In particular, this method cannot be used to cast away const-ness from
432  the base type T.
433 
434  When the type U is const-qualified, this method can be used only if the
435  host pointer is currently valid (the device pointer may be valid or
436  invalid).
437 
438  When the type U is not const-qualified, this method can be used only if
439  the host pointer is the only valid pointer.
440 
441  When the Memory is empty, this method can be used and it returns NULL. */
442  template <typename U>
443  inline explicit operator U*();
444 
445  /// Direct access to the host memory via explicit typecast, const version.
446  /** A pointer to type T must be reinterpret_cast-able to a pointer to type
447  const U.
448 
449  This method can be used only if the host pointer is currently valid (the
450  device pointer may be valid or invalid).
451 
452  When the Memory is empty, this method can be used and it returns NULL. */
453  template <typename U>
454  inline explicit operator const U*() const;
455 
456  /// Get read-write access to the memory with the given MemoryClass.
457  /** If only read or only write access is needed, then the methods
458  Read() or Write() should be used instead of this method.
459 
460  The parameter @a size must not exceed the Capacity(). */
461  inline T *ReadWrite(MemoryClass mc, int size);
462 
463  /// Get read-only access to the memory with the given MemoryClass.
464  /** The parameter @a size must not exceed the Capacity(). */
465  inline const T *Read(MemoryClass mc, int size) const;
466 
467  /// Get write-only access to the memory with the given MemoryClass.
468  /** The parameter @a size must not exceed the Capacity().
469 
470  The contents of the returned pointer is undefined, unless it was
471  validated by a previous call to Read() or ReadWrite() with
472  the same MemoryClass. */
473  inline T *Write(MemoryClass mc, int size);
474 
475  /// Copy the host/device pointer validity flags from @a other to @a *this.
476  /** This method synchronizes the pointer validity flags of two Memory objects
477  that use the same host/device pointers, or when @a *this is an alias
478  (sub-Memory) of @a other. Typically, this method should be called after
479  @a other is manipulated in a way that changes its pointer validity flags
480  (e.g. it was moved from device to host memory). */
481  inline void Sync(const Memory &other) const;
482 
483  /** @brief Update the alias Memory @a *this to match the memory location (all
484  valid locations) of its base Memory, @a base. */
485  /** This method is useful when alias Memory is moved and manipulated in a
486  different memory space. Such operations render the pointer validity flags
487  of the base incorrect. Calling this method will ensure that @a base is
488  up-to-date. Note that this is achieved by moving/copying @a *this (if
489  necessary), and not @a base. */
490  inline void SyncAlias(const Memory &base, int alias_size) const;
491 
492  /** @brief Return a MemoryType that is currently valid. If both the host and
493  the device pointers are currently valid, then the device memory type is
494  returned. */
495  inline MemoryType GetMemoryType() const;
496 
497  /// Return the host MemoryType of the Memory object.
498  inline MemoryType GetHostMemoryType() const { return h_mt; }
499 
500  /** @brief Return the device MemoryType of the Memory object. If the device
501  MemoryType is not set, return MemoryType::DEFAULT. */
502  inline MemoryType GetDeviceMemoryType() const;
503 
504  /** @brief Return true if host pointer is valid */
505  inline bool HostIsValid() const;
506 
507  /** @brief Return true if device pointer is valid */
508  inline bool DeviceIsValid() const;
509 
510  /// Copy @a size entries from @a src to @a *this.
511  /** The given @a size should not exceed the Capacity() of the source @a src
512  and the destination, @a *this. */
513  inline void CopyFrom(const Memory &src, int size);
514 
515  /// Copy @a size entries from the host pointer @a src to @a *this.
516  /** The given @a size should not exceed the Capacity() of @a *this. */
517  inline void CopyFromHost(const T *src, int size);
518 
519  /// Copy @a size entries from @a *this to @a dest.
520  /** The given @a size should not exceed the Capacity() of @a *this and the
521  destination, @a dest. */
522  inline void CopyTo(Memory &dest, int size) const;
523 
524  /// Copy @a size entries from @a *this to the host pointer @a dest.
525  /** The given @a size should not exceed the Capacity() of @a *this. */
526  inline void CopyToHost(T *dest, int size) const;
527 
528  /// Print the internal flags.
529  /** This method can be useful for debugging. It is explicitly instantiated
530  for Memory<T> with T = int and T = double. */
531  inline void PrintFlags() const;
532 
533  /// If both the host and the device data are valid, compare their contents.
534  /** This method can be useful for debugging. It is explicitly instantiated
535  for Memory<T> with T = int and T = double. */
536  inline int CompareHostAndDevice(int size) const;
537 
538 private:
539  // GCC 4.8 workaround: max_align_t is not in std.
540  static constexpr std::size_t def_align_bytes_()
541  {
542  using namespace std;
543  return alignof(max_align_t);
544  }
545  static constexpr std::size_t def_align_bytes = def_align_bytes_();
546  static constexpr std::size_t new_align_bytes =
547  alignof(T) > def_align_bytes ? alignof(T) : def_align_bytes;
548 
549  template <std::size_t align_bytes, bool dummy = true> struct Alloc
550  {
551 #if __cplusplus < 201703L
552  static inline T *New(std::size_t)
553  {
554  // Generate an error in debug mode
555  MFEM_ASSERT(false, "overaligned type cannot use MemoryType::HOST");
556  return nullptr;
557  }
558 #else
559  static inline T *New(std::size_t size) { return new T[size]; }
560 #endif
561  };
562 
563 #if __cplusplus < 201703L
564  template<bool dummy> struct Alloc<def_align_bytes,dummy>
565  {
566  static inline T *New(std::size_t size) { return new T[size]; }
567  };
568 #endif
569 
570  // Shortcut for Alloc<new_align_bytes>::New(size)
571  static inline T *NewHOST(std::size_t size)
572  {
573  return Alloc<new_align_bytes>::New(size);
574  }
575 };
576 
577 
578 /** The MFEM memory manager class. Host-side pointers are inserted into this
579  manager which keeps track of the associated device pointer, and where the
580  data currently resides. */
582 {
583 private:
584 
585  typedef MemoryType MemType;
586  typedef Memory<int> Mem;
587 
588  template <typename T> friend class Memory;
589 
590  /// Host memory type set during the Setup.
591  static MemoryType host_mem_type;
592 
593  /// Device memory type set during the Setup.
594  static MemoryType device_mem_type;
595 
596  /// Allow to detect if a global memory manager instance exists.
597  static bool exists;
598 
599  /// Return true if the global memory manager instance exists.
600  static bool Exists() { return exists; }
601 
602  /// Array defining the dual MemoryType for each MemoryType
603  /** The dual of a host MemoryType is a device MemoryType and vice versa: the
604  dual of a device MemoryType is a host MemoryType. */
605  static MemoryType dual_map[MemoryTypeSize];
606 
607  /// Update the dual memory type of @a mt to be @a dual_mt.
608  static void UpdateDualMemoryType(MemoryType mt, MemoryType dual_mt);
609 
610  /// True if Configure() was called.
611  static bool configured;
612 
613  /// Host and device allocator names for Umpire.
614 #ifdef MFEM_USE_UMPIRE
615  static const char * h_umpire_name;
616  static const char * d_umpire_name;
617  static const char * d_umpire_2_name;
618 #endif
619 
620 private: // Static methods used by the Memory<T> class
621 
622  /// Allocate and register a new pointer. Return the host pointer.
623  /// h_tmp must be already allocated using new T[] if mt is a pure device
624  /// memory type, e.g. CUDA (mt will not be HOST).
625  static void *New_(void *h_tmp, size_t bytes, MemoryType mt, unsigned &flags);
626 
627  static void *New_(void *h_tmp, size_t bytes, MemoryType h_mt,
628  MemoryType d_mt, unsigned valid_flags, unsigned &flags);
629 
630  /// Register an external pointer of the given MemoryType.
631  /// Return the host pointer.
632  static void *Register_(void *ptr, void *h_ptr, size_t bytes, MemoryType mt,
633  bool own, bool alias, unsigned &flags);
634 
635  /// Register a pair of external host and device pointers
636  static void Register2_(void *h_ptr, void *d_ptr, size_t bytes,
637  MemoryType h_mt, MemoryType d_mt,
638  bool own, bool alias, unsigned &flags);
639 
640  /// Register an alias. Note: base_h_ptr may be an alias.
641  static void Alias_(void *base_h_ptr, size_t offset, size_t bytes,
642  unsigned base_flags, unsigned &flags);
643 
644  static void SetDeviceMemoryType_(void *h_ptr, unsigned flags,
645  MemoryType d_mt);
646 
647  /// Un-register and free memory identified by its host pointer. Returns the
648  /// memory type of the host pointer.
649  static MemoryType Delete_(void *h_ptr, MemoryType mt, unsigned flags);
650 
651  /// Free device memory identified by its host pointer
652  static void DeleteDevice_(void *h_ptr, unsigned & flags);
653 
654  /// Check if the memory types given the memory class are valid
655  static bool MemoryClassCheck_(MemoryClass mc, void *h_ptr,
656  MemoryType h_mt, size_t bytes, unsigned flags);
657 
658  /// Return a pointer to the memory identified by the host pointer h_ptr for
659  /// access with the given MemoryClass.
660  static void *ReadWrite_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
661  size_t bytes, unsigned &flags);
662 
663  static const void *Read_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
664  size_t bytes, unsigned &flags);
665 
666  static void *Write_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
667  size_t bytes, unsigned &flags);
668 
669  static void SyncAlias_(const void *base_h_ptr, void *alias_h_ptr,
670  size_t alias_bytes, unsigned base_flags,
671  unsigned &alias_flags);
672 
673  /// Return the type the of the currently valid memory.
674  /// If more than one types are valid, return a device type.
675  static MemoryType GetDeviceMemoryType_(void *h_ptr, bool alias);
676 
677  /// Return the type the of the host memory.
678  static MemoryType GetHostMemoryType_(void *h_ptr);
679 
680  /// Verify that h_mt and h_ptr's h_mt (memory or alias) are equal.
681  static void CheckHostMemoryType_(MemoryType h_mt, void *h_ptr, bool alias);
682 
683  /// Copy entries from valid memory type to valid memory type.
684  /// Both dest_h_ptr and src_h_ptr are registered host pointers.
685  static void Copy_(void *dest_h_ptr, const void *src_h_ptr, size_t bytes,
686  unsigned src_flags, unsigned &dest_flags);
687 
688  /// Copy entries from valid memory type to host memory, where dest_h_ptr is
689  /// not a registered host pointer and src_h_ptr is a registered host pointer.
690  static void CopyToHost_(void *dest_h_ptr, const void *src_h_ptr,
691  size_t bytes, unsigned src_flags);
692 
693  /// Copy entries from host memory to valid memory type, where dest_h_ptr is a
694  /// registered host pointer and src_h_ptr is not a registered host pointer.
695  static void CopyFromHost_(void *dest_h_ptr, const void *src_h_ptr,
696  size_t bytes, unsigned &dest_flags);
697 
698  /// Check if the host pointer has been registered in the memory manager.
699  static bool IsKnown_(const void *h_ptr);
700 
701  /** @brief Check if the host pointer has been registered as an alias in the
702  memory manager. */
703  static bool IsAlias_(const void *h_ptr);
704 
705  /// Compare the contents of the host and the device memory.
706  static int CompareHostAndDevice_(void *h_ptr, size_t size, unsigned flags);
707 
708 private:
709 
710  /// Insert a host address @a h_ptr and size *a bytes in the memory map to be
711  /// managed.
712  void Insert(void *h_ptr, size_t bytes, MemoryType h_mt, MemoryType d_mt);
713 
714  /// Insert a device and the host addresses in the memory map
715  void InsertDevice(void *d_ptr, void *h_ptr, size_t bytes,
716  MemoryType h_mt, MemoryType d_mt);
717 
718  /// Insert an alias in the alias map
719  void InsertAlias(const void *base_ptr, void *alias_ptr,
720  const size_t bytes, const bool base_is_alias);
721 
722  /// Erase an address from the memory map, as well as all its aliases
723  void Erase(void *h_ptr, bool free_dev_ptr = true);
724 
725  /// Erase device memory for a given host address
726  void EraseDevice(void *h_ptr);
727 
728  /// Erase an alias from the aliases map
729  void EraseAlias(void *alias_ptr);
730 
731  /// Return the corresponding device pointer of h_ptr,
732  /// allocating and moving the data if needed
733  void *GetDevicePtr(const void *h_ptr, size_t bytes, bool copy_data);
734 
735  /// Return the corresponding device pointer of alias_ptr,
736  /// allocating and moving the data if needed
737  void *GetAliasDevicePtr(const void *alias_ptr, size_t bytes, bool copy_data);
738 
739  /// Return the corresponding host pointer of d_ptr,
740  /// allocating and moving the data if needed
741  void *GetHostPtr(const void *d_ptr, size_t bytes, bool copy_data);
742 
743  /// Return the corresponding host pointer of alias_ptr,
744  /// allocating and moving the data if needed
745  void *GetAliasHostPtr(const void *alias_ptr, size_t bytes, bool copy_data);
746 
747 public:
748  MemoryManager();
749  ~MemoryManager();
750 
751  /// Initialize the memory manager.
752  void Init();
753 
754  /// Return the dual MemoryType of the given one, @a mt.
755  /** The default dual memory types are:
756 
757  memory type | dual type
758  --------------- | ---------
759  HOST | DEVICE
760  HOST_32 | DEVICE
761  HOST_64 | DEVICE
762  HOST_DEBUG | DEVICE_DEBUG
763  HOST_UMPIRE | DEVICE_UMPIRE
764  HOST_PINNED | DEVICE
765  MANAGED | MANAGED
766  DEVICE | HOST
767  DEVICE_DEBUG | HOST_DEBUG
768  DEVICE_UMPIRE | HOST_UMPIRE
769  DEVICE_UMPIRE_2 | HOST_UMPIRE
770 
771  The dual types can be modified before device configuration using the
772  method SetDualMemoryType() or by calling Device::SetMemoryTypes(). */
774  { return dual_map[(int)mt]; }
775 
776  /// Set the dual memory type of @a mt to be @a dual_mt.
777  /** This method can only be called before configuration, i.e. before calling
778  Configure(), which is typically done during Device construction.
779 
780  One of the types must be a host MemoryType and the other must be a device
781  MemoryType or both types must be the same host memory type. The latter
782  case is only allowed for convenience in setting up pure host execution,
783  so the actual dual is not updated. */
784  static void SetDualMemoryType(MemoryType mt, MemoryType dual_mt);
785 
786  /** @brief Configure the Memory manager with given default host and device
787  types. This method will be called when configuring a device.
788 
789  The host and device MemoryType%s, @a h_mt and @a d_mt, are set to be dual
790  to each other. */
791  void Configure(const MemoryType h_mt, const MemoryType d_mt);
792 
793 #ifdef MFEM_USE_UMPIRE
794  /// Set the host Umpire allocator name used with MemoryType::HOST_UMPIRE
795  static void SetUmpireHostAllocatorName(const char * h_name) { h_umpire_name = h_name; }
796  /// Set the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE
797  static void SetUmpireDeviceAllocatorName(const char * d_name) { d_umpire_name = d_name; }
798  /// Set the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2
799  static void SetUmpireDevice2AllocatorName(const char * d_name) { d_umpire_2_name = d_name; }
800 
801  /// Get the host Umpire allocator name used with MemoryType::HOST_UMPIRE
802  static const char * GetUmpireHostAllocatorName() { return h_umpire_name; }
803  /// Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE
804  static const char * GetUmpireDeviceAllocatorName() { return d_umpire_name; }
805  /// Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2
806  static const char * GetUmpireDevice2AllocatorName() { return d_umpire_2_name; }
807 #endif
808 
809  /// Free all the device memories
810  void Destroy();
811 
812  /// Return true if the pointer is known by the memory manager
813  bool IsKnown(const void *h_ptr) { return IsKnown_(h_ptr); }
814 
815  /// Return true if the pointer is known by the memory manager as an alias
816  bool IsAlias(const void *h_ptr) { return IsAlias_(h_ptr); }
817 
818  /// Check if the host pointer has been registered in the memory manager
819  void RegisterCheck(void *h_ptr);
820 
821  /// Prints all pointers known by the memory manager,
822  /// returning the number of printed pointers
823  int PrintPtrs(std::ostream &out = mfem::out);
824 
825  /// Prints all aliases known by the memory manager
826  /// returning the number of printed pointers
827  int PrintAliases(std::ostream &out = mfem::out);
828 
829  static MemoryType GetHostMemoryType() { return host_mem_type; }
830  static MemoryType GetDeviceMemoryType() { return device_mem_type; }
831 };
832 
833 
834 // Inline methods
835 
836 template <typename T>
837 inline void Memory<T>::Reset()
838 {
839  h_ptr = NULL;
841  capacity = 0;
842  flags = 0;
843 }
844 
845 template <typename T>
846 inline void Memory<T>::Reset(MemoryType host_mt)
847 {
848  h_ptr = NULL;
849  h_mt = host_mt;
850  capacity = 0;
851  flags = 0;
852 }
853 
854 template <typename T>
855 inline void Memory<T>::New(int size)
856 {
857  capacity = size;
860  h_ptr = (h_mt == MemoryType::HOST) ? NewHOST(size) :
861  (T*)MemoryManager::New_(nullptr, size*sizeof(T), h_mt, flags);
862 }
863 
864 template <typename T>
865 inline void Memory<T>::New(int size, MemoryType mt)
866 {
867  capacity = size;
868  const size_t bytes = size*sizeof(T);
869  const bool mt_host = mt == MemoryType::HOST;
870  if (mt_host) { flags = OWNS_HOST | VALID_HOST; }
872  T *h_tmp = (h_mt == MemoryType::HOST) ? NewHOST(size) : nullptr;
873  h_ptr = (mt_host) ? h_tmp : (T*)MemoryManager::New_(h_tmp, bytes, mt, flags);
874 }
875 
876 template <typename T>
877 inline void Memory<T>::New(int size, MemoryType host_mt, MemoryType device_mt)
878 {
879  capacity = size;
880  const size_t bytes = size*sizeof(T);
881  this->h_mt = host_mt;
882  T *h_tmp = (host_mt == MemoryType::HOST) ? NewHOST(size) : nullptr;
883  h_ptr = (T*)MemoryManager::New_(h_tmp, bytes, host_mt, device_mt,
884  VALID_HOST, flags);
885 }
886 
887 template <typename T>
888 inline void Memory<T>::Wrap(T *ptr, int size, bool own)
889 {
890  h_ptr = ptr;
891  capacity = size;
892  flags = (own ? OWNS_HOST : 0) | VALID_HOST;
894 #ifdef MFEM_DEBUG
895  if (own && MemoryManager::Exists())
896  {
897  MemoryType h_ptr_mt = MemoryManager::GetHostMemoryType_(h_ptr);
898  MFEM_VERIFY(h_mt == h_ptr_mt,
899  "h_mt = " << (int)h_mt << ", h_ptr_mt = " << (int)h_ptr_mt);
900  }
901 #endif
902  if (own && h_mt != MemoryType::HOST)
903  {
904  const size_t bytes = size*sizeof(T);
905  MemoryManager::Register_(ptr, ptr, bytes, h_mt, own, false, flags);
906  }
907 }
908 
909 template <typename T>
910 inline void Memory<T>::Wrap(T *ptr, int size, MemoryType mt, bool own)
911 {
912  capacity = size;
913  if (IsHostMemory(mt))
914  {
915  h_mt = mt;
916  h_ptr = ptr;
917  if (mt == MemoryType::HOST || !own)
918  {
919  // Skip registration
920  flags = (own ? OWNS_HOST : 0) | VALID_HOST;
921  return;
922  }
923  }
924  else
925  {
927  h_ptr = (h_mt == MemoryType::HOST) ? NewHOST(size) : nullptr;
928  }
929  flags = 0;
930  h_ptr = (T*)MemoryManager::Register_(ptr, h_ptr, size*sizeof(T), mt,
931  own, false, flags);
932 }
933 
934 template <typename T>
935 inline void Memory<T>::Wrap(T *ptr, T *d_ptr, int size, MemoryType mt, bool own)
936 {
937  h_mt = mt;
938  flags = 0;
939  h_ptr = ptr;
940  capacity = size;
941  MFEM_ASSERT(IsHostMemory(h_mt),"");
942  const size_t bytes = size*sizeof(T);
944  MemoryManager::Register2_(h_ptr, d_ptr, bytes, h_mt, d_mt,
945  own, false, flags);
946 }
947 
948 template <typename T>
949 inline void Memory<T>::MakeAlias(const Memory &base, int offset, int size)
950 {
951  MFEM_ASSERT(0 <= offset, "invalid offset = " << offset);
952  MFEM_ASSERT(0 <= size, "invalid size = " << size);
953  MFEM_ASSERT(offset + size <= base.capacity,
954  "invalid offset + size = " << offset + size
955  << " > base capacity = " << base.capacity);
956  capacity = size;
957  h_mt = base.h_mt;
958  h_ptr = base.h_ptr + offset;
959  if (!(base.flags & REGISTERED))
960  {
961  if (
962 #if !defined(HYPRE_USING_GPU)
963  // If the following condition is true then MemoryManager::Exists()
964  // should also be true:
966 #else
967  // When HYPRE_USING_GPU is defined we always register the 'base' if
968  // the MemoryManager::Exists():
969  MemoryManager::Exists()
970 #endif
971  )
972  {
973  // Register 'base':
974  MemoryManager::Register_(base.h_ptr, nullptr, base.capacity*sizeof(T),
975  base.h_mt, base.flags & OWNS_HOST,
976  base.flags & ALIAS, base.flags);
977  }
978  else
979  {
980  // Copy the flags from 'base', setting the ALIAS flag to true, and
981  // setting both OWNS_HOST and OWNS_DEVICE to false:
982  flags = (base.flags | ALIAS) & ~(OWNS_HOST | OWNS_DEVICE);
983  return;
984  }
985  }
986  const size_t s_bytes = size*sizeof(T);
987  const size_t o_bytes = offset*sizeof(T);
988  MemoryManager::Alias_(base.h_ptr, o_bytes, s_bytes, base.flags, flags);
989 }
990 
991 template <typename T>
993 {
994  if (!IsDeviceMemory(d_mt)) { return; }
995  if (!(flags & REGISTERED))
996  {
997  MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
999  }
1000  MemoryManager::SetDeviceMemoryType_(h_ptr, flags, d_mt);
1001 }
1002 
1003 template <typename T>
1004 inline void Memory<T>::Delete()
1005 {
1006  const bool registered = flags & REGISTERED;
1007  const bool mt_host = h_mt == MemoryType::HOST;
1008  const bool std_delete = !registered && mt_host;
1009 
1010  if (std_delete ||
1011  MemoryManager::Delete_((void*)h_ptr, h_mt, flags) == MemoryType::HOST)
1012  {
1013  if (flags & OWNS_HOST) { delete [] h_ptr; }
1014  }
1015  Reset(h_mt);
1016 }
1017 
1018 template <typename T>
1019 inline void Memory<T>::DeleteDevice(bool copy_to_host)
1020 {
1021  if (flags & REGISTERED)
1022  {
1023  if (copy_to_host) { Read(MemoryClass::HOST, capacity); }
1024  MemoryManager::DeleteDevice_((void*)h_ptr, flags);
1025  }
1026 }
1027 
1028 template <typename T>
1029 inline T &Memory<T>::operator[](int idx)
1030 {
1031  MFEM_ASSERT((flags & VALID_HOST) && !(flags & VALID_DEVICE),
1032  "invalid host pointer access");
1033  return h_ptr[idx];
1034 }
1035 
1036 template <typename T>
1037 inline const T &Memory<T>::operator[](int idx) const
1038 {
1039  MFEM_ASSERT((flags & VALID_HOST), "invalid host pointer access");
1040  return h_ptr[idx];
1041 }
1042 
1043 template <typename T>
1045 {
1046  MFEM_ASSERT(Empty() ||
1047  ((flags & VALID_HOST) &&
1048  (std::is_const<T>::value || !(flags & VALID_DEVICE))),
1049  "invalid host pointer access");
1050  return h_ptr;
1051 }
1052 
1053 template <typename T>
1054 inline Memory<T>::operator const T*() const
1055 {
1056  MFEM_ASSERT(Empty() || (flags & VALID_HOST), "invalid host pointer access");
1057  return h_ptr;
1058 }
1059 
1060 template <typename T> template <typename U>
1062 {
1063  MFEM_ASSERT(Empty() ||
1064  ((flags & VALID_HOST) &&
1065  (std::is_const<U>::value || !(flags & VALID_DEVICE))),
1066  "invalid host pointer access");
1067  return reinterpret_cast<U*>(h_ptr);
1068 }
1069 
1070 template <typename T> template <typename U>
1071 inline Memory<T>::operator const U*() const
1072 {
1073  MFEM_ASSERT(Empty() || (flags & VALID_HOST), "invalid host pointer access");
1074  return reinterpret_cast<U*>(h_ptr);
1075 }
1076 
1077 template <typename T>
1078 inline T *Memory<T>::ReadWrite(MemoryClass mc, int size)
1079 {
1080  const size_t bytes = size * sizeof(T);
1081  if (!(flags & REGISTERED))
1082  {
1083  if (mc == MemoryClass::HOST) { return h_ptr; }
1084  MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
1085  flags & OWNS_HOST, flags & ALIAS, flags);
1086  }
1087  return (T*)MemoryManager::ReadWrite_(h_ptr, h_mt, mc, bytes, flags);
1088 }
1089 
1090 template <typename T>
1091 inline const T *Memory<T>::Read(MemoryClass mc, int size) const
1092 {
1093  const size_t bytes = size * sizeof(T);
1094  if (!(flags & REGISTERED))
1095  {
1096  if (mc == MemoryClass::HOST) { return h_ptr; }
1097  MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
1098  flags & OWNS_HOST, flags & ALIAS, flags);
1099  }
1100  return (const T*)MemoryManager::Read_(h_ptr, h_mt, mc, bytes, flags);
1101 }
1102 
1103 template <typename T>
1104 inline T *Memory<T>::Write(MemoryClass mc, int size)
1105 {
1106  const size_t bytes = size * sizeof(T);
1107  if (!(flags & REGISTERED))
1108  {
1109  if (mc == MemoryClass::HOST) { return h_ptr; }
1110  MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
1111  flags & OWNS_HOST, flags & ALIAS, flags);
1112  }
1113  return (T*)MemoryManager::Write_(h_ptr, h_mt, mc, bytes, flags);
1114 }
1115 
1116 template <typename T>
1117 inline void Memory<T>::Sync(const Memory &other) const
1118 {
1119  if (!(flags & REGISTERED) && (other.flags & REGISTERED))
1120  {
1121  MFEM_ASSERT(h_ptr == other.h_ptr &&
1122  (flags & ALIAS) == (other.flags & ALIAS),
1123  "invalid input");
1125  }
1126  flags = (flags & ~(VALID_HOST | VALID_DEVICE)) |
1127  (other.flags & (VALID_HOST | VALID_DEVICE));
1128 }
1129 
1130 template <typename T>
1131 inline void Memory<T>::SyncAlias(const Memory &base, int alias_size) const
1132 {
1133  // Assuming that if *this is registered then base is also registered.
1134  MFEM_ASSERT(!(flags & REGISTERED) || (base.flags & REGISTERED),
1135  "invalid base state");
1136  if (!(base.flags & REGISTERED)) { return; }
1137  MemoryManager::SyncAlias_(base.h_ptr, h_ptr, alias_size*sizeof(T),
1138  base.flags, flags);
1139 }
1140 
1141 template <typename T>
1143 {
1144  if (h_ptr == nullptr || !(flags & VALID_DEVICE)) { return h_mt; }
1145  return MemoryManager::GetDeviceMemoryType_(h_ptr, flags & ALIAS);
1146 }
1147 
1148 template <typename T>
1150 {
1151  if (!(flags & REGISTERED)) { return MemoryType::DEFAULT; }
1152  return MemoryManager::GetDeviceMemoryType_(h_ptr, flags & ALIAS);
1153 }
1154 
1155 template <typename T>
1156 inline bool Memory<T>::HostIsValid() const
1157 {
1158  return flags & VALID_HOST ? true : false;
1159 }
1160 
1161 template <typename T>
1162 inline bool Memory<T>::DeviceIsValid() const
1163 {
1164  return flags & VALID_DEVICE ? true : false;
1165 }
1166 
1167 template <typename T>
1168 inline void Memory<T>::CopyFrom(const Memory &src, int size)
1169 {
1170  MFEM_VERIFY(src.capacity>=size && capacity>=size, "Incorrect size");
1171  if (!(flags & REGISTERED) && !(src.flags & REGISTERED))
1172  {
1173  if (h_ptr != src.h_ptr && size != 0)
1174  {
1175  MFEM_ASSERT(h_ptr + size <= src.h_ptr || src.h_ptr + size <= h_ptr,
1176  "data overlaps!");
1177  std::memcpy(h_ptr, src, size*sizeof(T));
1178  }
1179  // *this is not registered, so (flags & VALID_HOST) must be true
1180  }
1181  else
1182  {
1183  MemoryManager::Copy_(h_ptr, src.h_ptr, size*sizeof(T), src.flags, flags);
1184  }
1185 }
1186 
1187 template <typename T>
1188 inline void Memory<T>::CopyFromHost(const T *src, int size)
1189 {
1190  MFEM_VERIFY(capacity>=size, "Incorrect size");
1191  if (!(flags & REGISTERED))
1192  {
1193  if (h_ptr != src && size != 0)
1194  {
1195  MFEM_ASSERT(h_ptr + size <= src || src + size <= h_ptr,
1196  "data overlaps!");
1197  std::memcpy(h_ptr, src, size*sizeof(T));
1198  }
1199  // *this is not registered, so (flags & VALID_HOST) must be true
1200  }
1201  else
1202  {
1203  MemoryManager::CopyFromHost_(h_ptr, src, size*sizeof(T), flags);
1204  }
1205 }
1206 
1207 template <typename T>
1208 inline void Memory<T>::CopyTo(Memory &dest, int size) const
1209 {
1210  MFEM_VERIFY(capacity>=size, "Incorrect size");
1211  dest.CopyFrom(*this, size);
1212 }
1213 
1214 template <typename T>
1215 inline void Memory<T>::CopyToHost(T *dest, int size) const
1216 {
1217  MFEM_VERIFY(capacity>=size, "Incorrect size");
1218  if (!(flags & REGISTERED))
1219  {
1220  if (h_ptr != dest && size != 0)
1221  {
1222  MFEM_ASSERT(h_ptr + size <= dest || dest + size <= h_ptr,
1223  "data overlaps!");
1224  std::memcpy(dest, h_ptr, size*sizeof(T));
1225  }
1226  }
1227  else
1228  {
1229  MemoryManager::CopyToHost_(dest, h_ptr, size*sizeof(T), flags);
1230  }
1231 }
1232 
1233 
1234 /** @brief Print the state of a Memory object based on its internal flags.
1235  Useful in a debugger. See also Memory<T>::PrintFlags(). */
1236 extern void MemoryPrintFlags(unsigned flags);
1237 
1238 
1239 template <typename T>
1240 inline void Memory<T>::PrintFlags() const
1241 {
1243 }
1244 
1245 template <typename T>
1246 inline int Memory<T>::CompareHostAndDevice(int size) const
1247 {
1248  if (!(flags & VALID_HOST) || !(flags & VALID_DEVICE)) { return 0; }
1249  return MemoryManager::CompareHostAndDevice_(h_ptr, size*sizeof(T), flags);
1250 }
1251 
1252 
1253 /// The (single) global memory manager object
1254 extern MemoryManager mm;
1255 
1256 } // namespace mfem
1257 
1258 #endif // MFEM_MEM_MANAGER_HPP
MemoryType h_mt
Host memory type.
Memory(Memory &&orig)
bool HostIsValid() const
Return true if host pointer is valid.
Host memory; aligned at 64 bytes.
bool IsHostMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::HOST.
Definition: mem_manager.hpp:85
~Memory()=default
Destructor: default.
friend void MemoryPrintFlags(unsigned flags)
Print the state of a Memory object based on its internal flags. Useful in a debugger. See also Memory&lt;T&gt;::PrintFlags().
Device memory; using CUDA or HIP *Malloc and *Free.
void PrintFlags() const
Print the internal flags.
static const char * GetUmpireHostAllocatorName()
Get the host Umpire allocator name used with MemoryType::HOST_UMPIRE.
const char * MemoryTypeName[MemoryTypeSize]
Memory type names, used during Device:: configuration.
void Delete()
Delete the owned pointers and reset the Memory object.
Memory(T *ptr, int size, MemoryType mt, bool own)
Wrap an externally allocated pointer, ptr, of the given MemoryType.
static MemoryType GetHostMemoryType()
void SyncAlias(const Memory &base, int alias_size) const
Update the alias Memory *this to match the memory location (all valid locations) of its base Memory...
Host pointer is valid.
void SetDevicePtrOwner(bool own) const
Set/clear the ownership flag for the device pointer. Ownership indicates whether the pointer will be ...
Host memory; allocated from a &quot;host-debug&quot; pool.
T * Write(MemoryClass mc, int size)
Get write-only access to the memory with the given MemoryClass.
Memory(int size)
Allocate host memory for size entries.
void UseDevice(bool use_dev) const
Set the internal device flag.
Host memory: pinned (page-locked)
void CopyFrom(const Memory &src, int size)
Copy size entries from src to *this.
Memory & operator=(Memory &&orig)
Number of host and device memory types.
int Capacity() const
Return the size of the allocated memory.
int CompareHostAndDevice(int size) const
If both the host and the device data are valid, compare their contents.
Memory(int size, MemoryType mt)
Allocate memory for size entries with the given MemoryType mt.
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
unsigned flags
Bit flags defined from the FlagMask enum.
bool IsAlias(const void *h_ptr)
Return true if the pointer is known by the memory manager as an alias.
class if defined(__alignas_is_defined) alignas(double) RowNode
Definition: sparsemat.hpp:38
bool MemoryClassContainsType(MemoryClass mc, MemoryType mt)
Return true iff the MemoryType mt is contained in the MemoryClass mc.
Definition: mem_manager.cpp:70
Host memory; aligned at 32 bytes.
void Wrap(T *ptr, int size, bool own)
Wrap an externally allocated host pointer, ptr with the current host memory type returned by MemoryMa...
static MemoryType GetDualMemoryType(MemoryType mt)
Return the dual MemoryType of the given one, mt.
void CopyFromHost(const T *src, int size)
Copy size entries from the host pointer src to *this.
void CopyTo(Memory &dest, int size) const
Copy size entries from *this to dest.
constexpr int DeviceMemoryType
Definition: mem_manager.hpp:63
static const char * GetUmpireDeviceAllocatorName()
Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE.
constexpr int HostMemoryType
Definition: mem_manager.hpp:61
static MemoryType GetDeviceMemoryType()
bool DeviceIsValid() const
Return true if device pointer is valid.
Memory(const Memory &base, int offset, int size)
Alias constructor. Create a Memory object that points inside the Memory object base.
Ownership flag for internal Memory data.
Device pointer is valid
The host pointer will be deleted by Delete()
bool OwnsHostPtr() const
Return true if the host pointer is owned. Ownership indicates whether the pointer will be deleted by ...
constexpr int MemoryTypeSize
Static casts to &#39;int&#39; and sizes of some useful memory types.
Definition: mem_manager.hpp:60
Memory & operator=(const Memory &orig)=default
Copy-assignment operator: default.
void Reset()
Reset the memory to be empty, ensuring that Delete() will be a no-op.
static const char * GetUmpireDevice2AllocatorName()
Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2.
void ClearOwnerFlags() const
Clear the ownership flags for the host and device pointers, as well as any internal data allocated by...
MemoryType GetDeviceMemoryType() const
Return the device MemoryType of the Memory object. If the device MemoryType is not set...
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:31
void SetHostPtrOwner(bool own) const
Set/clear the ownership flag for the host pointer. Ownership indicates whether the pointer will be de...
void Sync(const Memory &other) const
Copy the host/device pointer validity flags from other to *this.
void SetDeviceMemoryType(MemoryType d_mt)
Set the device MemoryType to be used by the Memory object.
bool IsKnown(const void *h_ptr)
Return true if the pointer is known by the memory manager.
void DeleteDevice(bool copy_to_host=true)
Delete the device pointer, if owned. If copy_to_host is true and the data is valid only on device...
A class to initialize the size of a Tensor.
Definition: dtensor.hpp:54
constexpr int HostMemoryTypeSize
Definition: mem_manager.hpp:62
void MakeAlias(const Memory &base, int offset, int size)
Create a memory object that points inside the memory object base.
bool IsDeviceMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::DEVICE.
Definition: mem_manager.hpp:88
Pointer is an alias.
static void SetUmpireDevice2AllocatorName(const char *d_name)
Set the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2.
MemoryManager mm
The (single) global memory manager object.
T * h_ptr
Pointer to host memory. Not owned.
int capacity
Size of the allocated memory.
Memory(int size, MemoryType h_mt, MemoryType d_mt)
Allocate memory for size entries with the given host MemoryType h_mt and device MemoryType d_mt...
Host memory; using new[] and delete[].
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
bool Empty() const
Return true if the Memory object is empty, see Reset().
T * ReadWrite(MemoryClass mc, int size)
Get read-write access to the memory with the given MemoryClass.
friend class MemoryManager
MemoryType GetMemoryType(MemoryClass mc)
Return a suitable MemoryType for a given MemoryClass.
Definition: mem_manager.cpp:55
void CopyToHost(T *dest, int size) const
Copy size entries from *this to the host pointer dest.
Class used by MFEM to store pointers to host and/or device memory.
static void SetUmpireHostAllocatorName(const char *h_name)
Set the host Umpire allocator name used with MemoryType::HOST_UMPIRE.
bool OwnsDevicePtr() const
Return true if the device pointer is owned. Ownership indicates whether the pointer will be deleted b...
bool UseDevice() const
Read the internal device flag.
constexpr int DeviceMemoryTypeSize
Definition: mem_manager.hpp:64
Memory(T *ptr, int size, bool own)
Wrap an externally allocated host pointer, ptr with the current host memory type returned by MemoryMa...
T & operator[](int idx)
Array subscript operator for host memory.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
MemoryClass operator*(MemoryClass mc1, MemoryClass mc2)
Return a suitable MemoryClass from a pair of MemoryClasses.
const T * Read(MemoryClass mc, int size) const
Get read-only access to the memory with the given MemoryClass.
static void SetUmpireDeviceAllocatorName(const char *d_name)
Set the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE.
MemoryType GetHostMemoryType() const
Return the host MemoryType of the Memory object.
MemoryClass
Memory classes identify sets of memory types.
Definition: mem_manager.hpp:73