MFEM  v4.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
mem_manager.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 #include "../general/forall.hpp"
13 
14 #include <cstring> // std::memcpy
15 
16 #include <list>
17 #include <unordered_map>
18 #include <algorithm> // std::max
19 
20 namespace mfem
21 {
22 
24 {
25  switch (mc)
26  {
32  }
33  return MemoryType::HOST;
34 }
35 
37 {
38  // | HOST HOST_32 HOST_64 CUDA CUDA_UVM
39  // ---------+--------------------------------------------------
40  // HOST | HOST HOST_32 HOST_64 CUDA CUDA_UVM
41  // HOST_32 | HOST_32 HOST_32 HOST_64 CUDA CUDA_UVM
42  // HOST_64 | HOST_64 HOST_64 HOST_64 CUDA CUDA_UVM
43  // CUDA | CUDA CUDA CUDA CUDA CUDA_UVM
44  // CUDA_UVM | CUDA_UVM CUDA_UVM CUDA_UVM CUDA_UVM CUDA_UVM
45 
46  // Using the enumeration ordering:
47  // HOST < HOST_32 < HOST_64 < CUDA < CUDA_UVM,
48  // the above table is simply: a*b = max(a,b).
49 
50  return std::max(mc1, mc2);
51 }
52 
53 
54 namespace internal
55 {
56 
57 /// Forward declaration of the Alias structure
58 struct Alias;
59 
60 /// Memory class that holds:
61 /// - a boolean telling which memory space is being used
62 /// - the size in bytes of this memory region,
63 /// - the host and the device pointer.
64 struct Memory
65 {
66  bool host;
67  const std::size_t bytes;
68  void *const h_ptr;
69  void *d_ptr;
70  Memory(void* const h, const std::size_t size):
71  host(true), bytes(size), h_ptr(h), d_ptr(nullptr) {}
72 };
73 
74 /// Alias class that holds the base memory region and the offset
75 struct Alias
76 {
77  Memory *const mem;
78  const long offset;
79  unsigned long counter;
80 };
81 
82 typedef std::unordered_map<const void*, Memory> MemoryMap;
83 // TODO: use 'Alias' or 'const Alias' as the mapped type in the AliasMap instead
84 // of 'Alias*'
85 typedef std::unordered_map<const void*, Alias*> AliasMap;
86 
87 struct Ledger
88 {
89  MemoryMap memories;
90  AliasMap aliases;
91 };
92 
93 } // namespace mfem::internal
94 
95 static internal::Ledger *maps;
96 
98 {
99  exists = true;
100  maps = new internal::Ledger();
101 }
102 
104 {
105  if (exists) { Destroy(); }
106 }
107 
109 {
110  MFEM_VERIFY(exists, "MemoryManager has been destroyed already!");
111  for (auto& n : maps->memories)
112  {
113  internal::Memory &mem = n.second;
114  if (mem.d_ptr) { CuMemFree(mem.d_ptr); }
115  }
116  for (auto& n : maps->aliases)
117  {
118  delete n.second;
119  }
120  delete maps;
121  exists = false;
122 }
123 
124 void* MemoryManager::Insert(void *ptr, const std::size_t bytes)
125 {
126  if (ptr == NULL)
127  {
128  MFEM_VERIFY(bytes == 0, "Trying to add NULL with size " << bytes);
129  return NULL;
130  }
131  auto res = maps->memories.emplace(ptr, internal::Memory(ptr, bytes));
132  if (res.second == false)
133  {
134  mfem_error("Trying to add an already present address!");
135  }
136  return ptr;
137 }
138 
139 void MemoryManager::InsertDevice(void *ptr, void *h_ptr, size_t bytes)
140 {
141  MFEM_VERIFY(ptr != NULL, "cannot register NULL device pointer");
142  MFEM_VERIFY(h_ptr != NULL, "internal error");
143  auto res = maps->memories.emplace(h_ptr, internal::Memory(h_ptr, bytes));
144  if (res.second == false)
145  {
146  mfem_error("Trying to add an already present address!");
147  }
148  res.first->second.d_ptr = ptr;
149 }
150 
151 void *MemoryManager::Erase(void *ptr, bool free_dev_ptr)
152 {
153  if (!ptr) { return ptr; }
154  auto mem_map_iter = maps->memories.find(ptr);
155  if (mem_map_iter == maps->memories.end())
156  {
157  mfem_error("Trying to erase an unknown pointer!");
158  }
159  internal::Memory &mem = mem_map_iter->second;
160  if (mem.d_ptr && free_dev_ptr) { CuMemFree(mem.d_ptr); }
161  maps->memories.erase(mem_map_iter);
162  return ptr;
163 }
164 
165 bool MemoryManager::IsKnown(const void *ptr)
166 {
167  return maps->memories.find(ptr) != maps->memories.end();
168 }
169 
170 void *MemoryManager::GetDevicePtr(const void *ptr, size_t bytes, bool copy_data)
171 {
172  if (!ptr)
173  {
174  MFEM_VERIFY(bytes == 0, "Trying to access NULL with size " << bytes);
175  return NULL;
176  }
177  internal::Memory &base = maps->memories.at(ptr);
178  if (!base.d_ptr)
179  {
180  CuMemAlloc(&base.d_ptr, base.bytes);
181  }
182  if (copy_data)
183  {
184  MFEM_ASSERT(bytes <= base.bytes, "invalid copy size");
185  CuMemcpyHtoD(base.d_ptr, ptr, bytes);
186  base.host = false;
187  }
188  return base.d_ptr;
189 }
190 
191 void MemoryManager::InsertAlias(const void *base_ptr, void *alias_ptr,
192  bool base_is_alias)
193 {
194  long offset = static_cast<const char*>(alias_ptr) -
195  static_cast<const char*>(base_ptr);
196  if (!base_ptr)
197  {
198  MFEM_VERIFY(offset == 0,
199  "Trying to add alias to NULL at offset " << offset);
200  return;
201  }
202  if (base_is_alias)
203  {
204  const internal::Alias *alias = maps->aliases.at(base_ptr);
205  base_ptr = alias->mem->h_ptr;
206  offset += alias->offset;
207  }
208  internal::Memory &mem = maps->memories.at(base_ptr);
209  auto res = maps->aliases.emplace(alias_ptr, nullptr);
210  if (res.second == false) // alias_ptr was already in the map
211  {
212  if (res.first->second->mem != &mem || res.first->second->offset != offset)
213  {
214  mfem_error("alias already exists with different base/offset!");
215  }
216  else
217  {
218  res.first->second->counter++;
219  }
220  }
221  else
222  {
223  res.first->second = new internal::Alias{&mem, offset, 1};
224  }
225 }
226 
227 void MemoryManager::EraseAlias(void *alias_ptr)
228 {
229  if (!alias_ptr) { return; }
230  auto alias_map_iter = maps->aliases.find(alias_ptr);
231  if (alias_map_iter == maps->aliases.end())
232  {
233  mfem_error("alias not found");
234  }
235  internal::Alias *alias = alias_map_iter->second;
236  if (--alias->counter) { return; }
237  // erase the alias from the alias map:
238  maps->aliases.erase(alias_map_iter);
239  delete alias;
240 }
241 
242 void *MemoryManager::GetAliasDevicePtr(const void *alias_ptr, size_t bytes,
243  bool copy_data)
244 {
245  if (!alias_ptr)
246  {
247  MFEM_VERIFY(bytes == 0, "Trying to access NULL with size " << bytes);
248  return NULL;
249  }
250  auto &alias_map = maps->aliases;
251  auto alias_map_iter = alias_map.find(alias_ptr);
252  if (alias_map_iter == alias_map.end())
253  {
254  mfem_error("alias not found");
255  }
256  const internal::Alias *alias = alias_map_iter->second;
257  internal::Memory &base = *alias->mem;
258  MFEM_ASSERT((char*)base.h_ptr + alias->offset == alias_ptr,
259  "internal error");
260  if (!base.d_ptr)
261  {
262  CuMemAlloc(&base.d_ptr, base.bytes);
263  }
264  if (copy_data)
265  {
266  CuMemcpyHtoD((char*)base.d_ptr + alias->offset, alias_ptr, bytes);
267  base.host = false;
268  }
269  return (char*)base.d_ptr + alias->offset;
270 }
271 
272 static void PullKnown(internal::Ledger *maps,
273  const void *ptr, const std::size_t bytes, bool copy_data)
274 {
275  internal::Memory &base = maps->memories.at(ptr);
276  MFEM_ASSERT(base.h_ptr == ptr, "internal error");
277  // There are cases where it is OK if base.d_ptr is not allocated yet:
278  // for example, when requesting read-write access on host to memory created
279  // as device memory.
280  if (copy_data && base.d_ptr)
281  {
282  CuMemcpyDtoH(base.h_ptr, base.d_ptr, bytes);
283  base.host = true;
284  }
285 }
286 
287 static void PullAlias(const internal::Ledger *maps,
288  const void *ptr, const std::size_t bytes, bool copy_data)
289 {
290  const internal::Alias *alias = maps->aliases.at(ptr);
291  MFEM_ASSERT((char*)alias->mem->h_ptr + alias->offset == ptr,
292  "internal error");
293  // There are cases where it is OK if alias->mem->d_ptr is not allocated yet:
294  // for example, when requesting read-write access on host to memory created
295  // as device memory.
296  if (copy_data && alias->mem->d_ptr)
297  {
298  CuMemcpyDtoH(const_cast<void*>(ptr),
299  static_cast<char*>(alias->mem->d_ptr) + alias->offset,
300  bytes);
301  }
302 }
303 
305 {
306  if (ptr != NULL)
307  {
308  if (!IsKnown(ptr))
309  {
310  mfem_error("Pointer is not registered!");
311  }
312  }
313 }
314 
316 {
317  for (const auto& n : maps->memories)
318  {
319  const internal::Memory &mem = n.second;
320  mfem::out << std::endl
321  << "key " << n.first << ", "
322  << "host " << mem.host << ", "
323  << "h_ptr " << mem.h_ptr << ", "
324  << "d_ptr " << mem.d_ptr;
325  }
326  mfem::out << std::endl;
327 }
328 
329 // Static private MemoryManager methods used by class Memory
330 
331 void *MemoryManager::New_(void *h_ptr, std::size_t size, MemoryType mt,
332  unsigned &flags)
333 {
334  // TODO: save the types of the pointers ...
336  switch (mt)
337  {
338  case MemoryType::HOST: return nullptr; // case is handled outside
339 
340  case MemoryType::HOST_32:
341  case MemoryType::HOST_64:
342  mfem_error("New_(): aligned host types are not implemented yet");
343  return nullptr;
344 
345  case MemoryType::CUDA:
346  mm.Insert(h_ptr, size);
348  return h_ptr;
349 
351  mfem_error("New_(): CUDA UVM allocation is not implemented yet");
352  return nullptr;
353  }
354  return nullptr;
355 }
356 
357 void *MemoryManager::Register_(void *ptr, void *h_ptr, std::size_t capacity,
358  MemoryType mt, bool own, bool alias,
359  unsigned &flags)
360 {
361  // TODO: save the type of the registered pointer ...
362  MFEM_VERIFY(alias == false, "cannot register an alias!");
363  flags = flags | (Mem::REGISTERED | Mem::OWNS_INTERNAL);
364  if (IsHostMemory(mt))
365  {
366  mm.Insert(ptr, capacity);
367  flags = (own ? flags | Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST) |
369  return ptr;
370  }
371  MFEM_VERIFY(mt == MemoryType::CUDA, "Only CUDA pointers are supported");
372  mm.InsertDevice(ptr, h_ptr, capacity);
373  flags = (own ? flags | Mem::OWNS_DEVICE : flags & ~Mem::OWNS_DEVICE) |
375  return h_ptr;
376 }
377 
378 void MemoryManager::Alias_(void *base_h_ptr, std::size_t offset,
379  std::size_t size, unsigned base_flags,
380  unsigned &flags)
381 {
382  // TODO: store the 'size' in the MemoryManager?
383  mm.InsertAlias(base_h_ptr, (char*)base_h_ptr + offset,
384  base_flags & Mem::ALIAS);
385  flags = (base_flags | Mem::ALIAS | Mem::OWNS_INTERNAL) &
387 }
388 
389 MemoryType MemoryManager::Delete_(void *h_ptr, unsigned flags)
390 {
391  // TODO: this logic needs to be updated when support for HOST_32 and HOST_64
392  // memory types is added.
393 
394  MFEM_ASSERT(!(flags & Mem::OWNS_DEVICE) || (flags & Mem::OWNS_INTERNAL),
395  "invalid Memory state");
396  if (mm.exists && (flags & Mem::OWNS_INTERNAL))
397  {
398  if (flags & Mem::ALIAS)
399  {
400  mm.EraseAlias(h_ptr);
401  }
402  else
403  {
404  mm.Erase(h_ptr, flags & Mem::OWNS_DEVICE);
405  }
406  }
407  return MemoryType::HOST;
408 }
409 
410 void *MemoryManager::ReadWrite_(void *h_ptr, MemoryClass mc,
411  std::size_t size, unsigned &flags)
412 {
413  switch (mc)
414  {
415  case MemoryClass::HOST:
416  if (!(flags & Mem::VALID_HOST))
417  {
418  if (flags & Mem::ALIAS) { PullAlias(maps, h_ptr, size, true); }
419  else { PullKnown(maps, h_ptr, size, true); }
420  }
421  flags = (flags | Mem::VALID_HOST) & ~Mem::VALID_DEVICE;
422  return h_ptr;
423 
425  // TODO: check that the host pointer is MemoryType::HOST_32 or
426  // MemoryType::HOST_64
427  return h_ptr;
428 
430  // TODO: check that the host pointer is MemoryType::HOST_64
431  return h_ptr;
432 
433  case MemoryClass::CUDA:
434  {
435  // TODO: check that the device pointer is MemoryType::CUDA or
436  // MemoryType::CUDA_UVM
437 
438  const bool need_copy = !(flags & Mem::VALID_DEVICE);
439  flags = (flags | Mem::VALID_DEVICE) & ~Mem::VALID_HOST;
440 
441  // TODO: add support for UVM
442  if (flags & Mem::ALIAS)
443  {
444  return mm.GetAliasDevicePtr(h_ptr, size, need_copy);
445  }
446  return mm.GetDevicePtr(h_ptr, size, need_copy);
447  }
448 
450  // TODO: check that the host+device pointers are MemoryType::CUDA_UVM
451 
452  // Do we need to update the validity flags?
453 
454  return h_ptr; // the host and device pointers are the same
455  }
456  return nullptr;
457 }
458 
459 const void *MemoryManager::Read_(void *h_ptr, MemoryClass mc,
460  std::size_t size, unsigned &flags)
461 {
462  switch (mc)
463  {
464  case MemoryClass::HOST:
465  if (!(flags & Mem::VALID_HOST))
466  {
467  if (flags & Mem::ALIAS) { PullAlias(maps, h_ptr, size, true); }
468  else { PullKnown(maps, h_ptr, size, true); }
469  }
470  flags = flags | Mem::VALID_HOST;
471  return h_ptr;
472 
474  // TODO: check that the host pointer is MemoryType::HOST_32 or
475  // MemoryType::HOST_64
476  return h_ptr;
477 
479  // TODO: check that the host pointer is MemoryType::HOST_64
480  return h_ptr;
481 
482  case MemoryClass::CUDA:
483  {
484  // TODO: check that the device pointer is MemoryType::CUDA or
485  // MemoryType::CUDA_UVM
486 
487  const bool need_copy = !(flags & Mem::VALID_DEVICE);
488  flags = flags | Mem::VALID_DEVICE;
489 
490  // TODO: add support for UVM
491  if (flags & Mem::ALIAS)
492  {
493  return mm.GetAliasDevicePtr(h_ptr, size, need_copy);
494  }
495  return mm.GetDevicePtr(h_ptr, size, need_copy);
496  }
497 
499  // TODO: check that the host+device pointers are MemoryType::CUDA_UVM
500 
501  // Do we need to update the validity flags?
502 
503  return h_ptr; // the host and device pointers are the same
504  }
505  return nullptr;
506 }
507 
508 void *MemoryManager::Write_(void *h_ptr, MemoryClass mc, std::size_t size,
509  unsigned &flags)
510 {
511  switch (mc)
512  {
513  case MemoryClass::HOST:
514  flags = (flags | Mem::VALID_HOST) & ~Mem::VALID_DEVICE;
515  return h_ptr;
516 
518  // TODO: check that the host pointer is MemoryType::HOST_32 or
519  // MemoryType::HOST_64
520 
521  flags = (flags | Mem::VALID_HOST) & ~Mem::VALID_DEVICE;
522  return h_ptr;
523 
525  // TODO: check that the host pointer is MemoryType::HOST_64
526 
527  flags = (flags | Mem::VALID_HOST) & ~Mem::VALID_DEVICE;
528  return h_ptr;
529 
530  case MemoryClass::CUDA:
531  // TODO: check that the device pointer is MemoryType::CUDA or
532  // MemoryType::CUDA_UVM
533 
534  flags = (flags | Mem::VALID_DEVICE) & ~Mem::VALID_HOST;
535 
536  // TODO: add support for UVM
537  if (flags & Mem::ALIAS)
538  {
539  return mm.GetAliasDevicePtr(h_ptr, size, false);
540  }
541  return mm.GetDevicePtr(h_ptr, size, false);
542 
544  // TODO: check that the host+device pointers are MemoryType::CUDA_UVM
545 
546  // Do we need to update the validity flags?
547 
548  return h_ptr; // the host and device pointers are the same
549  }
550  return nullptr;
551 }
552 
553 void MemoryManager::SyncAlias_(const void *base_h_ptr, void *alias_h_ptr,
554  size_t alias_size, unsigned base_flags,
555  unsigned &alias_flags)
556 {
557  // This is called only when (base_flags & Mem::REGISTERED) is true.
558  // Note that (alias_flags & REGISTERED) may not be true.
559  MFEM_ASSERT(alias_flags & Mem::ALIAS, "not an alias");
560  if ((base_flags & Mem::VALID_HOST) && !(alias_flags & Mem::VALID_HOST))
561  {
562  PullAlias(maps, alias_h_ptr, alias_size, true);
563  }
564  if ((base_flags & Mem::VALID_DEVICE) && !(alias_flags & Mem::VALID_DEVICE))
565  {
566  if (!(alias_flags & Mem::REGISTERED))
567  {
568  mm.InsertAlias(base_h_ptr, alias_h_ptr, base_flags & Mem::ALIAS);
569  alias_flags = (alias_flags | Mem::REGISTERED | Mem::OWNS_INTERNAL) &
570  ~(Mem::OWNS_HOST | Mem::OWNS_DEVICE);
571  }
572  mm.GetAliasDevicePtr(alias_h_ptr, alias_size, true);
573  }
574  alias_flags = (alias_flags & ~(Mem::VALID_HOST | Mem::VALID_DEVICE)) |
575  (base_flags & (Mem::VALID_HOST | Mem::VALID_DEVICE));
576 }
577 
578 MemoryType MemoryManager::GetMemoryType_(void *h_ptr, unsigned flags)
579 {
580  // TODO: support other memory types
581  if (flags & Mem::VALID_DEVICE) { return MemoryType::CUDA; }
582  return MemoryType::HOST;
583 }
584 
585 void MemoryManager::Copy_(void *dest_h_ptr, const void *src_h_ptr,
586  std::size_t size, unsigned src_flags,
587  unsigned &dest_flags)
588 {
589  // Type of copy to use based on the src and dest validity flags:
590  // | src
591  // | h | d | hd
592  // -----------+-----+-----+------
593  // h | h2h d2h h2h
594  // dest d | h2d d2d d2d
595  // hd | h2h d2d d2d
596 
597  const bool src_on_host =
598  (src_flags & Mem::VALID_HOST) &&
599  (!(src_flags & Mem::VALID_DEVICE) ||
600  ((dest_flags & Mem::VALID_HOST) && !(dest_flags & Mem::VALID_DEVICE)));
601  const bool dest_on_host =
602  (dest_flags & Mem::VALID_HOST) &&
603  (!(dest_flags & Mem::VALID_DEVICE) ||
604  ((src_flags & Mem::VALID_HOST) && !(src_flags & Mem::VALID_DEVICE)));
605  const void *src_d_ptr = src_on_host ? NULL :
606  ((src_flags & Mem::ALIAS) ?
607  mm.GetAliasDevicePtr(src_h_ptr, size, false) :
608  mm.GetDevicePtr(src_h_ptr, size, false));
609  if (dest_on_host)
610  {
611  if (src_on_host)
612  {
613  if (dest_h_ptr != src_h_ptr && size != 0)
614  {
615  MFEM_ASSERT((char*)dest_h_ptr + size <= src_h_ptr ||
616  (char*)src_h_ptr + size <= dest_h_ptr,
617  "data overlaps!");
618  std::memcpy(dest_h_ptr, src_h_ptr, size);
619  }
620  }
621  else
622  {
623  CuMemcpyDtoH(dest_h_ptr, src_d_ptr, size);
624  }
625  }
626  else
627  {
628  void *dest_d_ptr = (dest_flags & Mem::ALIAS) ?
629  mm.GetAliasDevicePtr(dest_h_ptr, size, false) :
630  mm.GetDevicePtr(dest_h_ptr, size, false);
631  if (src_on_host)
632  {
633  CuMemcpyHtoD(dest_d_ptr, src_h_ptr, size);
634  }
635  else
636  {
637  CuMemcpyDtoD(dest_d_ptr, src_d_ptr, size);
638  }
639  }
640  dest_flags = dest_flags &
641  ~(dest_on_host ? Mem::VALID_DEVICE : Mem::VALID_HOST);
642 }
643 
644 void MemoryManager::CopyToHost_(void *dest_h_ptr, const void *src_h_ptr,
645  std::size_t size, unsigned src_flags)
646 {
647  const bool src_on_host = src_flags & Mem::VALID_HOST;
648  if (src_on_host)
649  {
650  if (dest_h_ptr != src_h_ptr && size != 0)
651  {
652  MFEM_ASSERT((char*)dest_h_ptr + size <= src_h_ptr ||
653  (char*)src_h_ptr + size <= dest_h_ptr,
654  "data overlaps!");
655  std::memcpy(dest_h_ptr, src_h_ptr, size);
656  }
657  }
658  else
659  {
660  const void *src_d_ptr = (src_flags & Mem::ALIAS) ?
661  mm.GetAliasDevicePtr(src_h_ptr, size, false) :
662  mm.GetDevicePtr(src_h_ptr, size, false);
663  CuMemcpyDtoH(dest_h_ptr, src_d_ptr, size);
664  }
665 }
666 
667 void MemoryManager::CopyFromHost_(void *dest_h_ptr, const void *src_h_ptr,
668  std::size_t size, unsigned &dest_flags)
669 {
670  const bool dest_on_host = dest_flags & Mem::VALID_HOST;
671  if (dest_on_host)
672  {
673  if (dest_h_ptr != src_h_ptr && size != 0)
674  {
675  MFEM_ASSERT((char*)dest_h_ptr + size <= src_h_ptr ||
676  (char*)src_h_ptr + size <= dest_h_ptr,
677  "data overlaps!");
678  std::memcpy(dest_h_ptr, src_h_ptr, size);
679  }
680  }
681  else
682  {
683  void *dest_d_ptr = (dest_flags & Mem::ALIAS) ?
684  mm.GetAliasDevicePtr(dest_h_ptr, size, false) :
685  mm.GetDevicePtr(dest_h_ptr, size, false);
686  CuMemcpyHtoD(dest_d_ptr, src_h_ptr, size);
687  }
688  dest_flags = dest_flags &
689  ~(dest_on_host ? Mem::VALID_DEVICE : Mem::VALID_HOST);
690 }
691 
692 
693 void MemoryPrintFlags(unsigned flags)
694 {
695  typedef Memory<int> Mem;
696  mfem::out
697  << " registered = " << bool(flags & Mem::REGISTERED)
698  << "\n owns host = " << bool(flags & Mem::OWNS_HOST)
699  << "\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
700  << "\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
701  << "\n valid host = " << bool(flags & Mem::VALID_HOST)
702  << "\n valid device = " << bool(flags & Mem::VALID_DEVICE)
703  << "\n alias = " << bool(flags & Mem::ALIAS)
704  << "\n device flag = " << bool(flags & Mem::USE_DEVICE)
705  << std::endl;
706 }
707 
708 
710 bool MemoryManager::exists = false;
711 
712 } // namespace mfem
void * CuMemcpyHtoD(void *dst, const void *src, size_t bytes)
Copies memory from Host to Device.
Definition: cuda.cpp:64
void * CuMemFree(void *dptr)
Frees device memory.
Definition: cuda.cpp:49
Host memory aligned at 64 bytes (not supported yet)
bool IsHostMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::HOST.
Definition: mem_manager.hpp:50
The device pointer will be deleted by Delete()
Memory types: { CUDA, CUDA_UVM }.
Host pointer is valid.
Host memory aligned at 32 bytes (not supported yet)
The memory manager class.
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:146
void * CuMemcpyDtoD(void *dst, const void *src, size_t bytes)
Copies memory from Device to Device.
Definition: cuda.cpp:87
h_ptr is registered with the MemoryManager
The host pointer will be deleted by Delete()
Device pointer is valid.
Ownership flag for internal Memory data.
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:27
void RegisterCheck(void *ptr)
Check if pointer has been registered in the memory manager.
cudaMalloc, cudaFree
MemoryManager mm
The (single) global memory manager object.
Host memory; using new[] and delete[].
void PrintPtrs(void)
Prints all pointers known by the memory manager.
cudaMallocManaged, cudaFree (not supported yet)
MemoryType GetMemoryType(MemoryClass mc)
Return a suitable MemoryType for a given MemoryClass.
Definition: mem_manager.cpp:23
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:64
MemoryClass operator*(MemoryClass mc1, MemoryClass mc2)
Return a suitable MemoryClass from a pair of MemoryClasses.
Definition: mem_manager.cpp:36
void * CuMemAlloc(void **dptr, size_t bytes)
Allocates device memory.
Definition: cuda.cpp:34
MemoryClass
Memory classes identify subsets of memory types.
Definition: mem_manager.hpp:40
void * CuMemcpyDtoH(void *dst, const void *src, size_t bytes)
Copies memory from Device to Host.
Definition: cuda.cpp:110
void MemoryPrintFlags(unsigned flags)
Print the state of a Memory object based on its internal flags. Useful in a debugger.