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!");
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;
911 void MemoryManager::Delete_(
void *h_ptr,
MemoryType h_mt,
unsigned flags)
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; }
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);
951 void MemoryManager::DeleteDevice_(
void *h_ptr,
unsigned & flags)
956 mm.EraseDevice(h_ptr);
961 bool MemoryManager::MemoryClassCheck_(
MemoryClass mc,
void *h_ptr,
967 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
973 auto iter = maps->memories.find(h_ptr);
974 MFEM_VERIFY(iter != maps->memories.end(),
"internal error");
975 d_mt = iter->second.d_mt;
979 auto iter = maps->aliases.find(h_ptr);
980 MFEM_VERIFY(iter != maps->aliases.end(),
"internal error");
981 d_mt = iter->second.mem->d_mt;
1018 size_t bytes,
unsigned &flags)
1020 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1022 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1028 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1029 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1036 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1037 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1042 size_t bytes,
unsigned &flags)
1044 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1046 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1052 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1053 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1060 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1061 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1066 size_t bytes,
unsigned &flags)
1068 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1070 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1075 {
return mm.GetAliasHostPtr(h_ptr, bytes,
false); }
1076 else {
return mm.GetHostPtr(h_ptr, bytes,
false); }
1082 {
return mm.GetAliasDevicePtr(h_ptr, bytes,
false); }
1083 else {
return mm.GetDevicePtr(h_ptr, bytes,
false); }
1087 void MemoryManager::SyncAlias_(
const void *base_h_ptr,
void *alias_h_ptr,
1088 size_t alias_bytes,
unsigned base_flags,
1089 unsigned &alias_flags)
1093 MFEM_ASSERT(alias_flags &
Mem::ALIAS,
"not an alias");
1096 mm.GetAliasHostPtr(alias_h_ptr, alias_bytes,
true);
1102 mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags &
Mem::ALIAS);
1106 mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes,
true);
1112 MemoryType MemoryManager::GetDeviceMemoryType_(
void *h_ptr,
bool alias)
1118 auto iter = maps->memories.find(h_ptr);
1119 MFEM_ASSERT(iter != maps->memories.end(),
"internal error");
1120 return iter->second.d_mt;
1123 auto iter = maps->aliases.find(h_ptr);
1124 MFEM_ASSERT(iter != maps->aliases.end(),
"internal error");
1125 return iter->second.mem->d_mt;
1127 MFEM_ABORT(
"internal error");
1128 return MemoryManager::host_mem_type;
1131 MemoryType MemoryManager::GetHostMemoryType_(
void *h_ptr)
1133 if (!
mm.exists) {
return MemoryManager::host_mem_type; }
1134 if (
mm.
IsKnown(h_ptr)) {
return maps->memories.at(h_ptr).h_mt; }
1135 if (
mm.
IsAlias(h_ptr)) {
return maps->aliases.at(h_ptr).h_mt; }
1136 return MemoryManager::host_mem_type;
1139 void MemoryManager::Copy_(
void *dst_h_ptr,
const void *src_h_ptr,
1140 size_t bytes,
unsigned src_flags,
1141 unsigned &dst_flags)
1151 const bool dst_on_host =
1156 dst_flags = dst_flags &
1159 const bool src_on_host =
1164 const void *src_d_ptr =
1165 src_on_host ? NULL :
1167 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1168 mm.GetDevicePtr(src_h_ptr, bytes,
false));
1174 if (dst_h_ptr != src_h_ptr && bytes != 0)
1176 MFEM_ASSERT((
const char*)dst_h_ptr + bytes <= src_h_ptr ||
1177 (
const char*)src_h_ptr + bytes <= dst_h_ptr,
1179 std::memcpy(dst_h_ptr, src_h_ptr, bytes);
1184 if (dst_h_ptr != src_d_ptr && bytes != 0)
1186 internal::Memory &src_d_base = maps->memories.at(src_h_ptr);
1188 ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
1194 void *dest_d_ptr = (dst_flags &
Mem::ALIAS) ?
1195 mm.GetAliasDevicePtr(dst_h_ptr, bytes,
false) :
1196 mm.GetDevicePtr(dst_h_ptr, bytes,
false);
1199 const bool known =
mm.
IsKnown(dst_h_ptr);
1201 MFEM_VERIFY(alias||known,
"");
1203 maps->memories.at(dst_h_ptr).d_mt :
1204 maps->aliases.at(dst_h_ptr).mem->d_mt;
1205 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1209 if (dest_d_ptr != src_d_ptr && bytes != 0)
1211 const bool known =
mm.
IsKnown(dst_h_ptr);
1213 MFEM_VERIFY(alias||known,
"");
1215 maps->memories.at(dst_h_ptr).d_mt :
1216 maps->aliases.at(dst_h_ptr).mem->d_mt;
1217 ctrl->Device(d_mt)->DtoD(dest_d_ptr, src_d_ptr, bytes);
1223 void MemoryManager::CopyToHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1224 size_t bytes,
unsigned src_flags)
1229 if (dest_h_ptr != src_h_ptr && bytes != 0)
1231 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1232 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1234 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1239 MFEM_ASSERT(IsKnown_(src_h_ptr),
"internal error");
1240 const void *src_d_ptr = (src_flags &
Mem::ALIAS) ?
1241 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1242 mm.GetDevicePtr(src_h_ptr, bytes,
false);
1243 const internal::Memory &base = maps->memories.at(dest_h_ptr);
1245 ctrl->Device(d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
1249 void MemoryManager::CopyFromHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1250 size_t bytes,
unsigned &dest_flags)
1255 if (dest_h_ptr != src_h_ptr && bytes != 0)
1257 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1258 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1260 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1265 void *dest_d_ptr = (dest_flags &
Mem::ALIAS) ?
1266 mm.GetAliasDevicePtr(dest_h_ptr, bytes,
false) :
1267 mm.GetDevicePtr(dest_h_ptr, bytes,
false);
1268 const internal::Memory &base = maps->memories.at(dest_h_ptr);
1270 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1272 dest_flags = dest_flags &
1276 bool MemoryManager::IsKnown_(
const void *h_ptr)
1278 return maps->memories.find(h_ptr) != maps->memories.end();
1281 bool MemoryManager::IsAlias_(
const void *h_ptr)
1283 return maps->aliases.find(h_ptr) != maps->aliases.end();
1286 void MemoryManager::Insert(
void *h_ptr,
size_t bytes,
1289 #ifdef MFEM_TRACK_MEM_MANAGER 1290 mfem::out <<
"[mfem memory manager]: registering h_ptr: " << h_ptr
1291 <<
", bytes: " << bytes << std::endl;
1295 MFEM_VERIFY(bytes == 0,
"Trying to add NULL with size " << bytes);
1298 MFEM_VERIFY_TYPES(h_mt, d_mt);
1302 maps->memories.emplace(h_ptr, internal::Memory(h_ptr, bytes, h_mt, d_mt));
1304 if (res.second ==
false)
1306 auto &m = res.first->second;
1307 MFEM_VERIFY(m.bytes >= bytes && m.h_mt == h_mt &&
1310 "Address already present with different attributes!");
1311 #ifdef MFEM_TRACK_MEM_MANAGER 1312 mfem::out <<
"[mfem memory manager]: repeated registration of h_ptr: " 1313 << h_ptr << std::endl;
1319 void MemoryManager::InsertDevice(
void *d_ptr,
void *h_ptr,
size_t bytes,
1323 MFEM_ASSERT(h_ptr != NULL,
"internal error");
1324 Insert(h_ptr, bytes, h_mt, d_mt);
1325 internal::Memory &mem = maps->memories.at(h_ptr);
1326 if (d_ptr == NULL && bytes != 0) { ctrl->Device(d_mt)->Alloc(mem); }
1327 else { mem.d_ptr = d_ptr; }
1330 void MemoryManager::InsertAlias(
const void *base_ptr,
void *alias_ptr,
1331 const size_t bytes,
const bool base_is_alias)
1333 size_t offset =
static_cast<size_t>(
static_cast<const char*
>(alias_ptr) -
1334 static_cast<const char*>(base_ptr));
1335 #ifdef MFEM_TRACK_MEM_MANAGER 1336 mfem::out <<
"[mfem memory manager]: registering alias of base_ptr: " 1337 << base_ptr <<
", offset: " << offset <<
", bytes: " << bytes
1338 <<
", base is alias: " << base_is_alias << std::endl;
1342 MFEM_VERIFY(offset == 0,
1343 "Trying to add alias to NULL at offset " << offset);
1348 const internal::Alias &alias = maps->aliases.at(base_ptr);
1349 MFEM_ASSERT(alias.mem,
"");
1350 base_ptr = alias.mem->h_ptr;
1351 offset += alias.offset;
1352 #ifdef MFEM_TRACK_MEM_MANAGER 1353 mfem::out <<
"[mfem memory manager]: real base_ptr: " << base_ptr
1357 internal::Memory &mem = maps->memories.at(base_ptr);
1358 MFEM_VERIFY(offset + bytes <= mem.bytes,
"invalid alias");
1360 maps->aliases.emplace(alias_ptr,
1361 internal::Alias{&mem, offset, 1, mem.h_mt});
1362 if (res.second ==
false)
1364 internal::Alias &alias = res.first->second;
1367 alias.offset = offset;
1368 alias.h_mt = mem.h_mt;
1373 void MemoryManager::Erase(
void *h_ptr,
bool free_dev_ptr)
1375 #ifdef MFEM_TRACK_MEM_MANAGER 1376 mfem::out <<
"[mfem memory manager]: un-registering h_ptr: " << h_ptr
1379 if (!h_ptr) {
return; }
1380 auto mem_map_iter = maps->memories.find(h_ptr);
1381 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1382 internal::Memory &mem = mem_map_iter->second;
1383 if (mem.d_ptr && free_dev_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1384 maps->memories.erase(mem_map_iter);
1387 void MemoryManager::EraseDevice(
void *h_ptr)
1389 if (!h_ptr) {
return; }
1390 auto mem_map_iter = maps->memories.find(h_ptr);
1391 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1392 internal::Memory &mem = mem_map_iter->second;
1393 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1394 mem.d_ptr =
nullptr;
1397 void MemoryManager::EraseAlias(
void *alias_ptr)
1399 #ifdef MFEM_TRACK_MEM_MANAGER 1400 mfem::out <<
"[mfem memory manager]: un-registering alias_ptr: " << alias_ptr
1403 if (!alias_ptr) {
return; }
1404 auto alias_map_iter = maps->aliases.find(alias_ptr);
1405 if (alias_map_iter == maps->aliases.end()) {
mfem_error(
"Unknown alias!"); }
1406 internal::Alias &alias = alias_map_iter->second;
1407 if (--alias.counter) {
return; }
1408 maps->aliases.erase(alias_map_iter);
1411 void *MemoryManager::GetDevicePtr(
const void *h_ptr,
size_t bytes,
1416 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1419 internal::Memory &mem = maps->memories.at(h_ptr);
1422 MFEM_VERIFY_TYPES(h_mt, d_mt);
1426 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1429 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1432 MFEM_ASSERT(bytes <= mem.bytes,
"invalid copy size");
1433 if (bytes) { ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes); }
1435 ctrl->Host(h_mt)->Protect(mem, bytes);
1439 void *MemoryManager::GetAliasDevicePtr(
const void *alias_ptr,
size_t bytes,
1444 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1447 auto &alias_map = maps->aliases;
1448 auto alias_map_iter = alias_map.find(alias_ptr);
1449 if (alias_map_iter == alias_map.end()) {
mfem_error(
"alias not found"); }
1450 const internal::Alias &alias = alias_map_iter->second;
1451 const size_t offset = alias.offset;
1452 internal::Memory &mem = *alias.mem;
1455 MFEM_VERIFY_TYPES(h_mt, d_mt);
1459 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1461 void *alias_h_ptr =
static_cast<char*
>(mem.h_ptr) + offset;
1462 void *alias_d_ptr =
static_cast<char*
>(mem.d_ptr) + offset;
1463 MFEM_ASSERT(alias_h_ptr == alias_ptr,
"internal error");
1464 MFEM_ASSERT(offset + bytes <= mem.bytes,
"internal error");
1465 mem.d_rw = mem.h_rw =
false;
1466 if (mem.d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1467 ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
1468 if (copy && mem.d_ptr)
1469 { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
1470 ctrl->Host(h_mt)->AliasProtect(alias_ptr, bytes);
1474 void *MemoryManager::GetHostPtr(
const void *ptr,
size_t bytes,
bool copy)
1476 const internal::Memory &mem = maps->memories.at(ptr);
1477 MFEM_ASSERT(mem.h_ptr == ptr,
"internal error");
1478 MFEM_ASSERT(bytes <= mem.bytes,
"internal error")
1481 MFEM_VERIFY_TYPES(h_mt, d_mt);
1483 ctrl->Host(h_mt)->Unprotect(mem, bytes);
1484 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1485 if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
1486 if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
1490 void *MemoryManager::GetAliasHostPtr(
const void *ptr,
size_t bytes,
1493 const internal::Alias &alias = maps->aliases.at(ptr);
1494 const internal::Memory *
const mem = alias.mem;
1497 MFEM_VERIFY_TYPES(h_mt, d_mt);
1498 void *alias_h_ptr =
static_cast<char*
>(mem->h_ptr) + alias.offset;
1499 void *alias_d_ptr = static_cast<char*>(mem->d_ptr) + alias.offset;
1500 MFEM_ASSERT(alias_h_ptr == ptr,
"internal error");
1502 ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
1503 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1504 if (copy_data && mem->d_ptr)
1505 { ctrl->Device(d_mt)->DtoH(const_cast<void*>(ptr), alias_d_ptr, bytes); }
1506 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasProtect(alias_d_ptr, bytes); }
1512 if (exists) {
return; }
1513 maps =
new internal::Maps();
1514 ctrl =
new internal::Ctrl();
1525 MFEM_VERIFY(!configured,
"changing the dual MemoryTypes is not allowed after" 1526 " MemoryManager configuration!");
1527 UpdateDualMemoryType(mt, dual_mt);
1533 "invalid MemoryType, mt = " << (
int)mt);
1535 "invalid dual MemoryType, dual_mt = " << (
int)dual_mt);
1540 dual_map[(int)mt] = dual_mt;
1548 "invalid (mt, dual_mt) pair: (" 1557 MemoryManager::UpdateDualMemoryType(host_mt, device_mt);
1558 MemoryManager::UpdateDualMemoryType(device_mt, host_mt);
1563 MemoryManager::UpdateDualMemoryType(
1568 host_mem_type = host_mt;
1569 device_mem_type = device_mt;
1575 MFEM_VERIFY(exists,
"MemoryManager has already been destroyed!");
1576 #ifdef MFEM_TRACK_MEM_MANAGER 1577 size_t num_memories = maps->memories.size();
1578 size_t num_aliases = maps->aliases.size();
1579 if (num_memories != 0 || num_aliases != 0)
1581 MFEM_WARNING(
"...\n\t number of registered pointers: " << num_memories
1582 <<
"\n\t number of registered aliases : " << num_aliases);
1587 mfem::out <<
"Destroying the MemoryManager ...\n" 1588 <<
"remaining registered pointers : " 1589 << maps->memories.size() <<
'\n' 1590 <<
"remaining registered aliases : " 1591 << maps->aliases.size() <<
'\n';
1593 for (
auto& n : maps->memories)
1595 internal::Memory &mem = n.second;
1597 if (mem_h_ptr) { ctrl->Host(mem.h_mt)->Dealloc(mem.h_ptr); }
1598 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem); }
1600 delete maps; maps =
nullptr;
1601 delete ctrl; ctrl =
nullptr;
1622 for (
const auto& n : maps->memories)
1624 const internal::Memory &mem = n.second;
1625 os <<
"\nkey " << n.first <<
", " 1626 <<
"h_ptr " << mem.h_ptr <<
", " 1627 <<
"d_ptr " << mem.d_ptr;
1630 if (maps->memories.size() > 0) { os << std::endl; }
1637 for (
const auto& n : maps->aliases)
1639 const internal::Alias &alias = n.second;
1640 os <<
"\nalias: key " << n.first <<
", " 1641 <<
"h_ptr " << alias.mem->h_ptr <<
", " 1642 <<
"offset " << alias.offset <<
", " 1643 <<
"counter " << alias.counter;
1646 if (maps->aliases.size() > 0) { os << std::endl; }
1650 int MemoryManager::CompareHostAndDevice_(
void *h_ptr,
size_t size,
1654 mm.GetAliasDevicePtr(h_ptr, size,
false) :
1655 mm.GetDevicePtr(h_ptr, size,
false);
1656 char *h_buf =
new char[size];
1657 #if defined(MFEM_USE_CUDA) 1659 #elif defined(MFEM_USE_HIP) 1662 std::memcpy(h_buf, d_ptr, size);
1664 int res = std::memcmp(h_ptr, h_buf, size);
1674 <<
"\n registered = " << bool(flags & Mem::Registered)
1675 <<
"\n owns host = " << bool(flags & Mem::OWNS_HOST)
1676 <<
"\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
1677 <<
"\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
1678 <<
"\n valid host = " << bool(flags & Mem::VALID_HOST)
1679 <<
"\n valid device = " << bool(flags & Mem::VALID_DEVICE)
1680 <<
"\n device flag = " << bool(flags & Mem::USE_DEVICE)
1681 <<
"\n alias = " << bool(flags & Mem::ALIAS)
1685 void MemoryManager::CheckHostMemoryType_(
MemoryType h_mt,
void *h_ptr,
1688 if (!
mm.exists) {
return;}
1691 auto it = maps->memories.find(h_ptr);
1692 MFEM_VERIFY(it != maps->memories.end(),
1693 "host pointer is not registered: h_ptr = " << h_ptr);
1694 MFEM_VERIFY(h_mt == it->second.h_mt,
"host pointer MemoryType mismatch");
1698 auto it = maps->aliases.find(h_ptr);
1699 MFEM_VERIFY(it != maps->aliases.end(),
1700 "alias pointer is not registered: h_ptr = " << h_ptr);
1701 MFEM_VERIFY(h_mt == it->second.h_mt,
"alias pointer MemoryType mismatch");
1707 bool MemoryManager::exists =
false;
1708 bool MemoryManager::configured =
false;
1728 #ifdef MFEM_USE_UMPIRE 1729 const char * MemoryManager::h_umpire_name =
"MFEM_HOST";
1730 const char * MemoryManager::d_umpire_name =
"MFEM_DEVICE";
1731 const char * MemoryManager::d_umpire_2_name =
"MFEM_DEVICE_2";
1737 "host-std",
"host-32",
"host-64",
"host-debug",
"host-umpire",
"host-pinned",
1738 #if defined(MFEM_USE_CUDA) 1741 #elif defined(MFEM_USE_HIP) 1749 #if defined(MFEM_USE_CUDA) 1752 #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.
int CompareHostAndDevice(int size) const
If both the host and the device data are valid, compare their contents.
Device memory; using CUDA or HIP *Malloc and *Free.
void * CuMemFreeHostPinned(void *ptr)
Frees page-locked (pinned) host memory and returns destination ptr.
static const char * GetUmpireHostAllocatorName()
Get the host Umpire allocator name used with MemoryType::HOST_UMPIRE.
static MemoryType GetHostMemoryType()
Host memory; allocated from a "host-debug" pool.
MemoryManager mm
The (single) global memory manager object.
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)
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.
const char * MemoryTypeName[MemoryTypeSize]
Memory type names, used during Device:: configuration.
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.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
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.
Host memory; using new[] and delete[].
void * HipMemcpyHtoD(void *dst, const void *src, size_t bytes)
Copies memory from Host to Device.
void PrintFlags() const
Print the internal flags.
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
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().