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)
override {
mfem_error(
"! Host Alloc error"); }
247class Aligned32HostMemorySpace :
public HostMemorySpace
250 Aligned32HostMemorySpace(): HostMemorySpace() { }
251 void Alloc(
void **ptr,
size_t bytes)
override
252 {
if (mfem_memalign(ptr, 32, bytes) != 0) { throw ::std::bad_alloc(); } }
253 void Dealloc(
void *ptr)
override { mfem_aligned_free(ptr); }
257class Aligned64HostMemorySpace :
public HostMemorySpace
260 Aligned64HostMemorySpace(): HostMemorySpace() { }
261 void Alloc(
void **ptr,
size_t bytes)
override
262 {
if (mfem_memalign(ptr, 64, bytes) != 0) { throw ::std::bad_alloc(); } }
263 void Dealloc(
void *ptr)
override { mfem_aligned_free(ptr); }
267static uintptr_t pagesize = 0;
268static uintptr_t pagemask = 0;
270static struct sigaction old_segv_action;
271static struct sigaction old_bus_action;
274inline const void *MmuAddrR(
const void *ptr)
276 const uintptr_t addr = (uintptr_t) ptr;
277 return (addr & pagemask) ? (
void*) ((addr + pagesize) & ~pagemask) : ptr;
281inline const void *MmuAddrP(
const void *ptr)
283 const uintptr_t addr = (uintptr_t) ptr;
284 return (
void*) (addr & ~pagemask);
288inline uintptr_t MmuLengthR(
const void *ptr,
const size_t bytes)
291 const uintptr_t
a = (uintptr_t) ptr;
292 const uintptr_t A = (uintptr_t) MmuAddrR(ptr);
293 MFEM_ASSERT(
a <= A,
"");
294 const uintptr_t
b =
a + bytes;
295 const uintptr_t B =
b & ~pagemask;
296 MFEM_ASSERT(B <=
b,
"");
297 const uintptr_t length = B > A ? B - A : 0;
298 MFEM_ASSERT(length % pagesize == 0,
"");
303inline uintptr_t MmuLengthP(
const void *ptr,
const size_t bytes)
306 const uintptr_t
a = (uintptr_t) ptr;
307 const uintptr_t A = (uintptr_t) MmuAddrP(ptr);
308 MFEM_ASSERT(A <=
a,
"");
309 const uintptr_t
b =
a + bytes;
310 const uintptr_t B =
b & pagemask ? (
b + pagesize) & ~pagemask :
b;
311 MFEM_ASSERT(
b <= B,
"");
312 MFEM_ASSERT(B >= A,
"");
313 const uintptr_t length = B - A;
314 MFEM_ASSERT(length % pagesize == 0,
"");
319static void MmuError(
int sig, siginfo_t *si,
void* context)
321 constexpr size_t buf_size = 64;
324 const void *ptr = si->si_addr;
325 snprintf(str, buf_size,
"Error while accessing address %p!", ptr);
326 mfem::out << std::endl <<
"An illegal memory access was made!";
327 mfem::out << std::endl <<
"Caught signal " << sig <<
", code " << si->si_code <<
328 " at " << ptr << std::endl;
330 struct sigaction *old_action = (sig == SIGSEGV) ? &old_segv_action :
332 if (old_action->sa_flags & SA_SIGINFO && old_action->sa_sigaction)
335 old_action->sa_sigaction(sig, si, context);
337 else if (old_action->sa_handler == SIG_DFL)
340 sigaction(sig, old_action, NULL);
349 if (pagesize > 0) {
return; }
351 sa.sa_flags = SA_SIGINFO;
352 sigemptyset(&sa.sa_mask);
353 sa.sa_sigaction = MmuError;
354 if (sigaction(SIGBUS, &sa, &old_bus_action) == -1) {
mfem_error(
"SIGBUS"); }
355 if (sigaction(SIGSEGV, &sa, &old_segv_action) == -1) {
mfem_error(
"SIGSEGV"); }
356 pagesize = (uintptr_t) sysconf(_SC_PAGE_SIZE);
357 MFEM_ASSERT(pagesize > 0,
"pagesize must not be less than 1");
358 pagemask = pagesize - 1;
362inline void MmuAlloc(
void **ptr,
const size_t bytes)
364 const size_t length = bytes == 0 ? 8 : bytes;
365 const int prot = PROT_READ | PROT_WRITE;
366 const int flags = MAP_ANONYMOUS | MAP_PRIVATE;
367 *ptr = ::mmap(NULL, length, prot, flags, -1, 0);
368 if (*ptr == MAP_FAILED) { throw ::std::bad_alloc(); }
372inline void MmuDealloc(
void *ptr,
const size_t bytes)
374 const size_t length = bytes == 0 ? 8 : bytes;
375 if (::munmap(ptr, length) == -1) {
mfem_error(
"Dealloc error!"); }
379inline void MmuProtect(
const void *ptr,
const size_t bytes)
381 static const bool mmu_protect_error =
GetEnv(
"MFEM_MMU_PROTECT_ERROR");
382 if (!::mprotect(
const_cast<void*
>(ptr), bytes, PROT_NONE)) {
return; }
383 if (mmu_protect_error) {
mfem_error(
"MMU protection (NONE) error"); }
387inline void MmuAllow(
const void *ptr,
const size_t bytes)
389 const int RW = PROT_READ | PROT_WRITE;
390 static const bool mmu_protect_error =
GetEnv(
"MFEM_MMU_PROTECT_ERROR");
391 if (!::mprotect(
const_cast<void*
>(ptr), bytes, RW)) {
return; }
392 if (mmu_protect_error) {
mfem_error(
"MMU protection (R/W) error"); }
395inline void MmuInit() { }
396inline void MmuAlloc(
void **ptr,
const size_t bytes) { *ptr = std::malloc(bytes); }
397inline void MmuDealloc(
void *ptr,
const size_t) { std::free(ptr); }
398inline void MmuProtect(
const void*,
const size_t) { }
399inline void MmuAllow(
const void*,
const size_t) { }
400inline const void *MmuAddrR(
const void *
a) {
return a; }
401inline const void *MmuAddrP(
const void *
a) {
return a; }
402inline uintptr_t MmuLengthR(
const void*,
const size_t) {
return 0; }
403inline uintptr_t MmuLengthP(
const void*,
const size_t) {
return 0; }
407class MmuHostMemorySpace :
public HostMemorySpace
410 MmuHostMemorySpace(): HostMemorySpace() { MmuInit(); }
411 void Alloc(
void **ptr,
size_t bytes)
override { MmuAlloc(ptr, bytes); }
412 void Dealloc(
void *ptr)
override { MmuDealloc(ptr, maps->memories.at(ptr).bytes); }
413 void Protect(
const Memory& mem,
size_t bytes)
override
414 {
if (mem.h_rw) { mem.h_rw =
false; MmuProtect(mem.h_ptr, bytes); } }
415 void Unprotect(
const Memory &mem,
size_t bytes)
override
416 {
if (!mem.h_rw) { mem.h_rw =
true; MmuAllow(mem.h_ptr, bytes); } }
418 void AliasProtect(
const void *ptr,
size_t bytes)
override
419 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
421 void AliasUnprotect(
const void *ptr,
size_t bytes)
override
422 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
426class UvmHostMemorySpace :
public HostMemorySpace
429 UvmHostMemorySpace(): HostMemorySpace() { }
431 void Alloc(
void **ptr,
size_t bytes)
override
441 void Dealloc(
void *ptr)
override
453class NoDeviceMemorySpace:
public DeviceMemorySpace
456 void Alloc(internal::Memory&)
override {
mfem_error(
"! Device Alloc"); }
457 void Dealloc(Memory&)
override {
mfem_error(
"! Device Dealloc"); }
458 void *HtoD(
void*,
const void*,
size_t)
override {
mfem_error(
"!HtoD");
return nullptr; }
459 void *DtoD(
void*,
const void*,
size_t)
override {
mfem_error(
"!DtoD");
return nullptr; }
460 void *DtoH(
void*,
const void*,
size_t)
override {
mfem_error(
"!DtoH");
return nullptr; }
464class StdDeviceMemorySpace :
public DeviceMemorySpace { };
467class CudaDeviceMemorySpace:
public DeviceMemorySpace
470 CudaDeviceMemorySpace(): DeviceMemorySpace() { }
471 void Alloc(Memory &base)
override {
CuMemAlloc(&base.d_ptr, base.bytes); }
472 void Dealloc(Memory &base)
override {
CuMemFree(base.d_ptr); }
473 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
475 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
477 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
482class HostPinnedMemorySpace:
public HostMemorySpace
485 HostPinnedMemorySpace(): HostMemorySpace() { }
486 void Alloc(
void ** ptr,
size_t bytes)
override
495 void Dealloc(
void *ptr)
override
507class HipDeviceMemorySpace:
public DeviceMemorySpace
510 HipDeviceMemorySpace(): DeviceMemorySpace() { }
511 void Alloc(Memory &base)
override {
HipMemAlloc(&base.d_ptr, base.bytes); }
512 void Dealloc(Memory &base)
override {
HipMemFree(base.d_ptr); }
513 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
515 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
517 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
522class UvmCudaMemorySpace :
public DeviceMemorySpace
525 void Alloc(Memory &base)
override { base.d_ptr = base.h_ptr; }
526 void Dealloc(Memory&)
override { }
527 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
529 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
532 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
534 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
536 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
541class UvmHipMemorySpace :
public DeviceMemorySpace
544 void Alloc(Memory &base) { base.d_ptr = base.h_ptr; }
545 void Dealloc(Memory&) { }
546 void *HtoD(
void *dst,
const void *src,
size_t bytes)
548 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
551 void *DtoD(
void* dst,
const void* src,
size_t bytes)
553 void *DtoH(
void *dst,
const void *src,
size_t bytes)
555 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
561class MmuDeviceMemorySpace :
public DeviceMemorySpace
564 MmuDeviceMemorySpace(): DeviceMemorySpace() { }
565 void Alloc(Memory &m)
override { MmuAlloc(&m.d_ptr, m.bytes); }
566 void Dealloc(Memory &m)
override { MmuDealloc(m.d_ptr, m.bytes); }
567 void Protect(
const Memory &m)
override
568 {
if (m.d_rw) { m.d_rw =
false; MmuProtect(m.d_ptr, m.bytes); } }
569 void Unprotect(
const Memory &m)
override
570 {
if (!m.d_rw) { m.d_rw =
true; MmuAllow(m.d_ptr, m.bytes); } }
572 void AliasProtect(
const void *ptr,
size_t bytes)
override
573 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
575 void AliasUnprotect(
const void *ptr,
size_t bytes)
override
576 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
577 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
578 {
return std::memcpy(dst, src, bytes); }
579 void *DtoD(
void *dst,
const void *src,
size_t bytes)
override
580 {
return std::memcpy(dst, src, bytes); }
581 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
582 {
return std::memcpy(dst, src, bytes); }
585#ifdef MFEM_USE_UMPIRE
586class UmpireMemorySpace
589 umpire::ResourceManager &rm;
590 umpire::Allocator allocator;
591 bool owns_allocator{
false};
595 virtual ~UmpireMemorySpace() {
if (owns_allocator) { allocator.release(); } }
596 UmpireMemorySpace(
const char * name,
const char *
space)
597 : rm(umpire::ResourceManager::getInstance())
599 if (!rm.isAllocator(name))
601 allocator = rm.makeAllocator<umpire::strategy::QuickPool>(
602 name, rm.getAllocator(
space));
603 owns_allocator =
true;
607 allocator = rm.getAllocator(name);
608 owns_allocator =
false;
614class UmpireHostMemorySpace :
public HostMemorySpace,
public UmpireMemorySpace
617 umpire::strategy::AllocationStrategy *strat;
619 UmpireHostMemorySpace(
const char * name)
621 UmpireMemorySpace(name,
"HOST"),
622 strat(allocator.getAllocationStrategy()) {}
623 void Alloc(
void **ptr,
size_t bytes)
override
624 { *ptr = allocator.allocate(bytes); }
625 void Dealloc(
void *ptr)
override { allocator.deallocate(ptr); }
626 void Insert(
void *ptr,
size_t bytes)
627 { rm.registerAllocation(ptr, {ptr, bytes, strat}); }
631#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
632class UmpireDeviceMemorySpace :
public DeviceMemorySpace,
633 public UmpireMemorySpace
636 UmpireDeviceMemorySpace(
const char * name)
637 : DeviceMemorySpace(),
638 UmpireMemorySpace(name,
"DEVICE") {}
639 void Alloc(Memory &base)
override
640 { base.d_ptr = allocator.allocate(base.bytes); }
641 void Dealloc(Memory &base)
override { allocator.deallocate(base.d_ptr); }
642 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
652 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
662 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
674class UmpireDeviceMemorySpace :
public NoDeviceMemorySpace
677 UmpireDeviceMemorySpace(
const char * ) {}
692 Ctrl(): host{nullptr}, device{nullptr} { }
696 if (host[HostMemoryType])
698 mfem_error(
"Memory backends have already been configured!");
704 host[
static_cast<int>(MT::HOST)] =
new StdHostMemorySpace();
705 host[
static_cast<int>(MT::HOST_32)] =
new Aligned32HostMemorySpace();
706 host[
static_cast<int>(MT::HOST_64)] =
new Aligned64HostMemorySpace();
708 host[
static_cast<int>(MT::HOST_DEBUG)] =
nullptr;
709 host[
static_cast<int>(MT::HOST_UMPIRE)] =
nullptr;
710 host[
static_cast<int>(MT::MANAGED)] =
new UvmHostMemorySpace();
714#if defined(MFEM_USE_CUDA)
715 device[
static_cast<int>(MT::MANAGED)-shift] =
new UvmCudaMemorySpace();
716#elif defined(MFEM_USE_HIP)
717 device[
static_cast<int>(MT::MANAGED)-shift] =
new UvmHipMemorySpace();
720 device[
static_cast<int>(MT::MANAGED)-shift] =
new UvmCudaMemorySpace();
724 device[
static_cast<int>(MemoryType::DEVICE)-shift] =
nullptr;
725 device[
static_cast<int>(MT::DEVICE_DEBUG)-shift] =
nullptr;
726 device[
static_cast<int>(MT::DEVICE_UMPIRE)-shift] =
nullptr;
727 device[
static_cast<int>(MT::DEVICE_UMPIRE_2)-shift] =
nullptr;
730 HostMemorySpace* Host(
const MemoryType mt)
732 const int mt_i =
static_cast<int>(mt);
734 if (!host[mt_i]) { host[mt_i] = NewHostCtrl(mt); }
735 MFEM_ASSERT(host[mt_i],
"Host memory controller is not configured!");
739 DeviceMemorySpace* Device(
const MemoryType mt)
741 const int mt_i =
static_cast<int>(mt) - DeviceMemoryType;
742 MFEM_ASSERT(mt_i >= 0,
"");
744 if (!device[mt_i]) { device[mt_i] = NewDeviceCtrl(mt); }
745 MFEM_ASSERT(device[mt_i],
"Memory manager has not been configured!");
754 for (
int mt = mt_d; mt <
MemoryTypeSize; mt++) {
delete device[mt-mt_d]; }
758 HostMemorySpace* NewHostCtrl(
const MemoryType mt)
763 if (
GetEnv(
"MFEM_MMU_STD")) {
return new StdHostMemorySpace(); }
764 return new MmuHostMemorySpace();
765#ifdef MFEM_USE_UMPIRE
766 case MT::HOST_UMPIRE:
767 return new UmpireHostMemorySpace(
768 MemoryManager::GetUmpireHostAllocatorName());
770 case MT::HOST_UMPIRE:
return new NoHostMemorySpace();
772 case MT::HOST_PINNED:
return new HostPinnedMemorySpace();
773 default: MFEM_ABORT(
"Unknown host memory controller!");
778 DeviceMemorySpace* NewDeviceCtrl(
const MemoryType mt)
782#ifdef MFEM_USE_UMPIRE
783 case MT::DEVICE_UMPIRE:
784 return new UmpireDeviceMemorySpace(
785 MemoryManager::GetUmpireDeviceAllocatorName());
786 case MT::DEVICE_UMPIRE_2:
787 return new UmpireDeviceMemorySpace(
788 MemoryManager::GetUmpireDevice2AllocatorName());
790 case MT::DEVICE_UMPIRE:
return new NoDeviceMemorySpace();
791 case MT::DEVICE_UMPIRE_2:
return new NoDeviceMemorySpace();
793 case MT::DEVICE_DEBUG:
794 if (
GetEnv(
"MFEM_MMU_STD")) {
return new StdDeviceMemorySpace(); }
795 return new MmuDeviceMemorySpace();
798#if defined(MFEM_USE_CUDA)
799 return new CudaDeviceMemorySpace();
800#elif defined(MFEM_USE_HIP)
801 return new HipDeviceMemorySpace();
803 MFEM_ABORT(
"No device memory controller!");
807 default: MFEM_ABORT(
"Unknown device memory controller!");
815static internal::Ctrl *ctrl;
817void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType mt,
820 MFEM_ASSERT(exists,
"Internal error!");
839void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType h_mt,
843 MFEM_ASSERT(exists,
"Internal error!");
844 MFEM_ASSERT(
IsHostMemory(h_mt),
"h_mt must be host type");
847 "d_mt must be device type, the same is h_mt, or DEFAULT");
854 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
855 else { h_ptr = h_tmp; }
859 mm.Insert(h_ptr, bytes, h_mt, d_mt);
863 CheckHostMemoryType_(h_mt, h_ptr,
false);
868void *MemoryManager::Register_(
void *ptr,
void *h_tmp,
size_t bytes,
870 bool own,
bool alias,
unsigned &flags)
872 MFEM_ASSERT(exists,
"Internal error!");
880 MFEM_VERIFY_TYPES(h_mt, d_mt);
882 if (ptr ==
nullptr && h_tmp ==
nullptr)
884 MFEM_VERIFY(bytes == 0,
"internal error");
888 MFEM_VERIFY(!alias,
"Cannot register an alias!");
896 mm.Insert(h_ptr, bytes, h_mt, d_mt);
897 flags = (own ? flags |
Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST) |
902 MFEM_VERIFY(ptr || bytes == 0,
903 "cannot register NULL device pointer with bytes = " << bytes);
904 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
905 else { h_ptr = h_tmp; }
906 mm.InsertDevice(ptr, h_ptr, bytes, h_mt, d_mt);
910 CheckHostMemoryType_(h_mt, h_ptr, alias);
914void MemoryManager::Register2_(
void *h_ptr,
void *d_ptr,
size_t bytes,
916 bool own,
bool alias,
unsigned &flags,
917 unsigned valid_flags)
919 MFEM_CONTRACT_VAR(alias);
920 MFEM_ASSERT(exists,
"Internal error!");
921 MFEM_ASSERT(!alias,
"Cannot register an alias!");
922 MFEM_VERIFY_TYPES(h_mt, d_mt);
924 if (h_ptr ==
nullptr && d_ptr ==
nullptr)
926 MFEM_VERIFY(bytes == 0,
"internal error");
932 MFEM_VERIFY(d_ptr || bytes == 0,
933 "cannot register NULL device pointer with bytes = " << bytes);
934 mm.InsertDevice(d_ptr, h_ptr, bytes, h_mt, d_mt);
936 flags & ~(Mem::OWNS_HOST | Mem::OWNS_DEVICE)) |
939 CheckHostMemoryType_(h_mt, h_ptr, alias);
942void MemoryManager::Alias_(
void *base_h_ptr,
size_t offset,
size_t bytes,
943 unsigned base_flags,
unsigned &flags)
945 mm.InsertAlias(base_h_ptr, (
char*)base_h_ptr + offset, bytes,
951void MemoryManager::SetDeviceMemoryType_(
void *h_ptr,
unsigned flags,
954 MFEM_VERIFY(h_ptr,
"cannot set the device memory type: Memory is empty!");
957 auto mem_iter = maps->memories.find(h_ptr);
958 MFEM_VERIFY(mem_iter != maps->memories.end(),
"internal error");
959 internal::Memory &mem = mem_iter->second;
960 if (mem.d_mt == d_mt) {
return; }
961 MFEM_VERIFY(mem.d_ptr ==
nullptr,
"cannot set the device memory type:"
962 " device memory is allocated!");
967 auto alias_iter = maps->aliases.find(h_ptr);
968 MFEM_VERIFY(alias_iter != maps->aliases.end(),
"internal error");
969 internal::Alias &alias = alias_iter->second;
970 internal::Memory &base_mem = *alias.mem;
971 if (base_mem.d_mt == d_mt) {
return; }
972 MFEM_VERIFY(base_mem.d_ptr ==
nullptr,
973 "cannot set the device memory type:"
974 " alias' base device memory is allocated!");
975 base_mem.d_mt = d_mt;
979void MemoryManager::Delete_(
void *h_ptr,
MemoryType h_mt,
unsigned flags)
986 MFEM_ASSERT(
IsHostMemory(h_mt),
"invalid h_mt = " << (
int)h_mt);
988 MFEM_ASSERT(!owns_device || owns_internal,
"invalid Memory state");
993 MFEM_ASSERT(registered || !(owns_host || owns_device || owns_internal) ||
994 (!(owns_device || owns_internal) && h_ptr ==
nullptr),
995 "invalid Memory state");
996 if (!
mm.exists || !registered) {
return; }
1002 MFEM_ASSERT(h_mt == maps->aliases.at(h_ptr).h_mt,
"");
1003 mm.EraseAlias(h_ptr);
1009 { ctrl->Host(h_mt)->Dealloc(h_ptr); }
1013 MFEM_ASSERT(h_mt == maps->memories.at(h_ptr).h_mt,
"");
1014 mm.Erase(h_ptr, owns_device);
1019void MemoryManager::DeleteDevice_(
void *h_ptr,
unsigned & flags)
1024 mm.EraseDevice(h_ptr);
1029bool MemoryManager::MemoryClassCheck_(
MemoryClass mc,
void *h_ptr,
1035 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1041 auto iter = maps->memories.find(h_ptr);
1042 MFEM_VERIFY(iter != maps->memories.end(),
"internal error");
1043 d_mt = iter->second.d_mt;
1047 auto iter = maps->aliases.find(h_ptr);
1048 MFEM_VERIFY(iter != maps->aliases.end(),
"internal error");
1049 d_mt = iter->second.mem->d_mt;
1086 size_t bytes,
unsigned &flags)
1088 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1090 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1096 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1097 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1104 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1105 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1110 size_t bytes,
unsigned &flags)
1112 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1114 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1120 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1121 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1128 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1129 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1134 size_t bytes,
unsigned &flags)
1136 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1138 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1143 {
return mm.GetAliasHostPtr(h_ptr, bytes,
false); }
1144 else {
return mm.GetHostPtr(h_ptr, bytes,
false); }
1150 {
return mm.GetAliasDevicePtr(h_ptr, bytes,
false); }
1151 else {
return mm.GetDevicePtr(h_ptr, bytes,
false); }
1155void MemoryManager::SyncAlias_(
const void *base_h_ptr,
void *alias_h_ptr,
1156 size_t alias_bytes,
unsigned base_flags,
1157 unsigned &alias_flags)
1161 MFEM_ASSERT(alias_flags &
Mem::ALIAS,
"not an alias");
1164 mm.GetAliasHostPtr(alias_h_ptr, alias_bytes,
true);
1170 mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags &
Mem::ALIAS);
1174 mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes,
true);
1180MemoryType MemoryManager::GetDeviceMemoryType_(
void *h_ptr,
bool alias)
1186 auto iter = maps->memories.find(h_ptr);
1187 MFEM_ASSERT(iter != maps->memories.end(),
"internal error");
1188 return iter->second.d_mt;
1191 auto iter = maps->aliases.find(h_ptr);
1192 MFEM_ASSERT(iter != maps->aliases.end(),
"internal error");
1193 return iter->second.mem->d_mt;
1195 MFEM_ABORT(
"internal error");
1196 return MemoryManager::host_mem_type;
1199MemoryType MemoryManager::GetHostMemoryType_(
void *h_ptr)
1201 if (!
mm.exists) {
return MemoryManager::host_mem_type; }
1202 if (
mm.
IsKnown(h_ptr)) {
return maps->memories.at(h_ptr).h_mt; }
1203 if (
mm.
IsAlias(h_ptr)) {
return maps->aliases.at(h_ptr).h_mt; }
1204 return MemoryManager::host_mem_type;
1207void MemoryManager::Copy_(
void *dst_h_ptr,
const void *src_h_ptr,
1208 size_t bytes,
unsigned src_flags,
1209 unsigned &dst_flags)
1219 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1220 MFEM_ASSERT(dst_h_ptr !=
nullptr,
"invalid dst_h_ptr = nullptr");
1221 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1223 const bool dst_on_host =
1228 dst_flags = dst_flags &
1231 const bool src_on_host =
1236 const void *src_d_ptr =
1237 src_on_host ? NULL :
1239 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1240 mm.GetDevicePtr(src_h_ptr, bytes,
false));
1246 if (dst_h_ptr != src_h_ptr && bytes != 0)
1248 MFEM_ASSERT((
const char*)dst_h_ptr + bytes <= src_h_ptr ||
1249 (
const char*)src_h_ptr + bytes <= dst_h_ptr,
1251 std::memcpy(dst_h_ptr, src_h_ptr, bytes);
1256 if (dst_h_ptr != src_d_ptr && bytes != 0)
1259 maps->aliases.at(src_h_ptr).mem->d_mt :
1260 maps->memories.at(src_h_ptr).d_mt;
1261 ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
1267 void *dest_d_ptr = (dst_flags &
Mem::ALIAS) ?
1268 mm.GetAliasDevicePtr(dst_h_ptr, bytes,
false) :
1269 mm.GetDevicePtr(dst_h_ptr, bytes,
false);
1272 const bool known =
mm.
IsKnown(dst_h_ptr);
1274 MFEM_VERIFY(alias||known,
"");
1276 maps->memories.at(dst_h_ptr).d_mt :
1277 maps->aliases.at(dst_h_ptr).mem->d_mt;
1278 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1282 if (dest_d_ptr != src_d_ptr && bytes != 0)
1284 const bool known =
mm.
IsKnown(dst_h_ptr);
1286 MFEM_VERIFY(alias||known,
"");
1288 maps->memories.at(dst_h_ptr).d_mt :
1289 maps->aliases.at(dst_h_ptr).mem->d_mt;
1290 ctrl->Device(d_mt)->DtoD(dest_d_ptr, src_d_ptr, bytes);
1296void MemoryManager::CopyToHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1297 size_t bytes,
unsigned src_flags)
1299 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1300 MFEM_ASSERT(dest_h_ptr !=
nullptr,
"invalid dest_h_ptr = nullptr");
1301 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1306 if (dest_h_ptr != src_h_ptr && bytes != 0)
1308 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1309 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1311 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1316 MFEM_ASSERT(IsKnown_(src_h_ptr),
"internal error");
1317 const void *src_d_ptr = (src_flags &
Mem::ALIAS) ?
1318 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1319 mm.GetDevicePtr(src_h_ptr, bytes,
false);
1321 maps->aliases.at(src_h_ptr).mem->d_mt :
1322 maps->memories.at(src_h_ptr).d_mt;
1323 ctrl->Device(src_d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
1327void MemoryManager::CopyFromHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1328 size_t bytes,
unsigned &dest_flags)
1330 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1331 MFEM_ASSERT(dest_h_ptr !=
nullptr,
"invalid dest_h_ptr = nullptr");
1332 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1337 if (dest_h_ptr != src_h_ptr && bytes != 0)
1339 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1340 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1342 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1347 void *dest_d_ptr = (dest_flags &
Mem::ALIAS) ?
1348 mm.GetAliasDevicePtr(dest_h_ptr, bytes,
false) :
1349 mm.GetDevicePtr(dest_h_ptr, bytes,
false);
1351 maps->aliases.at(dest_h_ptr).mem->d_mt :
1352 maps->memories.at(dest_h_ptr).d_mt;
1353 ctrl->Device(dest_d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1355 dest_flags = dest_flags &
1359bool MemoryManager::IsKnown_(
const void *h_ptr)
1361 return maps->memories.find(h_ptr) != maps->memories.end();
1364bool MemoryManager::IsAlias_(
const void *h_ptr)
1366 return maps->aliases.find(h_ptr) != maps->aliases.end();
1369void MemoryManager::Insert(
void *h_ptr,
size_t bytes,
1372#ifdef MFEM_TRACK_MEM_MANAGER
1373 mfem::out <<
"[mfem memory manager]: registering h_ptr: " << h_ptr
1374 <<
", bytes: " << bytes << std::endl;
1378 MFEM_VERIFY(bytes == 0,
"Trying to add NULL with size " << bytes);
1381 MFEM_VERIFY_TYPES(h_mt, d_mt);
1385 maps->memories.emplace(h_ptr, internal::Memory(h_ptr, bytes, h_mt, d_mt));
1387 if (res.second ==
false)
1389 auto &m = res.first->second;
1390 MFEM_VERIFY(m.bytes >= bytes && m.h_mt == h_mt &&
1396 "Address already present with different attributes!");
1397#ifdef MFEM_TRACK_MEM_MANAGER
1398 mfem::out <<
"[mfem memory manager]: repeated registration of h_ptr: "
1399 << h_ptr << std::endl;
1405void MemoryManager::InsertDevice(
void *d_ptr,
void *h_ptr,
size_t bytes,
1409 MFEM_ASSERT(h_ptr != NULL,
"internal error");
1410 Insert(h_ptr, bytes, h_mt, d_mt);
1411 internal::Memory &mem = maps->memories.at(h_ptr);
1412 if (d_ptr == NULL && bytes != 0) { ctrl->Device(d_mt)->Alloc(mem); }
1413 else { mem.d_ptr = d_ptr; }
1416void MemoryManager::InsertAlias(
const void *base_ptr,
void *alias_ptr,
1417 const size_t bytes,
const bool base_is_alias)
1419 size_t offset =
static_cast<size_t>(
static_cast<const char*
>(alias_ptr) -
1420 static_cast<const char*
>(base_ptr));
1421#ifdef MFEM_TRACK_MEM_MANAGER
1422 mfem::out <<
"[mfem memory manager]: registering alias of base_ptr: "
1423 << base_ptr <<
", offset: " << offset <<
", bytes: " << bytes
1424 <<
", base is alias: " << base_is_alias << std::endl;
1428 MFEM_VERIFY(offset == 0,
1429 "Trying to add alias to NULL at offset " << offset);
1434 const internal::Alias &alias = maps->aliases.at(base_ptr);
1435 MFEM_ASSERT(alias.mem,
"");
1436 base_ptr = alias.mem->h_ptr;
1437 offset += alias.offset;
1438#ifdef MFEM_TRACK_MEM_MANAGER
1439 mfem::out <<
"[mfem memory manager]: real base_ptr: " << base_ptr
1443 internal::Memory &mem = maps->memories.at(base_ptr);
1444 MFEM_VERIFY(offset + bytes <= mem.bytes,
"invalid alias");
1446 maps->aliases.emplace(alias_ptr,
1447 internal::Alias{&mem, offset, 1, mem.h_mt});
1448 if (res.second ==
false)
1450 internal::Alias &alias = res.first->second;
1453 alias.offset = offset;
1454 alias.h_mt = mem.h_mt;
1459void MemoryManager::Erase(
void *h_ptr,
bool free_dev_ptr)
1461#ifdef MFEM_TRACK_MEM_MANAGER
1462 mfem::out <<
"[mfem memory manager]: un-registering h_ptr: " << h_ptr
1465 if (!h_ptr) {
return; }
1466 auto mem_map_iter = maps->memories.find(h_ptr);
1467 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1468 internal::Memory &mem = mem_map_iter->second;
1469 if (mem.d_ptr && free_dev_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1470 maps->memories.erase(mem_map_iter);
1473void MemoryManager::EraseDevice(
void *h_ptr)
1475 if (!h_ptr) {
return; }
1476 auto mem_map_iter = maps->memories.find(h_ptr);
1477 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1478 internal::Memory &mem = mem_map_iter->second;
1479 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1480 mem.d_ptr =
nullptr;
1483void MemoryManager::EraseAlias(
void *alias_ptr)
1485#ifdef MFEM_TRACK_MEM_MANAGER
1486 mfem::out <<
"[mfem memory manager]: un-registering alias_ptr: " << alias_ptr
1489 if (!alias_ptr) {
return; }
1490 auto alias_map_iter = maps->aliases.find(alias_ptr);
1491 if (alias_map_iter == maps->aliases.end()) {
mfem_error(
"Unknown alias!"); }
1492 internal::Alias &alias = alias_map_iter->second;
1493 if (--alias.counter) {
return; }
1494 maps->aliases.erase(alias_map_iter);
1497void *MemoryManager::GetDevicePtr(
const void *h_ptr,
size_t bytes,
1502 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1505 internal::Memory &mem = maps->memories.at(h_ptr);
1508 MFEM_VERIFY_TYPES(h_mt, d_mt);
1512 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1515 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1518 MFEM_ASSERT(bytes <= mem.bytes,
"invalid copy size");
1519 if (bytes) { ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes); }
1521 ctrl->Host(h_mt)->Protect(mem, bytes);
1525void *MemoryManager::GetAliasDevicePtr(
const void *alias_ptr,
size_t bytes,
1530 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1533 auto &alias_map = maps->aliases;
1534 auto alias_map_iter = alias_map.find(alias_ptr);
1535 if (alias_map_iter == alias_map.end()) {
mfem_error(
"alias not found"); }
1536 const internal::Alias &alias = alias_map_iter->second;
1537 const size_t offset = alias.offset;
1538 internal::Memory &mem = *alias.mem;
1541 MFEM_VERIFY_TYPES(h_mt, d_mt);
1545 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1547 void *alias_h_ptr =
static_cast<char*
>(mem.h_ptr) + offset;
1548 void *alias_d_ptr =
static_cast<char*
>(mem.d_ptr) + offset;
1549 MFEM_ASSERT(alias_h_ptr == alias_ptr,
"internal error");
1550 MFEM_ASSERT(offset + bytes <= mem.bytes,
"internal error");
1551 mem.d_rw = mem.h_rw =
false;
1552 if (mem.d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1553 ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
1554 if (copy && mem.d_ptr)
1555 { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
1556 ctrl->Host(h_mt)->AliasProtect(alias_ptr, bytes);
1560void *MemoryManager::GetHostPtr(
const void *ptr,
size_t bytes,
bool copy)
1562 const internal::Memory &mem = maps->memories.at(ptr);
1563 MFEM_ASSERT(mem.h_ptr == ptr,
"internal error");
1564 MFEM_ASSERT(bytes <= mem.bytes,
"internal error")
1567 MFEM_VERIFY_TYPES(h_mt, d_mt);
1569 ctrl->Host(h_mt)->Unprotect(mem, bytes);
1570 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1571 if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
1572 if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
1576void *MemoryManager::GetAliasHostPtr(
const void *ptr,
size_t bytes,
1579 const internal::Alias &alias = maps->aliases.at(ptr);
1580 const internal::Memory *
const mem = alias.mem;
1583 MFEM_VERIFY_TYPES(h_mt, d_mt);
1584 void *alias_h_ptr =
static_cast<char*
>(mem->h_ptr) + alias.offset;
1585 void *alias_d_ptr =
static_cast<char*
>(mem->d_ptr) + alias.offset;
1586 MFEM_ASSERT(alias_h_ptr == ptr,
"internal error");
1588 ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
1589 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1590 if (copy_data && mem->d_ptr)
1591 { ctrl->Device(d_mt)->DtoH(
const_cast<void*
>(ptr), alias_d_ptr, bytes); }
1592 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasProtect(alias_d_ptr, bytes); }
1598 if (exists) {
return; }
1599 maps =
new internal::Maps();
1600 ctrl =
new internal::Ctrl();
1611 MFEM_VERIFY(!configured,
"changing the dual MemoryTypes is not allowed after"
1612 " MemoryManager configuration!");
1613 UpdateDualMemoryType(mt, dual_mt);
1619 "invalid MemoryType, mt = " << (
int)mt);
1621 "invalid dual MemoryType, dual_mt = " << (
int)dual_mt);
1626 dual_map[(int)mt] = dual_mt;
1634 "invalid (mt, dual_mt) pair: ("
1643 MemoryManager::UpdateDualMemoryType(host_mt, device_mt);
1644 MemoryManager::UpdateDualMemoryType(device_mt, host_mt);
1649 MemoryManager::UpdateDualMemoryType(
1654 host_mem_type = host_mt;
1655 device_mem_type = device_mt;
1661 MFEM_VERIFY(exists,
"MemoryManager has already been destroyed!");
1662#ifdef MFEM_TRACK_MEM_MANAGER
1663 size_t num_memories = maps->memories.size();
1664 size_t num_aliases = maps->aliases.size();
1665 if (num_memories != 0 || num_aliases != 0)
1667 MFEM_WARNING(
"...\n\t number of registered pointers: " << num_memories
1668 <<
"\n\t number of registered aliases : " << num_aliases);
1673 mfem::out <<
"Destroying the MemoryManager ...\n"
1674 <<
"remaining registered pointers : "
1675 << maps->memories.size() <<
'\n'
1676 <<
"remaining registered aliases : "
1677 << maps->aliases.size() <<
'\n';
1679 for (
auto& n : maps->memories)
1681 internal::Memory &mem = n.second;
1683 if (mem_h_ptr) { ctrl->Host(mem.h_mt)->Dealloc(mem.h_ptr); }
1684 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem); }
1686 delete maps; maps =
nullptr;
1687 delete ctrl; ctrl =
nullptr;
1708 for (
const auto& n : maps->memories)
1710 const internal::Memory &mem = n.second;
1711 os <<
"\nkey " << n.first <<
", "
1712 <<
"h_ptr " << mem.h_ptr <<
", "
1713 <<
"d_ptr " << mem.d_ptr;
1716 if (maps->memories.size() > 0) { os << std::endl; }
1723 for (
const auto& n : maps->aliases)
1725 const internal::Alias &alias = n.second;
1726 os <<
"\nalias: key " << n.first <<
", "
1727 <<
"h_ptr " << alias.mem->h_ptr <<
", "
1728 <<
"offset " << alias.offset <<
", "
1729 <<
"counter " << alias.counter;
1732 if (maps->aliases.size() > 0) { os << std::endl; }
1736int MemoryManager::CompareHostAndDevice_(
void *h_ptr,
size_t size,
1740 mm.GetAliasDevicePtr(h_ptr, size,
false) :
1741 mm.GetDevicePtr(h_ptr, size,
false);
1742 char *h_buf =
new char[size];
1743#if defined(MFEM_USE_CUDA)
1745#elif defined(MFEM_USE_HIP)
1748 std::memcpy(h_buf, d_ptr, size);
1750 int res = std::memcmp(h_ptr, h_buf, size);
1760 <<
"\n registered = " << bool(flags & Mem::Registered)
1761 <<
"\n owns host = " << bool(flags & Mem::OWNS_HOST)
1762 <<
"\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
1763 <<
"\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
1764 <<
"\n valid host = " << bool(flags & Mem::VALID_HOST)
1765 <<
"\n valid device = " << bool(flags & Mem::VALID_DEVICE)
1766 <<
"\n device flag = " << bool(flags & Mem::USE_DEVICE)
1767 <<
"\n alias = " << bool(flags & Mem::ALIAS)