MFEM  v4.3.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-2021, 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_CUDA
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: no initialization.
179  Memory() { }
180 
181  /// Copy constructor: default.
182  Memory(const Memory &orig) = default;
183 
184  /// Move constructor: default.
185  Memory(Memory &&orig) = default;
186 
187  /// Copy-assignment operator: default.
188  Memory &operator=(const Memory &orig) = default;
189 
190  /// Move-assignment operator: default.
191  Memory &operator=(Memory &&orig) = default;
192 
193  /// Allocate host memory for @a size entries.
194  /** The allocation uses the current host memory type returned by
195  MemoryManager::GetHostMemoryType(). */
196  explicit Memory(int size) { New(size); }
197 
198  /** @brief Allocate memory for @a size entries with the given MemoryType
199  @a mt. */
200  /** The newly allocated memory is not initialized, however the given
201  MemoryType is still set as valid. */
202  Memory(int size, MemoryType mt) { New(size, mt); }
203 
204  /** @brief Allocate memory for @a size entries with the given host MemoryType
205  @a h_mt and device MemoryType @a d_mt. */
206  /** The newly allocated memory is not initialized. The host pointer is set as
207  valid. */
208  Memory(int size, MemoryType h_mt, MemoryType d_mt) { New(size, h_mt, d_mt); }
209 
210  /** @brief Wrap an externally allocated host pointer, @a ptr with the current
211  host memory type returned by MemoryManager::GetHostMemoryType(). */
212  /** The parameter @a own determines whether @a ptr will be deleted when the
213  method Delete() is called. */
214  explicit Memory(T *ptr, int size, bool own) { Wrap(ptr, size, own); }
215 
216  /// Wrap an externally allocated pointer, @a ptr, of the given MemoryType.
217  /** The new memory object will have the given MemoryType set as valid.
218 
219  The given @a ptr must be allocated appropriately for the given
220  MemoryType.
221 
222  The parameter @a own determines whether @a ptr will be deleted when the
223  method Delete() is called. */
224  Memory(T *ptr, int size, MemoryType mt, bool own)
225  { Wrap(ptr, size, mt, own); }
226 
227  /** @brief Alias constructor. Create a Memory object that points inside the
228  Memory object @a base. */
229  /** The new Memory object uses the same MemoryType(s) as @a base. */
230  Memory(const Memory &base, int offset, int size)
231  { MakeAlias(base, offset, size); }
232 
233  /// Destructor: default.
234  /** @note The destructor will NOT delete the current memory. */
235  ~Memory() = default;
236 
237  /** @brief Return true if the host pointer is owned. Ownership indicates
238  whether the pointer will be deleted by the method Delete(). */
239  bool OwnsHostPtr() const { return flags & OWNS_HOST; }
240 
241  /** @brief Set/clear the ownership flag for the host pointer. Ownership
242  indicates whether the pointer will be deleted by the method Delete(). */
243  void SetHostPtrOwner(bool own) const
244  { flags = own ? (flags | OWNS_HOST) : (flags & ~OWNS_HOST); }
245 
246  /** @brief Return true if the device pointer is owned. Ownership indicates
247  whether the pointer will be deleted by the method Delete(). */
248  bool OwnsDevicePtr() const { return flags & OWNS_DEVICE; }
249 
250  /** @brief Set/clear the ownership flag for the device pointer. Ownership
251  indicates whether the pointer will be deleted by the method Delete(). */
252  void SetDevicePtrOwner(bool own) const
253  { flags = own ? (flags | OWNS_DEVICE) : (flags & ~OWNS_DEVICE); }
254 
255  /** @brief Clear the ownership flags for the host and device pointers, as
256  well as any internal data allocated by the Memory object. */
257  void ClearOwnerFlags() const
259 
260  /// Read the internal device flag.
261  bool UseDevice() const { return flags & USE_DEVICE; }
262 
263  /// Set the internal device flag.
264  void UseDevice(bool use_dev) const
265  { flags = use_dev ? (flags | USE_DEVICE) : (flags & ~USE_DEVICE); }
266 
267  /// Return the size of the allocated memory.
268  int Capacity() const { return capacity; }
269 
270  /// Reset the memory to be empty, ensuring that Delete() will be a no-op.
271  /** This is the Memory class equivalent to setting a pointer to NULL, see
272  Empty().
273 
274  @note The current memory is NOT deleted by this method. */
275  void Reset();
276 
277  /// Reset the memory and set the host memory type.
278  void Reset(MemoryType host_mt);
279 
280  /// Return true if the Memory object is empty, see Reset().
281  /** Default-constructed objects are uninitialized, so they are not guaranteed
282  to be empty. */
283  bool Empty() const { return h_ptr == NULL; }
284 
285  /** @brief Allocate host memory for @a size entries with the current host
286  memory type returned by MemoryManager::GetHostMemoryType(). */
287  /** @note The current memory is NOT deleted by this method. */
288  inline void New(int size);
289 
290  /// Allocate memory for @a size entries with the given MemoryType.
291  /** The newly allocated memory is not initialized, however the given
292  MemoryType is still set as valid.
293 
294  When @a mt is a host type, the device MemoryType will be set later, if
295  requested, using the dual type of @a mt, see
296  MemoryManager::GetDualMemoryType().
297 
298  When @a mt is a device type, the host MemoryType will be set immediately
299  to be the dual of @a mt, see MemoryManager::GetDualMemoryType().
300 
301  @note The current memory is NOT deleted by this method. */
302  inline void New(int size, MemoryType mt);
303 
304  /** @brief Allocate memory for @a size entries with the given host MemoryType
305  @a h_mt and device MemoryType @a d_mt. */
306  /** The newly allocated memory is not initialized. The host pointer is set as
307  valid.
308 
309  @note The current memory is NOT deleted by this method. */
310  inline void New(int size, MemoryType h_mt, MemoryType d_mt);
311 
312  /** @brief Wrap an externally allocated host pointer, @a ptr with the current
313  host memory type returned by MemoryManager::GetHostMemoryType(). */
314  /** The parameter @a own determines whether @a ptr will be deleted when the
315  method Delete() is called.
316 
317  @note The current memory is NOT deleted by this method. */
318  inline void Wrap(T *ptr, int size, bool own);
319 
320  /// Wrap an externally allocated pointer, @a ptr, of the given MemoryType.
321  /** The new memory object will have the given MemoryType set as valid.
322 
323  The given @a ptr must be allocated appropriately for the given
324  MemoryType.
325 
326  The parameter @a own determines whether @a ptr will be deleted when the
327  method Delete() is called.
328 
329  @note The current memory is NOT deleted by this method. */
330  inline void Wrap(T *ptr, int size, MemoryType mt, bool own);
331 
332  /** Wrap an externally pair of allocated pointers, @a h_ptr and @a d_ptr,
333  of the given host MemoryType @a h_mt. */
334  /** The new memory object will have the device MemoryType set as valid.
335 
336  The given @a h_ptr and @a d_ptr must be allocated appropriately for the
337  given host MemoryType and its dual device MemoryType as defined by
338  MemoryManager::GetDualMemoryType().
339 
340  The parameter @a own determines whether both @a h_ptr and @a d_ptr will
341  be deleted when the method Delete() is called.
342 
343  @note Ownership can also be controlled by using the following methods:
344  - ClearOwnerFlags,
345  - SetHostPtrOwner,
346  - SetDevicePtrOwner.
347 
348  @note The current memory is NOT deleted by this method. */
349  inline void Wrap(T *h_ptr, T *d_ptr, int size, MemoryType h_mt, bool own);
350 
351  /// Create a memory object that points inside the memory object @a base.
352  /** The new Memory object uses the same MemoryType(s) as @a base.
353 
354  @note The current memory is NOT deleted by this method. */
355  inline void MakeAlias(const Memory &base, int offset, int size);
356 
357  /// Set the device MemoryType to be used by the Memory object.
358  /** If the specified @a d_mt is not a device MemoryType, i.e. not one of the
359  types in MemoryClass::DEVICE, then this method will return immediately.
360 
361  If the device MemoryType has been previously set to a different type and
362  the actual device memory has been allocated, this method will trigger an
363  error. This method will not perform the actual device memory allocation,
364  however, the allocation may already exist if the MemoryType is the same
365  as the current one.
366 
367  If the Memory is an alias Memory, the device MemoryType of its base will
368  be updated as described above. */
369  inline void SetDeviceMemoryType(MemoryType d_mt);
370 
371  /** @brief Delete the owned pointers. The Memory is not reset by this method,
372  i.e. it will, generally, not be Empty() after this call. */
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  { dest.CopyFrom(*this, size); }
499 
500  /// Copy @a size entries from @a *this to the host pointer @a dest.
501  /** The given @a size should not exceed the Capacity() of @a *this. */
502  inline void CopyToHost(T *dest, int size) const;
503 
504  /// Print the internal flags.
505  /** This method can be useful for debugging. It is explicitly instantiated
506  for Memory<T> with T = int and T = double. */
507  inline void PrintFlags() const;
508 
509  /// If both the host and the device data are valid, compare their contents.
510  /** This method can be useful for debugging. It is explicitly instantiated
511  for Memory<T> with T = int and T = double. */
512  inline int CompareHostAndDevice(int size) const;
513 
514 private:
515  // GCC 4.8 workaround: max_align_t is not in std.
516  static constexpr std::size_t def_align_bytes_()
517  {
518  using namespace std;
519  return alignof(max_align_t);
520  }
521  static constexpr std::size_t def_align_bytes = def_align_bytes_();
522  static constexpr std::size_t new_align_bytes =
523  alignof(T) > def_align_bytes ? alignof(T) : def_align_bytes;
524 
525  template <std::size_t align_bytes, bool dummy = true> struct Alloc
526  {
527 #if __cplusplus < 201703L
528  static inline T *New(std::size_t)
529  {
530  // Generate an error in debug mode
531  MFEM_ASSERT(false, "overaligned type cannot use MemoryType::HOST");
532  return nullptr;
533  }
534 #else
535  static inline T *New(std::size_t size) { return new T[size]; }
536 #endif
537  };
538 
539 #if __cplusplus < 201703L
540  template<bool dummy> struct Alloc<def_align_bytes,dummy>
541  {
542  static inline T *New(std::size_t size) { return new T[size]; }
543  };
544 #endif
545 
546  // Shortcut for Alloc<new_align_bytes>::New(size)
547  static inline T *NewHOST(std::size_t size)
548  {
549  return Alloc<new_align_bytes>::New(size);
550  }
551 };
552 
553 
554 /** The MFEM memory manager class. Host-side pointers are inserted into this
555  manager which keeps track of the associated device pointer, and where the
556  data currently resides. */
558 {
559 private:
560 
561  typedef MemoryType MemType;
562  typedef Memory<int> Mem;
563 
564  template <typename T> friend class Memory;
565 
566  /// Host memory type set during the Setup.
567  static MemoryType host_mem_type;
568 
569  /// Device memory type set during the Setup.
570  static MemoryType device_mem_type;
571 
572  /// Allow to detect if a global memory manager instance exists.
573  static bool exists;
574 
575  /// Return true if the global memory manager instance exists.
576  static bool Exists() { return exists; }
577 
578  /// Array defining the dual MemoryType for each MemoryType
579  /** The dual of a host MemoryType is a device MemoryType and vice versa: the
580  dual of a device MemoryType is a host MemoryType. */
581  static MemoryType dual_map[MemoryTypeSize];
582 
583  /// Update the dual memory type of @a mt to be @a dual_mt.
584  static void UpdateDualMemoryType(MemoryType mt, MemoryType dual_mt);
585 
586  /// True if Configure() was called.
587  static bool configured;
588 
589  /// Host and device allocator names for Umpire.
590 #ifdef MFEM_USE_UMPIRE
591  static const char * h_umpire_name;
592  static const char * d_umpire_name;
593  static const char * d_umpire_2_name;
594 #endif
595 
596 private: // Static methods used by the Memory<T> class
597 
598  /// Allocate and register a new pointer. Return the host pointer.
599  /// h_tmp must be already allocated using new T[] if mt is a pure device
600  /// memory type, e.g. CUDA (mt will not be HOST).
601  static void *New_(void *h_tmp, size_t bytes, MemoryType mt, unsigned &flags);
602 
603  static void *New_(void *h_tmp, size_t bytes, MemoryType h_mt,
604  MemoryType d_mt, unsigned valid_flags, unsigned &flags);
605 
606  /// Register an external pointer of the given MemoryType.
607  /// Return the host pointer.
608  static void *Register_(void *ptr, void *h_ptr, size_t bytes, MemoryType mt,
609  bool own, bool alias, unsigned &flags);
610 
611  /// Register a pair of external host and device pointers
612  static void Register2_(void *h_ptr, void *d_ptr, size_t bytes,
613  MemoryType h_mt, MemoryType d_mt,
614  bool own, bool alias, unsigned &flags);
615 
616  /// Register an alias. Note: base_h_ptr may be an alias.
617  static void Alias_(void *base_h_ptr, size_t offset, size_t bytes,
618  unsigned base_flags, unsigned &flags);
619 
620  static void SetDeviceMemoryType_(void *h_ptr, unsigned flags,
621  MemoryType d_mt);
622 
623  /// Un-register and free memory identified by its host pointer. Returns the
624  /// memory type of the host pointer.
625  static MemoryType Delete_(void *h_ptr, MemoryType mt, unsigned flags);
626 
627  /// Free device memory identified by its host pointer
628  static void DeleteDevice_(void *h_ptr, unsigned & flags);
629 
630  /// Check if the memory types given the memory class are valid
631  static bool MemoryClassCheck_(MemoryClass mc, void *h_ptr,
632  MemoryType h_mt, size_t bytes, unsigned flags);
633 
634  /// Return a pointer to the memory identified by the host pointer h_ptr for
635  /// access with the given MemoryClass.
636  static void *ReadWrite_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
637  size_t bytes, unsigned &flags);
638 
639  static const void *Read_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
640  size_t bytes, unsigned &flags);
641 
642  static void *Write_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
643  size_t bytes, unsigned &flags);
644 
645  static void SyncAlias_(const void *base_h_ptr, void *alias_h_ptr,
646  size_t alias_bytes, unsigned base_flags,
647  unsigned &alias_flags);
648 
649  /// Return the type the of the currently valid memory.
650  /// If more than one types are valid, return a device type.
651  static MemoryType GetDeviceMemoryType_(void *h_ptr, bool alias);
652 
653  /// Return the type the of the host memory.
654  static MemoryType GetHostMemoryType_(void *h_ptr);
655 
656  /// Verify that h_mt and h_ptr's h_mt (memory or alias) are equal.
657  static void CheckHostMemoryType_(MemoryType h_mt, void *h_ptr, bool alias);
658 
659  /// Copy entries from valid memory type to valid memory type.
660  /// Both dest_h_ptr and src_h_ptr are registered host pointers.
661  static void Copy_(void *dest_h_ptr, const void *src_h_ptr, size_t bytes,
662  unsigned src_flags, unsigned &dest_flags);
663 
664  /// Copy entries from valid memory type to host memory, where dest_h_ptr is
665  /// not a registered host pointer and src_h_ptr is a registered host pointer.
666  static void CopyToHost_(void *dest_h_ptr, const void *src_h_ptr,
667  size_t bytes, unsigned src_flags);
668 
669  /// Copy entries from host memory to valid memory type, where dest_h_ptr is a
670  /// registered host pointer and src_h_ptr is not a registered host pointer.
671  static void CopyFromHost_(void *dest_h_ptr, const void *src_h_ptr,
672  size_t bytes, unsigned &dest_flags);
673 
674  /// Check if the host pointer has been registered in the memory manager.
675  static bool IsKnown_(const void *h_ptr);
676 
677  /** @brief Check if the host pointer has been registered as an alias in the
678  memory manager. */
679  static bool IsAlias_(const void *h_ptr);
680 
681  /// Compare the contents of the host and the device memory.
682  static int CompareHostAndDevice_(void *h_ptr, size_t size, unsigned flags);
683 
684 private:
685 
686  /// Insert a host address @a h_ptr and size *a bytes in the memory map to be
687  /// managed.
688  void Insert(void *h_ptr, size_t bytes, MemoryType h_mt, MemoryType d_mt);
689 
690  /// Insert a device and the host addresses in the memory map
691  void InsertDevice(void *d_ptr, void *h_ptr, size_t bytes,
692  MemoryType h_mt, MemoryType d_mt);
693 
694  /// Insert an alias in the alias map
695  void InsertAlias(const void *base_ptr, void *alias_ptr,
696  const size_t bytes, const bool base_is_alias);
697 
698  /// Erase an address from the memory map, as well as all its aliases
699  void Erase(void *h_ptr, bool free_dev_ptr = true);
700 
701  /// Erase device memory for a given host address
702  void EraseDevice(void *h_ptr);
703 
704  /// Erase an alias from the aliases map
705  void EraseAlias(void *alias_ptr);
706 
707  /// Return the corresponding device pointer of h_ptr,
708  /// allocating and moving the data if needed
709  void *GetDevicePtr(const void *h_ptr, size_t bytes, bool copy_data);
710 
711  /// Return the corresponding device pointer of alias_ptr,
712  /// allocating and moving the data if needed
713  void *GetAliasDevicePtr(const void *alias_ptr, size_t bytes, bool copy_data);
714 
715  /// Return the corresponding host pointer of d_ptr,
716  /// allocating and moving the data if needed
717  void *GetHostPtr(const void *d_ptr, size_t bytes, bool copy_data);
718 
719  /// Return the corresponding host pointer of alias_ptr,
720  /// allocating and moving the data if needed
721  void *GetAliasHostPtr(const void *alias_ptr, size_t bytes, bool copy_data);
722 
723 public:
724  MemoryManager();
725  ~MemoryManager();
726 
727  /// Initialize the memory manager.
728  void Init();
729 
730  /// Return the dual MemoryType of the given one, @a mt.
731  /** The default dual memory types are:
732 
733  memory type | dual type
734  --------------- | ---------
735  HOST | DEVICE
736  HOST_32 | DEVICE
737  HOST_64 | DEVICE
738  HOST_DEBUG | DEVICE_DEBUG
739  HOST_UMPIRE | DEVICE_UMPIRE
740  HOST_PINNED | DEVICE
741  MANAGED | MANAGED
742  DEVICE | HOST
743  DEVICE_DEBUG | HOST_DEBUG
744  DEVICE_UMPIRE | HOST_UMPIRE
745  DEVICE_UMPIRE_2 | HOST_UMPIRE
746 
747  The dual types can be modified before device configuration using the
748  method SetDualMemoryType() or by calling Device::SetMemoryTypes(). */
750  { return dual_map[(int)mt]; }
751 
752  /// Set the dual memory type of @a mt to be @a dual_mt.
753  /** This method can only be called before configuration, i.e. before calling
754  Configure(), which is typically done during Device construction.
755 
756  One of the types must be a host MemoryType and the other must be a device
757  MemoryType or both types must be the same host memory type. The latter
758  case is only allowed for convenience in setting up pure host execution,
759  so the actual dual is not updated. */
760  static void SetDualMemoryType(MemoryType mt, MemoryType dual_mt);
761 
762  /** @brief Configure the Memory manager with given default host and device
763  types. This method will be called when configuring a device.
764 
765  The host and device MemoryType%s, @a h_mt and @a d_mt, are set to be dual
766  to each other. */
767  void Configure(const MemoryType h_mt, const MemoryType d_mt);
768 
769 #ifdef MFEM_USE_UMPIRE
770  /// Set the host Umpire allocator name used with MemoryType::HOST_UMPIRE
771  static void SetUmpireHostAllocatorName(const char * h_name) { h_umpire_name = h_name; }
772  /// Set the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE
773  static void SetUmpireDeviceAllocatorName(const char * d_name) { d_umpire_name = d_name; }
774  /// Set the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2
775  static void SetUmpireDevice2AllocatorName(const char * d_name) { d_umpire_2_name = d_name; }
776 
777  /// Get the host Umpire allocator name used with MemoryType::HOST_UMPIRE
778  static const char * GetUmpireHostAllocatorName() { return h_umpire_name; }
779  /// Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE
780  static const char * GetUmpireDeviceAllocatorName() { return d_umpire_name; }
781  /// Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2
782  static const char * GetUmpireDevice2AllocatorName() { return d_umpire_2_name; }
783 #endif
784 
785  /// Free all the device memories
786  void Destroy();
787 
788  /// Return true if the pointer is known by the memory manager
789  bool IsKnown(const void *h_ptr) { return IsKnown_(h_ptr); }
790 
791  /// Return true if the pointer is known by the memory manager as an alias
792  bool IsAlias(const void *h_ptr) { return IsAlias_(h_ptr); }
793 
794  /// Check if the host pointer has been registered in the memory manager
795  void RegisterCheck(void *h_ptr);
796 
797  /// Prints all pointers known by the memory manager,
798  /// returning the number of printed pointers
799  int PrintPtrs(std::ostream &out = mfem::out);
800 
801  /// Prints all aliases known by the memory manager
802  /// returning the number of printed pointers
803  int PrintAliases(std::ostream &out = mfem::out);
804 
805  static MemoryType GetHostMemoryType() { return host_mem_type; }
806  static MemoryType GetDeviceMemoryType() { return device_mem_type; }
807 };
808 
809 
810 // Inline methods
811 
812 template <typename T>
813 inline void Memory<T>::Reset()
814 {
815  h_ptr = NULL;
817  capacity = 0;
818  flags = 0;
819 }
820 
821 template <typename T>
822 inline void Memory<T>::Reset(MemoryType host_mt)
823 {
824  h_ptr = NULL;
825  h_mt = host_mt;
826  capacity = 0;
827  flags = 0;
828 }
829 
830 template <typename T>
831 inline void Memory<T>::New(int size)
832 {
833  capacity = size;
836  h_ptr = (h_mt == MemoryType::HOST) ? NewHOST(size) :
837  (T*)MemoryManager::New_(nullptr, size*sizeof(T), h_mt, flags);
838 }
839 
840 template <typename T>
841 inline void Memory<T>::New(int size, MemoryType mt)
842 {
843  capacity = size;
844  const size_t bytes = size*sizeof(T);
845  const bool mt_host = mt == MemoryType::HOST;
846  if (mt_host) { flags = OWNS_HOST | VALID_HOST; }
848  T *h_tmp = (h_mt == MemoryType::HOST) ? NewHOST(size) : nullptr;
849  h_ptr = (mt_host) ? h_tmp : (T*)MemoryManager::New_(h_tmp, bytes, mt, flags);
850 }
851 
852 template <typename T>
853 inline void Memory<T>::New(int size, MemoryType h_mt, MemoryType d_mt)
854 {
855  capacity = size;
856  const size_t bytes = size*sizeof(T);
857  this->h_mt = h_mt;
858  T *h_tmp = (h_mt == MemoryType::HOST) ? NewHOST(size) : nullptr;
859  h_ptr = (T*)MemoryManager::New_(h_tmp, bytes, h_mt, d_mt, 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  capacity = size;
927  h_mt = base.h_mt;
928  h_ptr = base.h_ptr + offset;
929  if (!(base.flags & REGISTERED))
930  {
931  if (
932 #ifndef HYPRE_USING_CUDA
933  // If the following condition is true then MemoryManager::Exists()
934  // should also be true:
936 #else
937  // When HYPRE_USING_CUDA is defined we always register the 'base' if
938  // the MemoryManager::Exists():
939  MemoryManager::Exists()
940 #endif
941  )
942  {
943  // Register 'base':
944  MemoryManager::Register_(base.h_ptr, nullptr, base.capacity*sizeof(T),
945  base.h_mt, base.flags & OWNS_HOST,
946  base.flags & ALIAS, base.flags);
947  }
948  else
949  {
950  // Copy the flags from 'base', setting the ALIAS flag to true, and
951  // setting both OWNS_HOST and OWNS_DEVICE to false:
952  flags = (base.flags | ALIAS) & ~(OWNS_HOST | OWNS_DEVICE);
953  return;
954  }
955  }
956  const size_t s_bytes = size*sizeof(T);
957  const size_t o_bytes = offset*sizeof(T);
958  MemoryManager::Alias_(base.h_ptr, o_bytes, s_bytes, base.flags, flags);
959 }
960 
961 template <typename T>
963 {
964  if (!IsDeviceMemory(d_mt)) { return; }
965  if (!(flags & REGISTERED))
966  {
967  MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
969  }
970  MemoryManager::SetDeviceMemoryType_(h_ptr, flags, d_mt);
971 }
972 
973 template <typename T>
974 inline void Memory<T>::Delete()
975 {
976  const bool registered = flags & REGISTERED;
977  const bool mt_host = h_mt == MemoryType::HOST;
978  const bool std_delete = !registered && mt_host;
979 
980  if (std_delete ||
981  MemoryManager::Delete_((void*)h_ptr, h_mt, flags) == MemoryType::HOST)
982  {
983  if (flags & OWNS_HOST) { delete [] h_ptr; }
984  }
985 }
986 
987 template <typename T>
988 inline void Memory<T>::DeleteDevice(bool copy_to_host)
989 {
990  if (flags & REGISTERED)
991  {
992  if (copy_to_host) { Read(MemoryClass::HOST, capacity); }
993  MemoryManager::DeleteDevice_((void*)h_ptr, flags);
994  }
995 }
996 
997 template <typename T>
998 inline T &Memory<T>::operator[](int idx)
999 {
1000  MFEM_ASSERT((flags & VALID_HOST) && !(flags & VALID_DEVICE),
1001  "invalid host pointer access");
1002  return h_ptr[idx];
1003 }
1004 
1005 template <typename T>
1006 inline const T &Memory<T>::operator[](int idx) const
1007 {
1008  MFEM_ASSERT((flags & VALID_HOST), "invalid host pointer access");
1009  return h_ptr[idx];
1010 }
1011 
1012 template <typename T>
1014 {
1015  MFEM_ASSERT(Empty() ||
1016  ((flags & VALID_HOST) &&
1017  (std::is_const<T>::value || !(flags & VALID_DEVICE))),
1018  "invalid host pointer access");
1019  return h_ptr;
1020 }
1021 
1022 template <typename T>
1023 inline Memory<T>::operator const T*() const
1024 {
1025  MFEM_ASSERT(Empty() || (flags & VALID_HOST), "invalid host pointer access");
1026  return h_ptr;
1027 }
1028 
1029 template <typename T> template <typename U>
1031 {
1032  MFEM_ASSERT(Empty() ||
1033  ((flags & VALID_HOST) &&
1034  (std::is_const<U>::value || !(flags & VALID_DEVICE))),
1035  "invalid host pointer access");
1036  return reinterpret_cast<U*>(h_ptr);
1037 }
1038 
1039 template <typename T> template <typename U>
1040 inline Memory<T>::operator const U*() const
1041 {
1042  MFEM_ASSERT(Empty() || (flags & VALID_HOST), "invalid host pointer access");
1043  return reinterpret_cast<U*>(h_ptr);
1044 }
1045 
1046 template <typename T>
1047 inline T *Memory<T>::ReadWrite(MemoryClass mc, int size)
1048 {
1049  const size_t bytes = size * sizeof(T);
1050  if (!(flags & REGISTERED))
1051  {
1052  if (mc == MemoryClass::HOST) { return h_ptr; }
1053  MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
1054  flags & OWNS_HOST, flags & ALIAS, flags);
1055  }
1056  return (T*)MemoryManager::ReadWrite_(h_ptr, h_mt, mc, bytes, flags);
1057 }
1058 
1059 template <typename T>
1060 inline const T *Memory<T>::Read(MemoryClass mc, int size) const
1061 {
1062  const size_t bytes = size * sizeof(T);
1063  if (!(flags & REGISTERED))
1064  {
1065  if (mc == MemoryClass::HOST) { return h_ptr; }
1066  MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
1067  flags & OWNS_HOST, flags & ALIAS, flags);
1068  }
1069  return (const T*)MemoryManager::Read_(h_ptr, h_mt, mc, bytes, flags);
1070 }
1071 
1072 template <typename T>
1073 inline T *Memory<T>::Write(MemoryClass mc, int size)
1074 {
1075  const size_t bytes = size * sizeof(T);
1076  if (!(flags & REGISTERED))
1077  {
1078  if (mc == MemoryClass::HOST) { return h_ptr; }
1079  MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
1080  flags & OWNS_HOST, flags & ALIAS, flags);
1081  }
1082  return (T*)MemoryManager::Write_(h_ptr, h_mt, mc, bytes, flags);
1083 }
1084 
1085 template <typename T>
1086 inline void Memory<T>::Sync(const Memory &other) const
1087 {
1088  if (!(flags & REGISTERED) && (other.flags & REGISTERED))
1089  {
1090  MFEM_ASSERT(h_ptr == other.h_ptr &&
1091  (flags & ALIAS) == (other.flags & ALIAS),
1092  "invalid input");
1094  }
1095  flags = (flags & ~(VALID_HOST | VALID_DEVICE)) |
1096  (other.flags & (VALID_HOST | VALID_DEVICE));
1097 }
1098 
1099 template <typename T>
1100 inline void Memory<T>::SyncAlias(const Memory &base, int alias_size) const
1101 {
1102  // Assuming that if *this is registered then base is also registered.
1103  MFEM_ASSERT(!(flags & REGISTERED) || (base.flags & REGISTERED),
1104  "invalid base state");
1105  if (!(base.flags & REGISTERED)) { return; }
1106  MemoryManager::SyncAlias_(base.h_ptr, h_ptr, alias_size*sizeof(T),
1107  base.flags, flags);
1108 }
1109 
1110 template <typename T>
1112 {
1113  if (!(flags & VALID_DEVICE)) { return h_mt; }
1114  return MemoryManager::GetDeviceMemoryType_(h_ptr, flags & ALIAS);
1115 }
1116 
1117 template <typename T>
1119 {
1120  if (!(flags & REGISTERED)) { return MemoryType::DEFAULT; }
1121  return MemoryManager::GetDeviceMemoryType_(h_ptr, flags & ALIAS);
1122 }
1123 
1124 template <typename T>
1125 inline bool Memory<T>::HostIsValid() const
1126 {
1127  return flags & VALID_HOST ? true : false;
1128 }
1129 
1130 template <typename T>
1131 inline bool Memory<T>::DeviceIsValid() const
1132 {
1133  return flags & VALID_DEVICE ? true : false;
1134 }
1135 
1136 template <typename T>
1137 inline void Memory<T>::CopyFrom(const Memory &src, int size)
1138 {
1139  if (!(flags & REGISTERED) && !(src.flags & REGISTERED))
1140  {
1141  if (h_ptr != src.h_ptr && size != 0)
1142  {
1143  MFEM_ASSERT(h_ptr + size <= src.h_ptr || src.h_ptr + size <= h_ptr,
1144  "data overlaps!");
1145  std::memcpy(h_ptr, src, size*sizeof(T));
1146  }
1147  // *this is not registered, so (flags & VALID_HOST) must be true
1148  }
1149  else
1150  {
1151  MemoryManager::Copy_(h_ptr, src.h_ptr, size*sizeof(T), src.flags, flags);
1152  }
1153 }
1154 
1155 template <typename T>
1156 inline void Memory<T>::CopyFromHost(const T *src, int size)
1157 {
1158  if (!(flags & REGISTERED))
1159  {
1160  if (h_ptr != src && size != 0)
1161  {
1162  MFEM_ASSERT(h_ptr + size <= src || src + size <= h_ptr,
1163  "data overlaps!");
1164  std::memcpy(h_ptr, src, size*sizeof(T));
1165  }
1166  // *this is not registered, so (flags & VALID_HOST) must be true
1167  }
1168  else
1169  {
1170  MemoryManager::CopyFromHost_(h_ptr, src, size*sizeof(T), flags);
1171  }
1172 }
1173 
1174 template <typename T>
1175 inline void Memory<T>::CopyToHost(T *dest, int size) const
1176 {
1177  if (!(flags & REGISTERED))
1178  {
1179  if (h_ptr != dest && size != 0)
1180  {
1181  MFEM_ASSERT(h_ptr + size <= dest || dest + size <= h_ptr,
1182  "data overlaps!");
1183  std::memcpy(dest, h_ptr, size*sizeof(T));
1184  }
1185  }
1186  else
1187  {
1188  MemoryManager::CopyToHost_(dest, h_ptr, size*sizeof(T), flags);
1189  }
1190 }
1191 
1192 
1193 /** @brief Print the state of a Memory object based on its internal flags.
1194  Useful in a debugger. See also Memory<T>::PrintFlags(). */
1195 extern void MemoryPrintFlags(unsigned flags);
1196 
1197 
1198 template <typename T>
1199 inline void Memory<T>::PrintFlags() const
1200 {
1202 }
1203 
1204 template <typename T>
1205 inline int Memory<T>::CompareHostAndDevice(int size) const
1206 {
1207  if (!(flags & VALID_HOST) || !(flags & VALID_DEVICE)) { return 0; }
1208  return MemoryManager::CompareHostAndDevice_(h_ptr, size*sizeof(T), flags);
1209 }
1210 
1211 
1212 /// The (single) global memory manager object
1213 extern MemoryManager mm;
1214 
1215 } // namespace mfem
1216 
1217 #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. The Memory is not reset by this method, i.e. it will, generally, not be Empty() after this call.
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.
bool MemoryClassContainsType(MemoryClass mc, MemoryType mt)
Return true iff the MemoryType mt is contained in the MemoryClass mc.
Definition: mem_manager.cpp:69
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:54
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.
Memory()
Default constructor: no initialization.
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