17 #include <unordered_map>
28 #define mfem_memalign(p,a,s) posix_memalign(p,a,s)
29 #define mfem_aligned_free free
31 #define mfem_memalign(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno)
32 #define mfem_aligned_free _aligned_free
35 #ifdef MFEM_USE_UMPIRE
36 #include <umpire/Umpire.hpp>
37 #include <umpire/strategy/QuickPool.hpp>
40 #if defined(MFEM_USE_CUDA) && !defined(UMPIRE_ENABLE_CUDA)
41 #error "CUDA is not enabled in Umpire!"
44 #if defined(MFEM_USE_HIP) && !defined(UMPIRE_ENABLE_HIP)
45 #error "HIP is not enabled in Umpire!"
47 #endif // MFEM_USE_UMPIRE
65 MFEM_VERIFY(
false,
"");
86 MFEM_ABORT(
"invalid MemoryClass");
95 "d_mt = " << (
int)d_mt);
121 MFEM_VERIFY(sync,
"");
139 return std::max(mc1, mc2);
166 mutable bool h_rw, d_rw;
168 h_ptr(p), d_ptr(nullptr), bytes(b), h_mt(h), d_mt(d),
169 h_rw(true), d_rw(true) { }
184 typedef std::unordered_map<const void*, Memory> MemoryMap;
185 typedef std::unordered_map<const void*, Alias> AliasMap;
195 static internal::Maps *maps;
201 class HostMemorySpace
204 virtual ~HostMemorySpace() { }
205 virtual void Alloc(
void **ptr,
size_t bytes) { *ptr = std::malloc(bytes); }
206 virtual void Dealloc(
void *ptr) { std::free(ptr); }
207 virtual void Protect(
const Memory&,
size_t) { }
208 virtual void Unprotect(
const Memory&,
size_t) { }
209 virtual void AliasProtect(
const void*,
size_t) { }
210 virtual void AliasUnprotect(
const void*,
size_t) { }
214 class DeviceMemorySpace
217 virtual ~DeviceMemorySpace() { }
218 virtual void Alloc(Memory &base) { base.d_ptr = std::malloc(base.bytes); }
219 virtual void Dealloc(Memory &base) { std::free(base.d_ptr); }
220 virtual void Protect(
const Memory&) { }
221 virtual void Unprotect(
const Memory&) { }
222 virtual void AliasProtect(
const void*,
size_t) { }
223 virtual void AliasUnprotect(
const void*,
size_t) { }
224 virtual void *HtoD(
void *dst,
const void *src,
size_t bytes)
225 {
return std::memcpy(dst, src, bytes); }
226 virtual void *DtoD(
void *dst,
const void *src,
size_t bytes)
227 {
return std::memcpy(dst, src, bytes); }
228 virtual void *DtoH(
void *dst,
const void *src,
size_t bytes)
229 {
return std::memcpy(dst, src, bytes); }
233 class StdHostMemorySpace :
public HostMemorySpace { };
236 struct NoHostMemorySpace :
public HostMemorySpace
238 void Alloc(
void**,
const size_t) {
mfem_error(
"! Host Alloc error"); }
242 class Aligned32HostMemorySpace :
public HostMemorySpace
245 Aligned32HostMemorySpace(): HostMemorySpace() { }
246 void Alloc(
void **ptr,
size_t bytes)
247 {
if (mfem_memalign(ptr, 32, bytes) != 0) { throw ::std::bad_alloc(); } }
248 void Dealloc(
void *ptr) { mfem_aligned_free(ptr); }
252 class Aligned64HostMemorySpace :
public HostMemorySpace
255 Aligned64HostMemorySpace(): HostMemorySpace() { }
256 void Alloc(
void **ptr,
size_t bytes)
257 {
if (mfem_memalign(ptr, 64, bytes) != 0) { throw ::std::bad_alloc(); } }
258 void Dealloc(
void *ptr) { mfem_aligned_free(ptr); }
262 static uintptr_t pagesize = 0;
263 static uintptr_t pagemask = 0;
266 inline const void *MmuAddrR(
const void *ptr)
268 const uintptr_t addr = (uintptr_t) ptr;
269 return (addr & pagemask) ? (
void*) ((addr + pagesize) & ~pagemask) : ptr;
273 inline const void *MmuAddrP(
const void *ptr)
275 const uintptr_t addr = (uintptr_t) ptr;
276 return (
void*) (addr & ~pagemask);
280 inline uintptr_t MmuLengthR(
const void *ptr,
const size_t bytes)
283 const uintptr_t
a = (uintptr_t) ptr;
284 const uintptr_t A = (uintptr_t) MmuAddrR(ptr);
285 MFEM_ASSERT(a <= A,
"");
286 const uintptr_t
b = a + bytes;
287 const uintptr_t B = b & ~pagemask;
288 MFEM_ASSERT(B <= b,
"");
289 const uintptr_t length = B > A ? B - A : 0;
290 MFEM_ASSERT(length % pagesize == 0,
"");
295 inline uintptr_t MmuLengthP(
const void *ptr,
const size_t bytes)
298 const uintptr_t a = (uintptr_t) ptr;
299 const uintptr_t A = (uintptr_t) MmuAddrP(ptr);
300 MFEM_ASSERT(A <= a,
"");
301 const uintptr_t
b = a + bytes;
302 const uintptr_t B = b & pagemask ? (b + pagesize) & ~pagemask : b;
303 MFEM_ASSERT(b <= B,
"");
304 MFEM_ASSERT(B >= A,
"");
305 const uintptr_t length = B - A;
306 MFEM_ASSERT(length % pagesize == 0,
"");
311 static void MmuError(
int, siginfo_t *si,
void*)
313 constexpr
size_t buf_size = 64;
316 const void *ptr = si->si_addr;
317 snprintf(str, buf_size,
"Error while accessing address %p!", ptr);
318 mfem::out << std::endl <<
"An illegal memory access was made!";
323 static void MmuInit()
325 if (pagesize > 0) {
return; }
327 sa.sa_flags = SA_SIGINFO;
328 sigemptyset(&sa.sa_mask);
329 sa.sa_sigaction = MmuError;
330 if (sigaction(SIGBUS, &sa, NULL) == -1) {
mfem_error(
"SIGBUS"); }
331 if (sigaction(SIGSEGV, &sa, NULL) == -1) {
mfem_error(
"SIGSEGV"); }
332 pagesize = (uintptr_t) sysconf(_SC_PAGE_SIZE);
333 MFEM_ASSERT(pagesize > 0,
"pagesize must not be less than 1");
334 pagemask = pagesize - 1;
338 inline void MmuAlloc(
void **ptr,
const size_t bytes)
340 const size_t length = bytes == 0 ? 8 : bytes;
341 const int prot = PROT_READ | PROT_WRITE;
342 const int flags = MAP_ANONYMOUS | MAP_PRIVATE;
343 *ptr = ::mmap(NULL, length, prot, flags, -1, 0);
344 if (*ptr == MAP_FAILED) { throw ::std::bad_alloc(); }
348 inline void MmuDealloc(
void *ptr,
const size_t bytes)
350 const size_t length = bytes == 0 ? 8 : bytes;
351 if (::munmap(ptr, length) == -1) {
mfem_error(
"Dealloc error!"); }
355 inline void MmuProtect(
const void *ptr,
const size_t bytes)
357 static const bool mmu_protect_error = getenv(
"MFEM_MMU_PROTECT_ERROR");
358 if (!::mprotect(const_cast<void*>(ptr), bytes, PROT_NONE)) {
return; }
359 if (mmu_protect_error) {
mfem_error(
"MMU protection (NONE) error"); }
363 inline void MmuAllow(
const void *ptr,
const size_t bytes)
365 const int RW = PROT_READ | PROT_WRITE;
366 static const bool mmu_protect_error = getenv(
"MFEM_MMU_PROTECT_ERROR");
367 if (!::mprotect(const_cast<void*>(ptr), bytes, RW)) {
return; }
368 if (mmu_protect_error) {
mfem_error(
"MMU protection (R/W) error"); }
371 inline void MmuInit() { }
372 inline void MmuAlloc(
void **ptr,
const size_t bytes) { *ptr = std::malloc(bytes); }
373 inline void MmuDealloc(
void *ptr,
const size_t) { std::free(ptr); }
374 inline void MmuProtect(
const void*,
const size_t) { }
375 inline void MmuAllow(
const void*,
const size_t) { }
376 inline const void *MmuAddrR(
const void *a) {
return a; }
377 inline const void *MmuAddrP(
const void *a) {
return a; }
378 inline uintptr_t MmuLengthR(
const void*,
const size_t) {
return 0; }
379 inline uintptr_t MmuLengthP(
const void*,
const size_t) {
return 0; }
383 class MmuHostMemorySpace :
public HostMemorySpace
386 MmuHostMemorySpace(): HostMemorySpace() { MmuInit(); }
387 void Alloc(
void **ptr,
size_t bytes) { MmuAlloc(ptr, bytes); }
388 void Dealloc(
void *ptr) { MmuDealloc(ptr, maps->memories.at(ptr).bytes); }
389 void Protect(
const Memory& mem,
size_t bytes)
390 {
if (mem.h_rw) { mem.h_rw =
false; MmuProtect(mem.h_ptr, bytes); } }
391 void Unprotect(
const Memory &mem,
size_t bytes)
392 {
if (!mem.h_rw) { mem.h_rw =
true; MmuAllow(mem.h_ptr, bytes); } }
394 void AliasProtect(
const void *ptr,
size_t bytes)
395 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
397 void AliasUnprotect(
const void *ptr,
size_t bytes)
398 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
402 class UvmHostMemorySpace :
public HostMemorySpace
405 UvmHostMemorySpace(): HostMemorySpace() { }
406 void Alloc(
void **ptr,
size_t bytes) {
CuMallocManaged(ptr, bytes == 0 ? 8 : bytes); }
407 void Dealloc(
void *ptr) {
CuMemFree(ptr); }
411 class NoDeviceMemorySpace:
public DeviceMemorySpace
414 void Alloc(internal::Memory&) {
mfem_error(
"! Device Alloc"); }
415 void Dealloc(Memory&) {
mfem_error(
"! Device Dealloc"); }
416 void *HtoD(
void*,
const void*,
size_t) {
mfem_error(
"!HtoD");
return nullptr; }
417 void *DtoD(
void*,
const void*,
size_t) {
mfem_error(
"!DtoD");
return nullptr; }
418 void *DtoH(
void*,
const void*,
size_t) {
mfem_error(
"!DtoH");
return nullptr; }
422 class StdDeviceMemorySpace :
public DeviceMemorySpace { };
425 class CudaDeviceMemorySpace:
public DeviceMemorySpace
428 CudaDeviceMemorySpace(): DeviceMemorySpace() { }
429 void Alloc(Memory &base) {
CuMemAlloc(&base.d_ptr, base.bytes); }
430 void Dealloc(Memory &base) {
CuMemFree(base.d_ptr); }
431 void *HtoD(
void *dst,
const void *src,
size_t bytes)
433 void *DtoD(
void* dst,
const void* src,
size_t bytes)
435 void *DtoH(
void *dst,
const void *src,
size_t bytes)
440 class HostPinnedMemorySpace:
public HostMemorySpace
443 HostPinnedMemorySpace(): HostMemorySpace() { }
444 void Alloc(
void ** ptr,
size_t bytes)
override
453 void Dealloc(
void *ptr)
override
465 class HipDeviceMemorySpace:
public DeviceMemorySpace
468 HipDeviceMemorySpace(): DeviceMemorySpace() { }
469 void Alloc(Memory &base) {
HipMemAlloc(&base.d_ptr, base.bytes); }
470 void Dealloc(Memory &base) {
HipMemFree(base.d_ptr); }
471 void *HtoD(
void *dst,
const void *src,
size_t bytes)
473 void *DtoD(
void* dst,
const void* src,
size_t bytes)
478 void *DtoH(
void *dst,
const void *src,
size_t bytes)
483 class UvmCudaMemorySpace :
public DeviceMemorySpace
486 void Alloc(Memory &base) { base.d_ptr = base.h_ptr; }
487 void Dealloc(Memory&) { }
488 void *HtoD(
void *dst,
const void *src,
size_t bytes)
490 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
493 void *DtoD(
void* dst,
const void* src,
size_t bytes)
495 void *DtoH(
void *dst,
const void *src,
size_t bytes)
497 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
503 class MmuDeviceMemorySpace :
public DeviceMemorySpace
506 MmuDeviceMemorySpace(): DeviceMemorySpace() { }
507 void Alloc(Memory &m) { MmuAlloc(&m.d_ptr, m.bytes); }
508 void Dealloc(Memory &m) { MmuDealloc(m.d_ptr, m.bytes); }
509 void Protect(
const Memory &m)
510 {
if (m.d_rw) { m.d_rw =
false; MmuProtect(m.d_ptr, m.bytes); } }
511 void Unprotect(
const Memory &m)
512 {
if (!m.d_rw) { m.d_rw =
true; MmuAllow(m.d_ptr, m.bytes); } }
514 void AliasProtect(
const void *ptr,
size_t bytes)
515 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
517 void AliasUnprotect(
const void *ptr,
size_t bytes)
518 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
519 void *HtoD(
void *dst,
const void *src,
size_t bytes)
520 {
return std::memcpy(dst, src, bytes); }
521 void *DtoD(
void *dst,
const void *src,
size_t bytes)
522 {
return std::memcpy(dst, src, bytes); }
523 void *DtoH(
void *dst,
const void *src,
size_t bytes)
524 {
return std::memcpy(dst, src, bytes); }
527 #ifdef MFEM_USE_UMPIRE
528 class UmpireMemorySpace
531 umpire::ResourceManager &rm;
532 umpire::Allocator allocator;
533 bool owns_allocator{
false};
537 virtual ~UmpireMemorySpace() {
if (owns_allocator) { allocator.release(); } }
538 UmpireMemorySpace(
const char * name,
const char *
space)
539 : rm(umpire::ResourceManager::getInstance())
541 if (!rm.isAllocator(name))
543 allocator = rm.makeAllocator<umpire::strategy::QuickPool>(
544 name, rm.getAllocator(space));
545 owns_allocator =
true;
549 allocator = rm.getAllocator(name);
550 owns_allocator =
false;
556 class UmpireHostMemorySpace :
public HostMemorySpace,
public UmpireMemorySpace
559 umpire::strategy::AllocationStrategy *strat;
561 UmpireHostMemorySpace(
const char * name)
563 UmpireMemorySpace(name,
"HOST"),
564 strat(allocator.getAllocationStrategy()) {}
565 void Alloc(
void **ptr,
size_t bytes)
override
566 { *ptr = allocator.allocate(bytes); }
567 void Dealloc(
void *ptr)
override { allocator.deallocate(ptr); }
568 void Insert(
void *ptr,
size_t bytes)
569 { rm.registerAllocation(ptr, {ptr, bytes, strat}); }
573 #if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
574 class UmpireDeviceMemorySpace :
public DeviceMemorySpace,
575 public UmpireMemorySpace
578 UmpireDeviceMemorySpace(
const char * name)
579 : DeviceMemorySpace(),
580 UmpireMemorySpace(name,
"DEVICE") {}
581 void Alloc(Memory &base)
override
582 { base.d_ptr = allocator.allocate(base.bytes); }
583 void Dealloc(Memory &base)
override { rm.deallocate(base.d_ptr); }
584 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
594 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
607 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
619 class UmpireDeviceMemorySpace :
public NoDeviceMemorySpace
622 UmpireDeviceMemorySpace(
const char * ) {}
624 #endif // MFEM_USE_CUDA || MFEM_USE_HIP
625 #endif // MFEM_USE_UMPIRE
637 Ctrl(): host{
nullptr}, device{
nullptr} { }
643 mfem_error(
"Memory backends have already been configured!");
649 host[
static_cast<int>(
MT::HOST)] =
new StdHostMemorySpace();
650 host[
static_cast<int>(
MT::HOST_32)] =
new Aligned32HostMemorySpace();
651 host[
static_cast<int>(
MT::HOST_64)] =
new Aligned64HostMemorySpace();
655 host[
static_cast<int>(
MT::MANAGED)] =
new UvmHostMemorySpace();
659 device[
static_cast<int>(
MT::MANAGED)-shift] =
new UvmCudaMemorySpace();
669 const int mt_i =
static_cast<int>(mt);
671 if (!host[mt_i]) { host[mt_i] = NewHostCtrl(mt); }
672 MFEM_ASSERT(host[mt_i],
"Host memory controller is not configured!");
676 DeviceMemorySpace* Device(
const MemoryType mt)
679 MFEM_ASSERT(mt_i >= 0,
"");
681 if (!device[mt_i]) { device[mt_i] = NewDeviceCtrl(mt); }
682 MFEM_ASSERT(device[mt_i],
"Memory manager has not been configured!");
691 for (
int mt = mt_d; mt <
MemoryTypeSize; mt++) {
delete device[mt-mt_d]; }
695 HostMemorySpace* NewHostCtrl(
const MemoryType mt)
700 #ifdef MFEM_USE_UMPIRE
702 return new UmpireHostMemorySpace(
708 default: MFEM_ABORT(
"Unknown host memory controller!");
713 DeviceMemorySpace* NewDeviceCtrl(
const MemoryType mt)
717 #ifdef MFEM_USE_UMPIRE
719 return new UmpireDeviceMemorySpace(
722 return new UmpireDeviceMemorySpace(
731 #if defined(MFEM_USE_CUDA)
732 return new CudaDeviceMemorySpace();
733 #elif defined(MFEM_USE_HIP)
734 return new HipDeviceMemorySpace();
736 MFEM_ABORT(
"No device memory controller!");
740 default: MFEM_ABORT(
"Unknown device memory controller!");
748 static internal::Ctrl *ctrl;
750 void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType mt,
753 MFEM_ASSERT(exists,
"Internal error!");
772 void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType h_mt,
776 MFEM_ASSERT(exists,
"Internal error!");
777 MFEM_ASSERT(
IsHostMemory(h_mt),
"h_mt must be host type");
780 "d_mt must be device type, the same is h_mt, or DEFAULT");
787 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
788 else { h_ptr = h_tmp; }
792 mm.Insert(h_ptr, bytes, h_mt, d_mt);
796 CheckHostMemoryType_(h_mt, h_ptr,
false);
801 void *MemoryManager::Register_(
void *ptr,
void *h_tmp,
size_t bytes,
803 bool own,
bool alias,
unsigned &flags)
805 MFEM_CONTRACT_VAR(alias);
806 MFEM_ASSERT(exists,
"Internal error!");
807 MFEM_VERIFY(!alias,
"Cannot register an alias!");
815 MFEM_VERIFY_TYPES(h_mt, d_mt);
817 if (ptr ==
nullptr && h_tmp ==
nullptr)
819 MFEM_VERIFY(bytes == 0,
"internal error");
829 mm.Insert(h_ptr, bytes, h_mt, d_mt);
830 flags = (own ? flags |
Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST) |
835 MFEM_VERIFY(ptr || bytes == 0,
836 "cannot register NULL device pointer with bytes = " << bytes);
837 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
838 else { h_ptr = h_tmp; }
839 mm.InsertDevice(ptr, h_ptr, bytes, h_mt, d_mt);
843 CheckHostMemoryType_(h_mt, h_ptr, alias);
847 void MemoryManager::Register2_(
void *h_ptr,
void *d_ptr,
size_t bytes,
849 bool own,
bool alias,
unsigned &flags)
851 MFEM_CONTRACT_VAR(alias);
852 MFEM_ASSERT(exists,
"Internal error!");
853 MFEM_ASSERT(!alias,
"Cannot register an alias!");
854 MFEM_VERIFY_TYPES(h_mt, d_mt);
856 if (h_ptr ==
nullptr && d_ptr ==
nullptr)
858 MFEM_VERIFY(bytes == 0,
"internal error");
864 MFEM_VERIFY(d_ptr || bytes == 0,
865 "cannot register NULL device pointer with bytes = " << bytes);
866 mm.InsertDevice(d_ptr, h_ptr, bytes, h_mt, d_mt);
871 CheckHostMemoryType_(h_mt, h_ptr, alias);
874 void MemoryManager::Alias_(
void *base_h_ptr,
size_t offset,
size_t bytes,
875 unsigned base_flags,
unsigned &flags)
877 mm.InsertAlias(base_h_ptr, (
char*)base_h_ptr + offset, bytes,
883 void MemoryManager::SetDeviceMemoryType_(
void *h_ptr,
unsigned flags,
886 MFEM_VERIFY(h_ptr,
"cannot set the device memory type: Memory is empty!");
887 if (!(flags & Mem::ALIAS))
889 auto mem_iter = maps->memories.find(h_ptr);
890 MFEM_VERIFY(mem_iter != maps->memories.end(),
"internal error");
891 internal::Memory &mem = mem_iter->second;
892 if (mem.d_mt == d_mt) {
return; }
893 MFEM_VERIFY(mem.d_ptr ==
nullptr,
"cannot set the device memory type:"
894 " device memory is allocated!");
899 auto alias_iter = maps->aliases.find(h_ptr);
900 MFEM_VERIFY(alias_iter != maps->aliases.end(),
"internal error");
901 internal::Alias &alias = alias_iter->second;
902 internal::Memory &base_mem = *alias.mem;
903 if (base_mem.d_mt == d_mt) {
return; }
904 MFEM_VERIFY(base_mem.d_ptr ==
nullptr,
905 "cannot set the device memory type:"
906 " alias' base device memory is allocated!");
907 base_mem.d_mt = d_mt;
918 MFEM_ASSERT(
IsHostMemory(h_mt),
"invalid h_mt = " << (
int)h_mt);
920 MFEM_ASSERT(!owns_device || owns_internal,
"invalid Memory state");
925 MFEM_ASSERT(registered || !(owns_host || owns_device || owns_internal) ||
926 (!(owns_device || owns_internal) && h_ptr ==
nullptr),
927 "invalid Memory state");
928 if (!
mm.exists || !registered) {
return h_mt; }
934 MFEM_ASSERT(h_mt == maps->aliases.at(h_ptr).h_mt,
"");
935 mm.EraseAlias(h_ptr);
941 { ctrl->Host(h_mt)->Dealloc(h_ptr); }
945 MFEM_ASSERT(h_mt == maps->memories.at(h_ptr).h_mt,
"");
946 mm.Erase(h_ptr, owns_device);
952 void MemoryManager::DeleteDevice_(
void *h_ptr,
unsigned & flags)
957 mm.EraseDevice(h_ptr);
962 bool MemoryManager::MemoryClassCheck_(
MemoryClass mc,
void *h_ptr,
968 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
972 if (!(flags & Mem::ALIAS))
974 auto iter = maps->memories.find(h_ptr);
975 MFEM_VERIFY(iter != maps->memories.end(),
"internal error");
976 d_mt = iter->second.d_mt;
980 auto iter = maps->aliases.find(h_ptr);
981 MFEM_VERIFY(iter != maps->aliases.end(),
"internal error");
982 d_mt = iter->second.mem->d_mt;
1019 size_t bytes,
unsigned &flags)
1021 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
1022 if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,
""); }
1023 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1028 if (flags & Mem::ALIAS)
1029 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1030 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1036 if (flags & Mem::ALIAS)
1037 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1038 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1043 size_t bytes,
unsigned &flags)
1045 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
1046 if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,
""); }
1047 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1052 if (flags & Mem::ALIAS)
1053 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1054 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1060 if (flags & Mem::ALIAS)
1061 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1062 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1067 size_t bytes,
unsigned &flags)
1069 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
1070 if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,
""); }
1071 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1075 if (flags & Mem::ALIAS)
1076 {
return mm.GetAliasHostPtr(h_ptr, bytes,
false); }
1077 else {
return mm.GetHostPtr(h_ptr, bytes,
false); }
1082 if (flags & Mem::ALIAS)
1083 {
return mm.GetAliasDevicePtr(h_ptr, bytes,
false); }
1084 else {
return mm.GetDevicePtr(h_ptr, bytes,
false); }
1088 void MemoryManager::SyncAlias_(
const void *base_h_ptr,
void *alias_h_ptr,
1089 size_t alias_bytes,
unsigned base_flags,
1090 unsigned &alias_flags)
1094 MFEM_ASSERT(alias_flags & Mem::ALIAS,
"not an alias");
1095 if ((base_flags &
Mem::VALID_HOST) && !(alias_flags & Mem::VALID_HOST))
1097 mm.GetAliasHostPtr(alias_h_ptr, alias_bytes,
true);
1101 if (!(alias_flags & Mem::REGISTERED))
1103 mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags & Mem::ALIAS);
1105 ~(Mem::OWNS_HOST | Mem::OWNS_DEVICE);
1107 mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes,
true);
1113 MemoryType MemoryManager::GetDeviceMemoryType_(
void *h_ptr,
bool alias)
1119 auto iter = maps->memories.find(h_ptr);
1120 MFEM_ASSERT(iter != maps->memories.end(),
"internal error");
1121 return iter->second.d_mt;
1124 auto iter = maps->aliases.find(h_ptr);
1125 MFEM_ASSERT(iter != maps->aliases.end(),
"internal error");
1126 return iter->second.mem->d_mt;
1128 MFEM_ABORT(
"internal error");
1129 return MemoryManager::host_mem_type;
1132 MemoryType MemoryManager::GetHostMemoryType_(
void *h_ptr)
1134 if (!
mm.exists) {
return MemoryManager::host_mem_type; }
1135 if (
mm.
IsKnown(h_ptr)) {
return maps->memories.at(h_ptr).h_mt; }
1136 if (
mm.
IsAlias(h_ptr)) {
return maps->aliases.at(h_ptr).h_mt; }
1137 return MemoryManager::host_mem_type;
1140 void MemoryManager::Copy_(
void *dst_h_ptr,
const void *src_h_ptr,
1141 size_t bytes,
unsigned src_flags,
1142 unsigned &dst_flags)
1152 const bool dst_on_host =
1154 (!(dst_flags & Mem::VALID_DEVICE) ||
1157 dst_flags = dst_flags &
1160 const bool src_on_host =
1162 (!(src_flags & Mem::VALID_DEVICE) ||
1165 const void *src_d_ptr =
1166 src_on_host ? NULL :
1168 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1169 mm.GetDevicePtr(src_h_ptr, bytes,
false));
1175 if (dst_h_ptr != src_h_ptr && bytes != 0)
1177 MFEM_ASSERT((
const char*)dst_h_ptr + bytes <= src_h_ptr ||
1178 (
const char*)src_h_ptr + bytes <= dst_h_ptr,
1180 std::memcpy(dst_h_ptr, src_h_ptr, bytes);
1185 if (dst_h_ptr != src_d_ptr && bytes != 0)
1187 internal::Memory &src_d_base = maps->memories.at(src_h_ptr);
1189 ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
1195 void *dest_d_ptr = (dst_flags &
Mem::ALIAS) ?
1196 mm.GetAliasDevicePtr(dst_h_ptr, bytes,
false) :
1197 mm.GetDevicePtr(dst_h_ptr, bytes,
false);
1200 const bool known =
mm.
IsKnown(dst_h_ptr);
1202 MFEM_VERIFY(alias||known,
"");
1204 maps->memories.at(dst_h_ptr).d_mt :
1205 maps->aliases.at(dst_h_ptr).mem->d_mt;
1206 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1210 if (dest_d_ptr != src_d_ptr && bytes != 0)
1212 const bool known =
mm.
IsKnown(dst_h_ptr);
1214 MFEM_VERIFY(alias||known,
"");
1216 maps->memories.at(dst_h_ptr).d_mt :
1217 maps->aliases.at(dst_h_ptr).mem->d_mt;
1218 ctrl->Device(d_mt)->DtoD(dest_d_ptr, src_d_ptr, bytes);
1224 void MemoryManager::CopyToHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1225 size_t bytes,
unsigned src_flags)
1230 if (dest_h_ptr != src_h_ptr && bytes != 0)
1232 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1233 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1235 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1240 MFEM_ASSERT(IsKnown_(src_h_ptr),
"internal error");
1241 const void *src_d_ptr = (src_flags &
Mem::ALIAS) ?
1242 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1243 mm.GetDevicePtr(src_h_ptr, bytes,
false);
1244 const internal::Memory &base = maps->memories.at(dest_h_ptr);
1246 ctrl->Device(d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
1250 void MemoryManager::CopyFromHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1251 size_t bytes,
unsigned &dest_flags)
1256 if (dest_h_ptr != src_h_ptr && bytes != 0)
1258 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1259 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1261 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1266 void *dest_d_ptr = (dest_flags &
Mem::ALIAS) ?
1267 mm.GetAliasDevicePtr(dest_h_ptr, bytes,
false) :
1268 mm.GetDevicePtr(dest_h_ptr, bytes,
false);
1269 const internal::Memory &base = maps->memories.at(dest_h_ptr);
1271 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1273 dest_flags = dest_flags &
1277 bool MemoryManager::IsKnown_(
const void *h_ptr)
1279 return maps->memories.find(h_ptr) != maps->memories.end();
1282 bool MemoryManager::IsAlias_(
const void *h_ptr)
1284 return maps->aliases.find(h_ptr) != maps->aliases.end();
1287 void MemoryManager::Insert(
void *h_ptr,
size_t bytes,
1290 #ifdef MFEM_TRACK_MEM_MANAGER
1291 mfem::out <<
"[mfem memory manager]: registering h_ptr: " << h_ptr
1292 <<
", bytes: " << bytes << std::endl;
1296 MFEM_VERIFY(bytes == 0,
"Trying to add NULL with size " << bytes);
1299 MFEM_VERIFY_TYPES(h_mt, d_mt);
1303 maps->memories.emplace(h_ptr, internal::Memory(h_ptr, bytes, h_mt, d_mt));
1305 if (res.second ==
false)
1307 auto &m = res.first->second;
1308 MFEM_VERIFY(m.bytes >= bytes && m.h_mt == h_mt &&
1311 "Address already present with different attributes!");
1312 #ifdef MFEM_TRACK_MEM_MANAGER
1313 mfem::out <<
"[mfem memory manager]: repeated registration of h_ptr: "
1314 << h_ptr << std::endl;
1320 void MemoryManager::InsertDevice(
void *d_ptr,
void *h_ptr,
size_t bytes,
1324 MFEM_ASSERT(h_ptr != NULL,
"internal error");
1325 Insert(h_ptr, bytes, h_mt, d_mt);
1326 internal::Memory &mem = maps->memories.at(h_ptr);
1327 if (d_ptr == NULL && bytes != 0) { ctrl->Device(d_mt)->Alloc(mem); }
1328 else { mem.d_ptr = d_ptr; }
1331 void MemoryManager::InsertAlias(
const void *base_ptr,
void *alias_ptr,
1332 const size_t bytes,
const bool base_is_alias)
1334 size_t offset =
static_cast<size_t>(
static_cast<const char*
>(alias_ptr) -
1335 static_cast<const char*>(base_ptr));
1336 #ifdef MFEM_TRACK_MEM_MANAGER
1337 mfem::out <<
"[mfem memory manager]: registering alias of base_ptr: "
1338 << base_ptr <<
", offset: " << offset <<
", bytes: " << bytes
1339 <<
", base is alias: " << base_is_alias << std::endl;
1343 MFEM_VERIFY(offset == 0,
1344 "Trying to add alias to NULL at offset " << offset);
1349 const internal::Alias &alias = maps->aliases.at(base_ptr);
1350 MFEM_ASSERT(alias.mem,
"");
1351 base_ptr = alias.mem->h_ptr;
1352 offset += alias.offset;
1353 #ifdef MFEM_TRACK_MEM_MANAGER
1354 mfem::out <<
"[mfem memory manager]: real base_ptr: " << base_ptr
1358 internal::Memory &mem = maps->memories.at(base_ptr);
1359 MFEM_VERIFY(offset + bytes <= mem.bytes,
"invalid alias");
1361 maps->aliases.emplace(alias_ptr,
1362 internal::Alias{&mem, offset, 1, mem.h_mt});
1363 if (res.second ==
false)
1365 internal::Alias &alias = res.first->second;
1368 alias.offset = offset;
1369 alias.h_mt = mem.h_mt;
1374 void MemoryManager::Erase(
void *h_ptr,
bool free_dev_ptr)
1376 #ifdef MFEM_TRACK_MEM_MANAGER
1377 mfem::out <<
"[mfem memory manager]: un-registering h_ptr: " << h_ptr
1380 if (!h_ptr) {
return; }
1381 auto mem_map_iter = maps->memories.find(h_ptr);
1382 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1383 internal::Memory &mem = mem_map_iter->second;
1384 if (mem.d_ptr && free_dev_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1385 maps->memories.erase(mem_map_iter);
1388 void MemoryManager::EraseDevice(
void *h_ptr)
1390 if (!h_ptr) {
return; }
1391 auto mem_map_iter = maps->memories.find(h_ptr);
1392 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1393 internal::Memory &mem = mem_map_iter->second;
1394 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1395 mem.d_ptr =
nullptr;
1398 void MemoryManager::EraseAlias(
void *alias_ptr)
1400 #ifdef MFEM_TRACK_MEM_MANAGER
1401 mfem::out <<
"[mfem memory manager]: un-registering alias_ptr: " << alias_ptr
1404 if (!alias_ptr) {
return; }
1405 auto alias_map_iter = maps->aliases.find(alias_ptr);
1406 if (alias_map_iter == maps->aliases.end()) {
mfem_error(
"Unknown alias!"); }
1407 internal::Alias &alias = alias_map_iter->second;
1408 if (--alias.counter) {
return; }
1409 maps->aliases.erase(alias_map_iter);
1412 void *MemoryManager::GetDevicePtr(
const void *h_ptr,
size_t bytes,
1417 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1420 internal::Memory &mem = maps->memories.at(h_ptr);
1423 MFEM_VERIFY_TYPES(h_mt, d_mt);
1427 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1430 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1433 MFEM_ASSERT(bytes <= mem.bytes,
"invalid copy size");
1434 if (bytes) { ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes); }
1436 ctrl->Host(h_mt)->Protect(mem, bytes);
1440 void *MemoryManager::GetAliasDevicePtr(
const void *alias_ptr,
size_t bytes,
1445 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1448 auto &alias_map = maps->aliases;
1449 auto alias_map_iter = alias_map.find(alias_ptr);
1450 if (alias_map_iter == alias_map.end()) {
mfem_error(
"alias not found"); }
1451 const internal::Alias &alias = alias_map_iter->second;
1452 const size_t offset = alias.offset;
1453 internal::Memory &mem = *alias.mem;
1456 MFEM_VERIFY_TYPES(h_mt, d_mt);
1460 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1462 void *alias_h_ptr =
static_cast<char*
>(mem.h_ptr) + offset;
1463 void *alias_d_ptr =
static_cast<char*
>(mem.d_ptr) + offset;
1464 MFEM_ASSERT(alias_h_ptr == alias_ptr,
"internal error");
1465 MFEM_ASSERT(offset + bytes <= mem.bytes,
"internal error");
1466 mem.d_rw = mem.h_rw =
false;
1467 if (mem.d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1468 ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
1469 if (copy && mem.d_ptr)
1470 { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
1471 ctrl->Host(h_mt)->AliasProtect(alias_ptr, bytes);
1475 void *MemoryManager::GetHostPtr(
const void *ptr,
size_t bytes,
bool copy)
1477 const internal::Memory &mem = maps->memories.at(ptr);
1478 MFEM_ASSERT(mem.h_ptr == ptr,
"internal error");
1479 MFEM_ASSERT(bytes <= mem.bytes,
"internal error")
1482 MFEM_VERIFY_TYPES(h_mt, d_mt);
1484 ctrl->Host(h_mt)->Unprotect(mem, bytes);
1485 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1486 if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
1487 if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
1491 void *MemoryManager::GetAliasHostPtr(
const void *ptr,
size_t bytes,
1494 const internal::Alias &alias = maps->aliases.at(ptr);
1495 const internal::Memory *
const mem = alias.mem;
1498 MFEM_VERIFY_TYPES(h_mt, d_mt);
1499 void *alias_h_ptr =
static_cast<char*
>(mem->h_ptr) + alias.offset;
1500 void *alias_d_ptr = static_cast<char*>(mem->d_ptr) + alias.offset;
1501 MFEM_ASSERT(alias_h_ptr == ptr,
"internal error");
1503 ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
1504 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1505 if (copy_data && mem->d_ptr)
1506 { ctrl->Device(d_mt)->DtoH(const_cast<void*>(ptr), alias_d_ptr, bytes); }
1507 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasProtect(alias_d_ptr, bytes); }
1513 if (exists) {
return; }
1514 maps =
new internal::Maps();
1515 ctrl =
new internal::Ctrl();
1526 MFEM_VERIFY(!configured,
"changing the dual MemoryTypes is not allowed after"
1527 " MemoryManager configuration!");
1528 UpdateDualMemoryType(mt, dual_mt);
1534 "invalid MemoryType, mt = " << (
int)mt);
1536 "invalid dual MemoryType, dual_mt = " << (
int)dual_mt);
1541 dual_map[(int)mt] = dual_mt;
1549 "invalid (mt, dual_mt) pair: ("
1558 MemoryManager::UpdateDualMemoryType(host_mt, device_mt);
1559 MemoryManager::UpdateDualMemoryType(device_mt, host_mt);
1564 MemoryManager::UpdateDualMemoryType(
1569 host_mem_type = host_mt;
1570 device_mem_type = device_mt;
1576 MFEM_VERIFY(exists,
"MemoryManager has already been destroyed!");
1577 #ifdef MFEM_TRACK_MEM_MANAGER
1578 size_t num_memories = maps->memories.size();
1579 size_t num_aliases = maps->aliases.size();
1580 if (num_memories != 0 || num_aliases != 0)
1582 MFEM_WARNING(
"...\n\t number of registered pointers: " << num_memories
1583 <<
"\n\t number of registered aliases : " << num_aliases);
1588 mfem::out <<
"Destroying the MemoryManager ...\n"
1589 <<
"remaining registered pointers : "
1590 << maps->memories.size() <<
'\n'
1591 <<
"remaining registered aliases : "
1592 << maps->aliases.size() <<
'\n';
1594 for (
auto& n : maps->memories)
1596 internal::Memory &mem = n.second;
1598 if (mem_h_ptr) { ctrl->Host(mem.h_mt)->Dealloc(mem.h_ptr); }
1599 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem); }
1601 delete maps; maps =
nullptr;
1602 delete ctrl; ctrl =
nullptr;
1623 for (
const auto& n : maps->memories)
1625 const internal::Memory &mem = n.second;
1626 os <<
"\nkey " << n.first <<
", "
1627 <<
"h_ptr " << mem.h_ptr <<
", "
1628 <<
"d_ptr " << mem.d_ptr;
1631 if (maps->memories.size() > 0) { os << std::endl; }
1638 for (
const auto& n : maps->aliases)
1640 const internal::Alias &alias = n.second;
1641 os <<
"\nalias: key " << n.first <<
", "
1642 <<
"h_ptr " << alias.mem->h_ptr <<
", "
1643 <<
"offset " << alias.offset <<
", "
1644 <<
"counter " << alias.counter;
1647 if (maps->aliases.size() > 0) { os << std::endl; }
1651 int MemoryManager::CompareHostAndDevice_(
void *h_ptr,
size_t size,
1655 mm.GetAliasDevicePtr(h_ptr, size,
false) :
1656 mm.GetDevicePtr(h_ptr, size,
false);
1657 char *h_buf =
new char[size];
1658 #if defined(MFEM_USE_CUDA)
1660 #elif defined(MFEM_USE_HIP)
1663 std::memcpy(h_buf, d_ptr, size);
1665 int res = std::memcmp(h_ptr, h_buf, size);
1675 <<
"\n registered = " << bool(flags & Mem::REGISTERED)
1676 <<
"\n owns host = " << bool(flags & Mem::OWNS_HOST)
1677 <<
"\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
1678 <<
"\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
1679 <<
"\n valid host = " << bool(flags & Mem::VALID_HOST)
1680 <<
"\n valid device = " << bool(flags & Mem::VALID_DEVICE)
1681 <<
"\n device flag = " << bool(flags & Mem::USE_DEVICE)
1682 <<
"\n alias = " << bool(flags & Mem::ALIAS)
1686 void MemoryManager::CheckHostMemoryType_(
MemoryType h_mt,
void *h_ptr,
1689 if (!
mm.exists) {
return;}
1692 auto it = maps->memories.find(h_ptr);
1693 MFEM_VERIFY(it != maps->memories.end(),
1694 "host pointer is not registered: h_ptr = " << h_ptr);
1695 MFEM_VERIFY(h_mt == it->second.h_mt,
"host pointer MemoryType mismatch");
1699 auto it = maps->aliases.find(h_ptr);
1700 MFEM_VERIFY(it != maps->aliases.end(),
1701 "alias pointer is not registered: h_ptr = " << h_ptr);
1702 MFEM_VERIFY(h_mt == it->second.h_mt,
"alias pointer MemoryType mismatch");
1708 bool MemoryManager::exists =
false;
1709 bool MemoryManager::configured =
false;
1726 MemoryType::HOST_UMPIRE
1729 #ifdef MFEM_USE_UMPIRE
1730 const char * MemoryManager::h_umpire_name =
"MFEM_HOST";
1731 const char * MemoryManager::d_umpire_name =
"MFEM_DEVICE";
1732 const char * MemoryManager::d_umpire_2_name =
"MFEM_DEVICE_2";
1738 "host-std",
"host-32",
"host-64",
"host-debug",
"host-umpire",
"host-pinned",
1739 #if defined(MFEM_USE_CUDA)
1742 #elif defined(MFEM_USE_HIP)
1750 #if defined(MFEM_USE_CUDA)
1753 #elif defined(MFEM_USE_HIP)
void * CuMemcpyHtoD(void *dst, const void *src, size_t bytes)
Copies memory from Host to Device and returns destination ptr.
void * CuMemFree(void *dptr)
Frees device memory and returns destination ptr.
Host memory; aligned at 64 bytes.
bool IsHostMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::HOST.
Device memory; using CUDA or HIP *Malloc and *Free.
void * CuMemFreeHostPinned(void *ptr)
Frees page-locked (pinned) host memory and returns destination ptr.
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.
static MemoryType GetHostMemoryType()
Host memory; allocated from a "host-debug" pool.
void Configure(const MemoryType h_mt, const MemoryType d_mt)
Configure the Memory manager with given default host and device types. This method will be called whe...
Host memory: pinned (page-locked)
int PrintAliases(std::ostream &out=mfem::out)
int CompareHostAndDevice(int size) const
If both the host and the device data are valid, compare their contents.
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.
void * HipMemcpyDtoDAsync(void *dst, const void *src, size_t bytes)
Copies memory from Device to Device.
void * HipMemFreeHostPinned(void *ptr)
Frees page-locked (pinned) host memory and returns destination ptr.
void * CuMallocManaged(void **dptr, size_t bytes)
Allocates managed device memory.
Host memory; aligned at 32 bytes.
static MemoryType GetDualMemoryType(MemoryType mt)
Return the dual MemoryType of the given one, mt.
constexpr int DeviceMemoryType
static const char * GetUmpireDeviceAllocatorName()
Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE.
void * HipMemAllocHostPinned(void **ptr, size_t bytes)
Allocates page-locked (pinned) host memory.
constexpr int HostMemoryType
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
static MemoryType GetDeviceMemoryType()
void * HipMemFree(void *dptr)
Frees device memory.
Ownership flag for internal Memory data.
void Destroy()
Free all the device memories.
int PrintPtrs(std::ostream &out=mfem::out)
The host pointer will be deleted by Delete()
void * CuMemcpyDtoD(void *dst, const void *src, size_t bytes)
Copies memory from Device to Device.
void RegisterCheck(void *h_ptr)
Check if the host pointer has been registered in the memory manager.
constexpr int MemoryTypeSize
Static casts to 'int' and sizes of some useful memory types.
void * HipMemcpyDtoH(void *dst, const void *src, size_t bytes)
Copies memory from Device to Host.
static const char * GetUmpireDevice2AllocatorName()
Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2.
void * HipMemAlloc(void **dptr, size_t bytes)
Allocates device memory.
double p(const Vector &x, double t)
static void SetDualMemoryType(MemoryType mt, MemoryType dual_mt)
Set the dual memory type of mt to be dual_mt.
void Init()
Initialize the memory manager.
MemoryType
Memory types supported by MFEM.
bool IsKnown(const void *h_ptr)
Return true if the pointer is known by the memory manager.
constexpr int HostMemoryTypeSize
bool IsDeviceMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::DEVICE.
MemoryManager mm
The (single) global memory manager object.
Host memory; using new[] and delete[].
void * HipMemcpyHtoD(void *dst, const void *src, size_t bytes)
Copies memory from Host to Device.
MemoryType GetMemoryType(MemoryClass mc)
Return a suitable MemoryType for a given MemoryClass.
void * CuMemAllocHostPinned(void **ptr, size_t bytes)
Allocates page-locked (pinned) host memory.
constexpr int DeviceMemoryTypeSize
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
MemoryClass operator*(MemoryClass mc1, MemoryClass mc2)
Return a suitable MemoryClass from a pair of MemoryClasses.
void * CuMemAlloc(void **dptr, size_t bytes)
Allocates device memory and returns destination ptr.
MemoryClass
Memory classes identify sets of memory types.
void * CuMemcpyDtoH(void *dst, const void *src, size_t bytes)
Copies memory from Device to Host.
void MemoryPrintFlags(unsigned flags)
Print the state of a Memory object based on its internal flags. Useful in a debugger. See also Memory<T>::PrintFlags().