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