171 mutable bool h_rw, d_rw;
173 h_ptr(
p), d_ptr(nullptr), bytes(
b), h_mt(h), d_mt(d),
174 h_rw(true), d_rw(true) { }
189typedef std::unordered_map<const void*, Memory> MemoryMap;
190typedef std::unordered_map<const void*, Alias> AliasMap;
200static internal::Maps *maps;
209 virtual ~HostMemorySpace() { }
210 virtual void Alloc(
void **ptr,
size_t bytes) { *ptr = std::malloc(bytes); }
211 virtual void Dealloc(
void *ptr) { std::free(ptr); }
212 virtual void Protect(
const Memory&,
size_t) { }
213 virtual void Unprotect(
const Memory&,
size_t) { }
214 virtual void AliasProtect(
const void*,
size_t) { }
215 virtual void AliasUnprotect(
const void*,
size_t) { }
219class DeviceMemorySpace
222 virtual ~DeviceMemorySpace() { }
223 virtual void Alloc(Memory &base) { base.d_ptr = std::malloc(base.bytes); }
224 virtual void Dealloc(Memory &base) { std::free(base.d_ptr); }
225 virtual void Protect(
const Memory&) { }
226 virtual void Unprotect(
const Memory&) { }
227 virtual void AliasProtect(
const void*,
size_t) { }
228 virtual void AliasUnprotect(
const void*,
size_t) { }
229 virtual void *HtoD(
void *dst,
const void *src,
size_t bytes)
230 {
return std::memcpy(dst, src, bytes); }
231 virtual void *DtoD(
void *dst,
const void *src,
size_t bytes)
232 {
return std::memcpy(dst, src, bytes); }
233 virtual void *DtoH(
void *dst,
const void *src,
size_t bytes)
234 {
return std::memcpy(dst, src, bytes); }
238class StdHostMemorySpace :
public HostMemorySpace { };
241struct NoHostMemorySpace :
public HostMemorySpace
243 void Alloc(
void**,
const size_t) {
mfem_error(
"! Host Alloc error"); }
247class Aligned32HostMemorySpace :
public HostMemorySpace
250 Aligned32HostMemorySpace(): HostMemorySpace() { }
251 void Alloc(
void **ptr,
size_t bytes)
252 {
if (mfem_memalign(ptr, 32, bytes) != 0) { throw ::std::bad_alloc(); } }
253 void Dealloc(
void *ptr) { mfem_aligned_free(ptr); }
257class Aligned64HostMemorySpace :
public HostMemorySpace
260 Aligned64HostMemorySpace(): HostMemorySpace() { }
261 void Alloc(
void **ptr,
size_t bytes)
262 {
if (mfem_memalign(ptr, 64, bytes) != 0) { throw ::std::bad_alloc(); } }
263 void Dealloc(
void *ptr) { mfem_aligned_free(ptr); }
267static uintptr_t pagesize = 0;
268static uintptr_t pagemask = 0;
271inline const void *MmuAddrR(
const void *ptr)
273 const uintptr_t addr = (uintptr_t) ptr;
274 return (addr & pagemask) ? (
void*) ((addr + pagesize) & ~pagemask) : ptr;
278inline const void *MmuAddrP(
const void *ptr)
280 const uintptr_t addr = (uintptr_t) ptr;
281 return (
void*) (addr & ~pagemask);
285inline uintptr_t MmuLengthR(
const void *ptr,
const size_t bytes)
288 const uintptr_t
a = (uintptr_t) ptr;
289 const uintptr_t A = (uintptr_t) MmuAddrR(ptr);
290 MFEM_ASSERT(
a <= A,
"");
291 const uintptr_t
b =
a + bytes;
292 const uintptr_t B =
b & ~pagemask;
293 MFEM_ASSERT(B <=
b,
"");
294 const uintptr_t length = B > A ? B - A : 0;
295 MFEM_ASSERT(length % pagesize == 0,
"");
300inline uintptr_t MmuLengthP(
const void *ptr,
const size_t bytes)
303 const uintptr_t
a = (uintptr_t) ptr;
304 const uintptr_t A = (uintptr_t) MmuAddrP(ptr);
305 MFEM_ASSERT(A <=
a,
"");
306 const uintptr_t
b =
a + bytes;
307 const uintptr_t B =
b & pagemask ? (
b + pagesize) & ~pagemask :
b;
308 MFEM_ASSERT(
b <= B,
"");
309 MFEM_ASSERT(B >= A,
"");
310 const uintptr_t length = B - A;
311 MFEM_ASSERT(length % pagesize == 0,
"");
316static void MmuError(
int, siginfo_t *si,
void*)
318 constexpr size_t buf_size = 64;
321 const void *ptr = si->si_addr;
322 snprintf(str, buf_size,
"Error while accessing address %p!", ptr);
323 mfem::out << std::endl <<
"An illegal memory access was made!";
330 if (pagesize > 0) {
return; }
332 sa.sa_flags = SA_SIGINFO;
333 sigemptyset(&sa.sa_mask);
334 sa.sa_sigaction = MmuError;
335 if (sigaction(SIGBUS, &sa, NULL) == -1) {
mfem_error(
"SIGBUS"); }
336 if (sigaction(SIGSEGV, &sa, NULL) == -1) {
mfem_error(
"SIGSEGV"); }
337 pagesize = (uintptr_t) sysconf(_SC_PAGE_SIZE);
338 MFEM_ASSERT(pagesize > 0,
"pagesize must not be less than 1");
339 pagemask = pagesize - 1;
343inline void MmuAlloc(
void **ptr,
const size_t bytes)
345 const size_t length = bytes == 0 ? 8 : bytes;
346 const int prot = PROT_READ | PROT_WRITE;
347 const int flags = MAP_ANONYMOUS | MAP_PRIVATE;
348 *ptr = ::mmap(NULL, length, prot, flags, -1, 0);
349 if (*ptr == MAP_FAILED) { throw ::std::bad_alloc(); }
353inline void MmuDealloc(
void *ptr,
const size_t bytes)
355 const size_t length = bytes == 0 ? 8 : bytes;
356 if (::munmap(ptr, length) == -1) {
mfem_error(
"Dealloc error!"); }
360inline void MmuProtect(
const void *ptr,
const size_t bytes)
362 static const bool mmu_protect_error = getenv(
"MFEM_MMU_PROTECT_ERROR");
363 if (!::mprotect(
const_cast<void*
>(ptr), bytes, PROT_NONE)) {
return; }
364 if (mmu_protect_error) {
mfem_error(
"MMU protection (NONE) error"); }
368inline void MmuAllow(
const void *ptr,
const size_t bytes)
370 const int RW = PROT_READ | PROT_WRITE;
371 static const bool mmu_protect_error = getenv(
"MFEM_MMU_PROTECT_ERROR");
372 if (!::mprotect(
const_cast<void*
>(ptr), bytes, RW)) {
return; }
373 if (mmu_protect_error) {
mfem_error(
"MMU protection (R/W) error"); }
376inline void MmuInit() { }
377inline void MmuAlloc(
void **ptr,
const size_t bytes) { *ptr = std::malloc(bytes); }
378inline void MmuDealloc(
void *ptr,
const size_t) { std::free(ptr); }
379inline void MmuProtect(
const void*,
const size_t) { }
380inline void MmuAllow(
const void*,
const size_t) { }
381inline const void *MmuAddrR(
const void *
a) {
return a; }
382inline const void *MmuAddrP(
const void *
a) {
return a; }
383inline uintptr_t MmuLengthR(
const void*,
const size_t) {
return 0; }
384inline uintptr_t MmuLengthP(
const void*,
const size_t) {
return 0; }
388class MmuHostMemorySpace :
public HostMemorySpace
391 MmuHostMemorySpace(): HostMemorySpace() { MmuInit(); }
392 void Alloc(
void **ptr,
size_t bytes) { MmuAlloc(ptr, bytes); }
393 void Dealloc(
void *ptr) { MmuDealloc(ptr, maps->memories.at(ptr).bytes); }
394 void Protect(
const Memory& mem,
size_t bytes)
395 {
if (mem.h_rw) { mem.h_rw =
false; MmuProtect(mem.h_ptr, bytes); } }
396 void Unprotect(
const Memory &mem,
size_t bytes)
397 {
if (!mem.h_rw) { mem.h_rw =
true; MmuAllow(mem.h_ptr, bytes); } }
399 void AliasProtect(
const void *ptr,
size_t bytes)
400 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
402 void AliasUnprotect(
const void *ptr,
size_t bytes)
403 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
407class UvmHostMemorySpace :
public HostMemorySpace
410 UvmHostMemorySpace(): HostMemorySpace() { }
411 void Alloc(
void **ptr,
size_t bytes) {
CuMallocManaged(ptr, bytes == 0 ? 8 : bytes); }
412 void Dealloc(
void *ptr) {
CuMemFree(ptr); }
416class NoDeviceMemorySpace:
public DeviceMemorySpace
419 void Alloc(internal::Memory&) {
mfem_error(
"! Device Alloc"); }
420 void Dealloc(Memory&) {
mfem_error(
"! Device Dealloc"); }
421 void *HtoD(
void*,
const void*,
size_t) {
mfem_error(
"!HtoD");
return nullptr; }
422 void *DtoD(
void*,
const void*,
size_t) {
mfem_error(
"!DtoD");
return nullptr; }
423 void *DtoH(
void*,
const void*,
size_t) {
mfem_error(
"!DtoH");
return nullptr; }
427class StdDeviceMemorySpace :
public DeviceMemorySpace { };
430class CudaDeviceMemorySpace:
public DeviceMemorySpace
433 CudaDeviceMemorySpace(): DeviceMemorySpace() { }
434 void Alloc(Memory &base) {
CuMemAlloc(&base.d_ptr, base.bytes); }
435 void Dealloc(Memory &base) {
CuMemFree(base.d_ptr); }
436 void *HtoD(
void *dst,
const void *src,
size_t bytes)
438 void *DtoD(
void* dst,
const void* src,
size_t bytes)
440 void *DtoH(
void *dst,
const void *src,
size_t bytes)
445class HostPinnedMemorySpace:
public HostMemorySpace
448 HostPinnedMemorySpace(): HostMemorySpace() { }
449 void Alloc(
void ** ptr,
size_t bytes)
override
458 void Dealloc(
void *ptr)
override
470class HipDeviceMemorySpace:
public DeviceMemorySpace
473 HipDeviceMemorySpace(): DeviceMemorySpace() { }
474 void Alloc(Memory &base) {
HipMemAlloc(&base.d_ptr, base.bytes); }
475 void Dealloc(Memory &base) {
HipMemFree(base.d_ptr); }
476 void *HtoD(
void *dst,
const void *src,
size_t bytes)
478 void *DtoD(
void* dst,
const void* src,
size_t bytes)
483 void *DtoH(
void *dst,
const void *src,
size_t bytes)
488class UvmCudaMemorySpace :
public DeviceMemorySpace
491 void Alloc(Memory &base) { base.d_ptr = base.h_ptr; }
492 void Dealloc(Memory&) { }
493 void *HtoD(
void *dst,
const void *src,
size_t bytes)
495 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
498 void *DtoD(
void* dst,
const void* src,
size_t bytes)
500 void *DtoH(
void *dst,
const void *src,
size_t bytes)
502 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
508class MmuDeviceMemorySpace :
public DeviceMemorySpace
511 MmuDeviceMemorySpace(): DeviceMemorySpace() { }
512 void Alloc(Memory &m) { MmuAlloc(&m.d_ptr, m.bytes); }
513 void Dealloc(Memory &m) { MmuDealloc(m.d_ptr, m.bytes); }
514 void Protect(
const Memory &m)
515 {
if (m.d_rw) { m.d_rw =
false; MmuProtect(m.d_ptr, m.bytes); } }
516 void Unprotect(
const Memory &m)
517 {
if (!m.d_rw) { m.d_rw =
true; MmuAllow(m.d_ptr, m.bytes); } }
519 void AliasProtect(
const void *ptr,
size_t bytes)
520 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
522 void AliasUnprotect(
const void *ptr,
size_t bytes)
523 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
524 void *HtoD(
void *dst,
const void *src,
size_t bytes)
525 {
return std::memcpy(dst, src, bytes); }
526 void *DtoD(
void *dst,
const void *src,
size_t bytes)
527 {
return std::memcpy(dst, src, bytes); }
528 void *DtoH(
void *dst,
const void *src,
size_t bytes)
529 {
return std::memcpy(dst, src, bytes); }
532#ifdef MFEM_USE_UMPIRE
533class UmpireMemorySpace
536 umpire::ResourceManager &rm;
537 umpire::Allocator allocator;
538 bool owns_allocator{
false};
542 virtual ~UmpireMemorySpace() {
if (owns_allocator) { allocator.release(); } }
543 UmpireMemorySpace(
const char * name,
const char *
space)
544 : rm(umpire::ResourceManager::getInstance())
546 if (!rm.isAllocator(name))
548 allocator = rm.makeAllocator<umpire::strategy::QuickPool>(
549 name, rm.getAllocator(
space));
550 owns_allocator =
true;
554 allocator = rm.getAllocator(name);
555 owns_allocator =
false;
561class UmpireHostMemorySpace :
public HostMemorySpace,
public UmpireMemorySpace
564 umpire::strategy::AllocationStrategy *strat;
566 UmpireHostMemorySpace(
const char * name)
568 UmpireMemorySpace(name,
"HOST"),
569 strat(allocator.getAllocationStrategy()) {}
570 void Alloc(
void **ptr,
size_t bytes)
override
571 { *ptr = allocator.allocate(bytes); }
572 void Dealloc(
void *ptr)
override { allocator.deallocate(ptr); }
573 void Insert(
void *ptr,
size_t bytes)
574 { rm.registerAllocation(ptr, {ptr, bytes, strat}); }
578#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
579class UmpireDeviceMemorySpace :
public DeviceMemorySpace,
580 public UmpireMemorySpace
583 UmpireDeviceMemorySpace(
const char * name)
584 : DeviceMemorySpace(),
585 UmpireMemorySpace(name,
"DEVICE") {}
586 void Alloc(Memory &base)
override
587 { base.d_ptr = allocator.allocate(base.bytes); }
588 void Dealloc(Memory &base)
override { rm.deallocate(base.d_ptr); }
589 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
599 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
612 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
624class UmpireDeviceMemorySpace :
public NoDeviceMemorySpace
627 UmpireDeviceMemorySpace(
const char * ) {}
642 Ctrl(): host{nullptr}, device{nullptr} { }
646 if (host[HostMemoryType])
648 mfem_error(
"Memory backends have already been configured!");
654 host[
static_cast<int>(MT::HOST)] =
new StdHostMemorySpace();
655 host[
static_cast<int>(MT::HOST_32)] =
new Aligned32HostMemorySpace();
656 host[
static_cast<int>(MT::HOST_64)] =
new Aligned64HostMemorySpace();
658 host[
static_cast<int>(MT::HOST_DEBUG)] =
nullptr;
659 host[
static_cast<int>(MT::HOST_UMPIRE)] =
nullptr;
660 host[
static_cast<int>(MT::MANAGED)] =
new UvmHostMemorySpace();
664 device[
static_cast<int>(MT::MANAGED)-shift] =
new UvmCudaMemorySpace();
666 device[
static_cast<int>(MemoryType::DEVICE)-shift] =
nullptr;
667 device[
static_cast<int>(MT::DEVICE_DEBUG)-shift] =
nullptr;
668 device[
static_cast<int>(MT::DEVICE_UMPIRE)-shift] =
nullptr;
669 device[
static_cast<int>(MT::DEVICE_UMPIRE_2)-shift] =
nullptr;
672 HostMemorySpace* Host(
const MemoryType mt)
674 const int mt_i =
static_cast<int>(mt);
676 if (!host[mt_i]) { host[mt_i] = NewHostCtrl(mt); }
677 MFEM_ASSERT(host[mt_i],
"Host memory controller is not configured!");
681 DeviceMemorySpace* Device(
const MemoryType mt)
683 const int mt_i =
static_cast<int>(mt) - DeviceMemoryType;
684 MFEM_ASSERT(mt_i >= 0,
"");
686 if (!device[mt_i]) { device[mt_i] = NewDeviceCtrl(mt); }
687 MFEM_ASSERT(device[mt_i],
"Memory manager has not been configured!");
696 for (
int mt = mt_d; mt <
MemoryTypeSize; mt++) {
delete device[mt-mt_d]; }
700 HostMemorySpace* NewHostCtrl(
const MemoryType mt)
704 case MT::HOST_DEBUG:
return new MmuHostMemorySpace();
705#ifdef MFEM_USE_UMPIRE
706 case MT::HOST_UMPIRE:
707 return new UmpireHostMemorySpace(
708 MemoryManager::GetUmpireHostAllocatorName());
710 case MT::HOST_UMPIRE:
return new NoHostMemorySpace();
712 case MT::HOST_PINNED:
return new HostPinnedMemorySpace();
713 default: MFEM_ABORT(
"Unknown host memory controller!");
718 DeviceMemorySpace* NewDeviceCtrl(
const MemoryType mt)
722#ifdef MFEM_USE_UMPIRE
723 case MT::DEVICE_UMPIRE:
724 return new UmpireDeviceMemorySpace(
725 MemoryManager::GetUmpireDeviceAllocatorName());
726 case MT::DEVICE_UMPIRE_2:
727 return new UmpireDeviceMemorySpace(
728 MemoryManager::GetUmpireDevice2AllocatorName());
730 case MT::DEVICE_UMPIRE:
return new NoDeviceMemorySpace();
731 case MT::DEVICE_UMPIRE_2:
return new NoDeviceMemorySpace();
733 case MT::DEVICE_DEBUG:
return new MmuDeviceMemorySpace();
736#if defined(MFEM_USE_CUDA)
737 return new CudaDeviceMemorySpace();
738#elif defined(MFEM_USE_HIP)
739 return new HipDeviceMemorySpace();
741 MFEM_ABORT(
"No device memory controller!");
745 default: MFEM_ABORT(
"Unknown device memory controller!");
753static internal::Ctrl *ctrl;
755void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType mt,
758 MFEM_ASSERT(exists,
"Internal error!");
777void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType h_mt,
781 MFEM_ASSERT(exists,
"Internal error!");
782 MFEM_ASSERT(
IsHostMemory(h_mt),
"h_mt must be host type");
785 "d_mt must be device type, the same is h_mt, or DEFAULT");
792 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
793 else { h_ptr = h_tmp; }
797 mm.Insert(h_ptr, bytes, h_mt, d_mt);
801 CheckHostMemoryType_(h_mt, h_ptr,
false);
806void *MemoryManager::Register_(
void *ptr,
void *h_tmp,
size_t bytes,
808 bool own,
bool alias,
unsigned &flags)
810 MFEM_ASSERT(exists,
"Internal error!");
818 MFEM_VERIFY_TYPES(h_mt, d_mt);
820 if (ptr ==
nullptr && h_tmp ==
nullptr)
822 MFEM_VERIFY(bytes == 0,
"internal error");
826 MFEM_VERIFY(!alias,
"Cannot register an alias!");
834 mm.Insert(h_ptr, bytes, h_mt, d_mt);
835 flags = (own ? flags |
Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST) |
840 MFEM_VERIFY(ptr || bytes == 0,
841 "cannot register NULL device pointer with bytes = " << bytes);
842 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
843 else { h_ptr = h_tmp; }
844 mm.InsertDevice(ptr, h_ptr, bytes, h_mt, d_mt);
848 CheckHostMemoryType_(h_mt, h_ptr, alias);
852void MemoryManager::Register2_(
void *h_ptr,
void *d_ptr,
size_t bytes,
854 bool own,
bool alias,
unsigned &flags,
855 unsigned valid_flags)
857 MFEM_CONTRACT_VAR(alias);
858 MFEM_ASSERT(exists,
"Internal error!");
859 MFEM_ASSERT(!alias,
"Cannot register an alias!");
860 MFEM_VERIFY_TYPES(h_mt, d_mt);
862 if (h_ptr ==
nullptr && d_ptr ==
nullptr)
864 MFEM_VERIFY(bytes == 0,
"internal error");
870 MFEM_VERIFY(d_ptr || bytes == 0,
871 "cannot register NULL device pointer with bytes = " << bytes);
872 mm.InsertDevice(d_ptr, h_ptr, bytes, h_mt, d_mt);
874 flags & ~(Mem::OWNS_HOST | Mem::OWNS_DEVICE)) |
877 CheckHostMemoryType_(h_mt, h_ptr, alias);
880void MemoryManager::Alias_(
void *base_h_ptr,
size_t offset,
size_t bytes,
881 unsigned base_flags,
unsigned &flags)
883 mm.InsertAlias(base_h_ptr, (
char*)base_h_ptr + offset, bytes,
889void MemoryManager::SetDeviceMemoryType_(
void *h_ptr,
unsigned flags,
892 MFEM_VERIFY(h_ptr,
"cannot set the device memory type: Memory is empty!");
895 auto mem_iter = maps->memories.find(h_ptr);
896 MFEM_VERIFY(mem_iter != maps->memories.end(),
"internal error");
897 internal::Memory &mem = mem_iter->second;
898 if (mem.d_mt == d_mt) {
return; }
899 MFEM_VERIFY(mem.d_ptr ==
nullptr,
"cannot set the device memory type:"
900 " device memory is allocated!");
905 auto alias_iter = maps->aliases.find(h_ptr);
906 MFEM_VERIFY(alias_iter != maps->aliases.end(),
"internal error");
907 internal::Alias &alias = alias_iter->second;
908 internal::Memory &base_mem = *alias.mem;
909 if (base_mem.d_mt == d_mt) {
return; }
910 MFEM_VERIFY(base_mem.d_ptr ==
nullptr,
911 "cannot set the device memory type:"
912 " alias' base device memory is allocated!");
913 base_mem.d_mt = d_mt;
917void MemoryManager::Delete_(
void *h_ptr,
MemoryType h_mt,
unsigned flags)
924 MFEM_ASSERT(
IsHostMemory(h_mt),
"invalid h_mt = " << (
int)h_mt);
926 MFEM_ASSERT(!owns_device || owns_internal,
"invalid Memory state");
931 MFEM_ASSERT(registered || !(owns_host || owns_device || owns_internal) ||
932 (!(owns_device || owns_internal) && h_ptr ==
nullptr),
933 "invalid Memory state");
934 if (!
mm.exists || !registered) {
return; }
940 MFEM_ASSERT(h_mt == maps->aliases.at(h_ptr).h_mt,
"");
941 mm.EraseAlias(h_ptr);
947 { ctrl->Host(h_mt)->Dealloc(h_ptr); }
951 MFEM_ASSERT(h_mt == maps->memories.at(h_ptr).h_mt,
"");
952 mm.Erase(h_ptr, owns_device);
957void MemoryManager::DeleteDevice_(
void *h_ptr,
unsigned & flags)
962 mm.EraseDevice(h_ptr);
967bool MemoryManager::MemoryClassCheck_(
MemoryClass mc,
void *h_ptr,
973 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
979 auto iter = maps->memories.find(h_ptr);
980 MFEM_VERIFY(iter != maps->memories.end(),
"internal error");
981 d_mt = iter->second.d_mt;
985 auto iter = maps->aliases.find(h_ptr);
986 MFEM_VERIFY(iter != maps->aliases.end(),
"internal error");
987 d_mt = iter->second.mem->d_mt;
1024 size_t bytes,
unsigned &flags)
1026 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1028 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1034 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1035 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1042 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1043 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1048 size_t bytes,
unsigned &flags)
1050 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1052 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1058 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1059 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1066 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1067 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1072 size_t bytes,
unsigned &flags)
1074 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1076 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1081 {
return mm.GetAliasHostPtr(h_ptr, bytes,
false); }
1082 else {
return mm.GetHostPtr(h_ptr, bytes,
false); }
1088 {
return mm.GetAliasDevicePtr(h_ptr, bytes,
false); }
1089 else {
return mm.GetDevicePtr(h_ptr, bytes,
false); }
1093void MemoryManager::SyncAlias_(
const void *base_h_ptr,
void *alias_h_ptr,
1094 size_t alias_bytes,
unsigned base_flags,
1095 unsigned &alias_flags)
1099 MFEM_ASSERT(alias_flags &
Mem::ALIAS,
"not an alias");
1102 mm.GetAliasHostPtr(alias_h_ptr, alias_bytes,
true);
1108 mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags &
Mem::ALIAS);
1112 mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes,
true);
1118MemoryType MemoryManager::GetDeviceMemoryType_(
void *h_ptr,
bool alias)
1124 auto iter = maps->memories.find(h_ptr);
1125 MFEM_ASSERT(iter != maps->memories.end(),
"internal error");
1126 return iter->second.d_mt;
1129 auto iter = maps->aliases.find(h_ptr);
1130 MFEM_ASSERT(iter != maps->aliases.end(),
"internal error");
1131 return iter->second.mem->d_mt;
1133 MFEM_ABORT(
"internal error");
1134 return MemoryManager::host_mem_type;
1137MemoryType MemoryManager::GetHostMemoryType_(
void *h_ptr)
1139 if (!
mm.exists) {
return MemoryManager::host_mem_type; }
1140 if (
mm.
IsKnown(h_ptr)) {
return maps->memories.at(h_ptr).h_mt; }
1141 if (
mm.
IsAlias(h_ptr)) {
return maps->aliases.at(h_ptr).h_mt; }
1142 return MemoryManager::host_mem_type;
1145void MemoryManager::Copy_(
void *dst_h_ptr,
const void *src_h_ptr,
1146 size_t bytes,
unsigned src_flags,
1147 unsigned &dst_flags)
1157 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1158 MFEM_ASSERT(dst_h_ptr !=
nullptr,
"invalid dst_h_ptr = nullptr");
1159 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1161 const bool dst_on_host =
1166 dst_flags = dst_flags &
1169 const bool src_on_host =
1174 const void *src_d_ptr =
1175 src_on_host ? NULL :
1177 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1178 mm.GetDevicePtr(src_h_ptr, bytes,
false));
1184 if (dst_h_ptr != src_h_ptr && bytes != 0)
1186 MFEM_ASSERT((
const char*)dst_h_ptr + bytes <= src_h_ptr ||
1187 (
const char*)src_h_ptr + bytes <= dst_h_ptr,
1189 std::memcpy(dst_h_ptr, src_h_ptr, bytes);
1194 if (dst_h_ptr != src_d_ptr && bytes != 0)
1196 internal::Memory &src_d_base = maps->memories.at(src_h_ptr);
1198 ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
1204 void *dest_d_ptr = (dst_flags &
Mem::ALIAS) ?
1205 mm.GetAliasDevicePtr(dst_h_ptr, bytes,
false) :
1206 mm.GetDevicePtr(dst_h_ptr, bytes,
false);
1209 const bool known =
mm.
IsKnown(dst_h_ptr);
1211 MFEM_VERIFY(alias||known,
"");
1213 maps->memories.at(dst_h_ptr).d_mt :
1214 maps->aliases.at(dst_h_ptr).mem->d_mt;
1215 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1219 if (dest_d_ptr != src_d_ptr && bytes != 0)
1221 const bool known =
mm.
IsKnown(dst_h_ptr);
1223 MFEM_VERIFY(alias||known,
"");
1225 maps->memories.at(dst_h_ptr).d_mt :
1226 maps->aliases.at(dst_h_ptr).mem->d_mt;
1227 ctrl->Device(d_mt)->DtoD(dest_d_ptr, src_d_ptr, bytes);
1233void MemoryManager::CopyToHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1234 size_t bytes,
unsigned src_flags)
1236 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1237 MFEM_ASSERT(dest_h_ptr !=
nullptr,
"invalid dest_h_ptr = nullptr");
1238 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1243 if (dest_h_ptr != src_h_ptr && bytes != 0)
1245 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1246 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1248 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1253 MFEM_ASSERT(IsKnown_(src_h_ptr),
"internal error");
1254 const void *src_d_ptr = (src_flags &
Mem::ALIAS) ?
1255 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1256 mm.GetDevicePtr(src_h_ptr, bytes,
false);
1257 const internal::Memory &base = maps->memories.at(dest_h_ptr);
1259 ctrl->Device(d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
1263void MemoryManager::CopyFromHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1264 size_t bytes,
unsigned &dest_flags)
1266 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1267 MFEM_ASSERT(dest_h_ptr !=
nullptr,
"invalid dest_h_ptr = nullptr");
1268 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1273 if (dest_h_ptr != src_h_ptr && bytes != 0)
1275 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1276 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1278 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1283 void *dest_d_ptr = (dest_flags &
Mem::ALIAS) ?
1284 mm.GetAliasDevicePtr(dest_h_ptr, bytes,
false) :
1285 mm.GetDevicePtr(dest_h_ptr, bytes,
false);
1286 const internal::Memory &base = maps->memories.at(dest_h_ptr);
1288 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1290 dest_flags = dest_flags &
1294bool MemoryManager::IsKnown_(
const void *h_ptr)
1296 return maps->memories.find(h_ptr) != maps->memories.end();
1299bool MemoryManager::IsAlias_(
const void *h_ptr)
1301 return maps->aliases.find(h_ptr) != maps->aliases.end();
1304void MemoryManager::Insert(
void *h_ptr,
size_t bytes,
1307#ifdef MFEM_TRACK_MEM_MANAGER
1308 mfem::out <<
"[mfem memory manager]: registering h_ptr: " << h_ptr
1309 <<
", bytes: " << bytes << std::endl;
1313 MFEM_VERIFY(bytes == 0,
"Trying to add NULL with size " << bytes);
1316 MFEM_VERIFY_TYPES(h_mt, d_mt);
1320 maps->memories.emplace(h_ptr, internal::Memory(h_ptr, bytes, h_mt, d_mt));
1322 if (res.second ==
false)
1324 auto &m = res.first->second;
1325 MFEM_VERIFY(m.bytes >= bytes && m.h_mt == h_mt &&
1328 "Address already present with different attributes!");
1329#ifdef MFEM_TRACK_MEM_MANAGER
1330 mfem::out <<
"[mfem memory manager]: repeated registration of h_ptr: "
1331 << h_ptr << std::endl;
1337void MemoryManager::InsertDevice(
void *d_ptr,
void *h_ptr,
size_t bytes,
1341 MFEM_ASSERT(h_ptr != NULL,
"internal error");
1342 Insert(h_ptr, bytes, h_mt, d_mt);
1343 internal::Memory &mem = maps->memories.at(h_ptr);
1344 if (d_ptr == NULL && bytes != 0) { ctrl->Device(d_mt)->Alloc(mem); }
1345 else { mem.d_ptr = d_ptr; }
1348void MemoryManager::InsertAlias(
const void *base_ptr,
void *alias_ptr,
1349 const size_t bytes,
const bool base_is_alias)
1351 size_t offset =
static_cast<size_t>(
static_cast<const char*
>(alias_ptr) -
1352 static_cast<const char*
>(base_ptr));
1353#ifdef MFEM_TRACK_MEM_MANAGER
1354 mfem::out <<
"[mfem memory manager]: registering alias of base_ptr: "
1355 << base_ptr <<
", offset: " << offset <<
", bytes: " << bytes
1356 <<
", base is alias: " << base_is_alias << std::endl;
1360 MFEM_VERIFY(offset == 0,
1361 "Trying to add alias to NULL at offset " << offset);
1366 const internal::Alias &alias = maps->aliases.at(base_ptr);
1367 MFEM_ASSERT(alias.mem,
"");
1368 base_ptr = alias.mem->h_ptr;
1369 offset += alias.offset;
1370#ifdef MFEM_TRACK_MEM_MANAGER
1371 mfem::out <<
"[mfem memory manager]: real base_ptr: " << base_ptr
1375 internal::Memory &mem = maps->memories.at(base_ptr);
1376 MFEM_VERIFY(offset + bytes <= mem.bytes,
"invalid alias");
1378 maps->aliases.emplace(alias_ptr,
1379 internal::Alias{&mem, offset, 1, mem.h_mt});
1380 if (res.second ==
false)
1382 internal::Alias &alias = res.first->second;
1385 alias.offset = offset;
1386 alias.h_mt = mem.h_mt;
1391void MemoryManager::Erase(
void *h_ptr,
bool free_dev_ptr)
1393#ifdef MFEM_TRACK_MEM_MANAGER
1394 mfem::out <<
"[mfem memory manager]: un-registering h_ptr: " << h_ptr
1397 if (!h_ptr) {
return; }
1398 auto mem_map_iter = maps->memories.find(h_ptr);
1399 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1400 internal::Memory &mem = mem_map_iter->second;
1401 if (mem.d_ptr && free_dev_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1402 maps->memories.erase(mem_map_iter);
1405void MemoryManager::EraseDevice(
void *h_ptr)
1407 if (!h_ptr) {
return; }
1408 auto mem_map_iter = maps->memories.find(h_ptr);
1409 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1410 internal::Memory &mem = mem_map_iter->second;
1411 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1412 mem.d_ptr =
nullptr;
1415void MemoryManager::EraseAlias(
void *alias_ptr)
1417#ifdef MFEM_TRACK_MEM_MANAGER
1418 mfem::out <<
"[mfem memory manager]: un-registering alias_ptr: " << alias_ptr
1421 if (!alias_ptr) {
return; }
1422 auto alias_map_iter = maps->aliases.find(alias_ptr);
1423 if (alias_map_iter == maps->aliases.end()) {
mfem_error(
"Unknown alias!"); }
1424 internal::Alias &alias = alias_map_iter->second;
1425 if (--alias.counter) {
return; }
1426 maps->aliases.erase(alias_map_iter);
1429void *MemoryManager::GetDevicePtr(
const void *h_ptr,
size_t bytes,
1434 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1437 internal::Memory &mem = maps->memories.at(h_ptr);
1440 MFEM_VERIFY_TYPES(h_mt, d_mt);
1444 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1447 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1450 MFEM_ASSERT(bytes <= mem.bytes,
"invalid copy size");
1451 if (bytes) { ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes); }
1453 ctrl->Host(h_mt)->Protect(mem, bytes);
1457void *MemoryManager::GetAliasDevicePtr(
const void *alias_ptr,
size_t bytes,
1462 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1465 auto &alias_map = maps->aliases;
1466 auto alias_map_iter = alias_map.find(alias_ptr);
1467 if (alias_map_iter == alias_map.end()) {
mfem_error(
"alias not found"); }
1468 const internal::Alias &alias = alias_map_iter->second;
1469 const size_t offset = alias.offset;
1470 internal::Memory &mem = *alias.mem;
1473 MFEM_VERIFY_TYPES(h_mt, d_mt);
1477 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1479 void *alias_h_ptr =
static_cast<char*
>(mem.h_ptr) + offset;
1480 void *alias_d_ptr =
static_cast<char*
>(mem.d_ptr) + offset;
1481 MFEM_ASSERT(alias_h_ptr == alias_ptr,
"internal error");
1482 MFEM_ASSERT(offset + bytes <= mem.bytes,
"internal error");
1483 mem.d_rw = mem.h_rw =
false;
1484 if (mem.d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1485 ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
1486 if (copy && mem.d_ptr)
1487 { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
1488 ctrl->Host(h_mt)->AliasProtect(alias_ptr, bytes);
1492void *MemoryManager::GetHostPtr(
const void *ptr,
size_t bytes,
bool copy)
1494 const internal::Memory &mem = maps->memories.at(ptr);
1495 MFEM_ASSERT(mem.h_ptr == ptr,
"internal error");
1496 MFEM_ASSERT(bytes <= mem.bytes,
"internal error")
1499 MFEM_VERIFY_TYPES(h_mt, d_mt);
1501 ctrl->Host(h_mt)->Unprotect(mem, bytes);
1502 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1503 if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
1504 if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
1508void *MemoryManager::GetAliasHostPtr(
const void *ptr,
size_t bytes,
1511 const internal::Alias &alias = maps->aliases.at(ptr);
1512 const internal::Memory *
const mem = alias.mem;
1515 MFEM_VERIFY_TYPES(h_mt, d_mt);
1516 void *alias_h_ptr =
static_cast<char*
>(mem->h_ptr) + alias.offset;
1517 void *alias_d_ptr =
static_cast<char*
>(mem->d_ptr) + alias.offset;
1518 MFEM_ASSERT(alias_h_ptr == ptr,
"internal error");
1520 ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
1521 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1522 if (copy_data && mem->d_ptr)
1523 { ctrl->Device(d_mt)->DtoH(
const_cast<void*
>(ptr), alias_d_ptr, bytes); }
1524 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasProtect(alias_d_ptr, bytes); }
1530 if (exists) {
return; }
1531 maps =
new internal::Maps();
1532 ctrl =
new internal::Ctrl();
1543 MFEM_VERIFY(!configured,
"changing the dual MemoryTypes is not allowed after"
1544 " MemoryManager configuration!");
1545 UpdateDualMemoryType(mt, dual_mt);
1551 "invalid MemoryType, mt = " << (
int)mt);
1553 "invalid dual MemoryType, dual_mt = " << (
int)dual_mt);
1558 dual_map[(int)mt] = dual_mt;
1566 "invalid (mt, dual_mt) pair: ("
1575 MemoryManager::UpdateDualMemoryType(host_mt, device_mt);
1576 MemoryManager::UpdateDualMemoryType(device_mt, host_mt);
1581 MemoryManager::UpdateDualMemoryType(
1586 host_mem_type = host_mt;
1587 device_mem_type = device_mt;
1593 MFEM_VERIFY(exists,
"MemoryManager has already been destroyed!");
1594#ifdef MFEM_TRACK_MEM_MANAGER
1595 size_t num_memories = maps->memories.size();
1596 size_t num_aliases = maps->aliases.size();
1597 if (num_memories != 0 || num_aliases != 0)
1599 MFEM_WARNING(
"...\n\t number of registered pointers: " << num_memories
1600 <<
"\n\t number of registered aliases : " << num_aliases);
1605 mfem::out <<
"Destroying the MemoryManager ...\n"
1606 <<
"remaining registered pointers : "
1607 << maps->memories.size() <<
'\n'
1608 <<
"remaining registered aliases : "
1609 << maps->aliases.size() <<
'\n';
1611 for (
auto& n : maps->memories)
1613 internal::Memory &mem = n.second;
1615 if (mem_h_ptr) { ctrl->Host(mem.h_mt)->Dealloc(mem.h_ptr); }
1616 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem); }
1618 delete maps; maps =
nullptr;
1619 delete ctrl; ctrl =
nullptr;
1640 for (
const auto& n : maps->memories)
1642 const internal::Memory &mem = n.second;
1643 os <<
"\nkey " << n.first <<
", "
1644 <<
"h_ptr " << mem.h_ptr <<
", "
1645 <<
"d_ptr " << mem.d_ptr;
1648 if (maps->memories.size() > 0) { os << std::endl; }
1655 for (
const auto& n : maps->aliases)
1657 const internal::Alias &alias = n.second;
1658 os <<
"\nalias: key " << n.first <<
", "
1659 <<
"h_ptr " << alias.mem->h_ptr <<
", "
1660 <<
"offset " << alias.offset <<
", "
1661 <<
"counter " << alias.counter;
1664 if (maps->aliases.size() > 0) { os << std::endl; }
1668int MemoryManager::CompareHostAndDevice_(
void *h_ptr,
size_t size,
1672 mm.GetAliasDevicePtr(h_ptr, size,
false) :
1673 mm.GetDevicePtr(h_ptr, size,
false);
1674 char *h_buf =
new char[size];
1675#if defined(MFEM_USE_CUDA)
1677#elif defined(MFEM_USE_HIP)
1680 std::memcpy(h_buf, d_ptr, size);
1682 int res = std::memcmp(h_ptr, h_buf, size);
1692 <<
"\n registered = " << bool(flags & Mem::Registered)
1693 <<
"\n owns host = " << bool(flags & Mem::OWNS_HOST)
1694 <<
"\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
1695 <<
"\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
1696 <<
"\n valid host = " << bool(flags & Mem::VALID_HOST)
1697 <<
"\n valid device = " << bool(flags & Mem::VALID_DEVICE)
1698 <<
"\n device flag = " << bool(flags & Mem::USE_DEVICE)
1699 <<
"\n alias = " << bool(flags & Mem::ALIAS)