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)
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)
762 case MT::HOST_DEBUG:
return new MmuHostMemorySpace();
763#ifdef MFEM_USE_UMPIRE
764 case MT::HOST_UMPIRE:
765 return new UmpireHostMemorySpace(
766 MemoryManager::GetUmpireHostAllocatorName());
768 case MT::HOST_UMPIRE:
return new NoHostMemorySpace();
770 case MT::HOST_PINNED:
return new HostPinnedMemorySpace();
771 default: MFEM_ABORT(
"Unknown host memory controller!");
776 DeviceMemorySpace* NewDeviceCtrl(
const MemoryType mt)
780#ifdef MFEM_USE_UMPIRE
781 case MT::DEVICE_UMPIRE:
782 return new UmpireDeviceMemorySpace(
783 MemoryManager::GetUmpireDeviceAllocatorName());
784 case MT::DEVICE_UMPIRE_2:
785 return new UmpireDeviceMemorySpace(
786 MemoryManager::GetUmpireDevice2AllocatorName());
788 case MT::DEVICE_UMPIRE:
return new NoDeviceMemorySpace();
789 case MT::DEVICE_UMPIRE_2:
return new NoDeviceMemorySpace();
791 case MT::DEVICE_DEBUG:
return new MmuDeviceMemorySpace();
794#if defined(MFEM_USE_CUDA)
795 return new CudaDeviceMemorySpace();
796#elif defined(MFEM_USE_HIP)
797 return new HipDeviceMemorySpace();
799 MFEM_ABORT(
"No device memory controller!");
803 default: MFEM_ABORT(
"Unknown device memory controller!");
811static internal::Ctrl *ctrl;
813void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType mt,
816 MFEM_ASSERT(exists,
"Internal error!");
835void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType h_mt,
839 MFEM_ASSERT(exists,
"Internal error!");
840 MFEM_ASSERT(
IsHostMemory(h_mt),
"h_mt must be host type");
843 "d_mt must be device type, the same is h_mt, or DEFAULT");
850 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
851 else { h_ptr = h_tmp; }
855 mm.Insert(h_ptr, bytes, h_mt, d_mt);
859 CheckHostMemoryType_(h_mt, h_ptr,
false);
864void *MemoryManager::Register_(
void *ptr,
void *h_tmp,
size_t bytes,
866 bool own,
bool alias,
unsigned &flags)
868 MFEM_ASSERT(exists,
"Internal error!");
876 MFEM_VERIFY_TYPES(h_mt, d_mt);
878 if (ptr ==
nullptr && h_tmp ==
nullptr)
880 MFEM_VERIFY(bytes == 0,
"internal error");
884 MFEM_VERIFY(!alias,
"Cannot register an alias!");
892 mm.Insert(h_ptr, bytes, h_mt, d_mt);
893 flags = (own ? flags |
Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST) |
898 MFEM_VERIFY(ptr || bytes == 0,
899 "cannot register NULL device pointer with bytes = " << bytes);
900 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
901 else { h_ptr = h_tmp; }
902 mm.InsertDevice(ptr, h_ptr, bytes, h_mt, d_mt);
906 CheckHostMemoryType_(h_mt, h_ptr, alias);
910void MemoryManager::Register2_(
void *h_ptr,
void *d_ptr,
size_t bytes,
912 bool own,
bool alias,
unsigned &flags,
913 unsigned valid_flags)
915 MFEM_CONTRACT_VAR(alias);
916 MFEM_ASSERT(exists,
"Internal error!");
917 MFEM_ASSERT(!alias,
"Cannot register an alias!");
918 MFEM_VERIFY_TYPES(h_mt, d_mt);
920 if (h_ptr ==
nullptr && d_ptr ==
nullptr)
922 MFEM_VERIFY(bytes == 0,
"internal error");
928 MFEM_VERIFY(d_ptr || bytes == 0,
929 "cannot register NULL device pointer with bytes = " << bytes);
930 mm.InsertDevice(d_ptr, h_ptr, bytes, h_mt, d_mt);
932 flags & ~(Mem::OWNS_HOST | Mem::OWNS_DEVICE)) |
935 CheckHostMemoryType_(h_mt, h_ptr, alias);
938void MemoryManager::Alias_(
void *base_h_ptr,
size_t offset,
size_t bytes,
939 unsigned base_flags,
unsigned &flags)
941 mm.InsertAlias(base_h_ptr, (
char*)base_h_ptr + offset, bytes,
947void MemoryManager::SetDeviceMemoryType_(
void *h_ptr,
unsigned flags,
950 MFEM_VERIFY(h_ptr,
"cannot set the device memory type: Memory is empty!");
953 auto mem_iter = maps->memories.find(h_ptr);
954 MFEM_VERIFY(mem_iter != maps->memories.end(),
"internal error");
955 internal::Memory &mem = mem_iter->second;
956 if (mem.d_mt == d_mt) {
return; }
957 MFEM_VERIFY(mem.d_ptr ==
nullptr,
"cannot set the device memory type:"
958 " device memory is allocated!");
963 auto alias_iter = maps->aliases.find(h_ptr);
964 MFEM_VERIFY(alias_iter != maps->aliases.end(),
"internal error");
965 internal::Alias &alias = alias_iter->second;
966 internal::Memory &base_mem = *alias.mem;
967 if (base_mem.d_mt == d_mt) {
return; }
968 MFEM_VERIFY(base_mem.d_ptr ==
nullptr,
969 "cannot set the device memory type:"
970 " alias' base device memory is allocated!");
971 base_mem.d_mt = d_mt;
975void MemoryManager::Delete_(
void *h_ptr,
MemoryType h_mt,
unsigned flags)
982 MFEM_ASSERT(
IsHostMemory(h_mt),
"invalid h_mt = " << (
int)h_mt);
984 MFEM_ASSERT(!owns_device || owns_internal,
"invalid Memory state");
989 MFEM_ASSERT(registered || !(owns_host || owns_device || owns_internal) ||
990 (!(owns_device || owns_internal) && h_ptr ==
nullptr),
991 "invalid Memory state");
992 if (!
mm.exists || !registered) {
return; }
998 MFEM_ASSERT(h_mt == maps->aliases.at(h_ptr).h_mt,
"");
999 mm.EraseAlias(h_ptr);
1005 { ctrl->Host(h_mt)->Dealloc(h_ptr); }
1009 MFEM_ASSERT(h_mt == maps->memories.at(h_ptr).h_mt,
"");
1010 mm.Erase(h_ptr, owns_device);
1015void MemoryManager::DeleteDevice_(
void *h_ptr,
unsigned & flags)
1020 mm.EraseDevice(h_ptr);
1025bool MemoryManager::MemoryClassCheck_(
MemoryClass mc,
void *h_ptr,
1031 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1037 auto iter = maps->memories.find(h_ptr);
1038 MFEM_VERIFY(iter != maps->memories.end(),
"internal error");
1039 d_mt = iter->second.d_mt;
1043 auto iter = maps->aliases.find(h_ptr);
1044 MFEM_VERIFY(iter != maps->aliases.end(),
"internal error");
1045 d_mt = iter->second.mem->d_mt;
1082 size_t bytes,
unsigned &flags)
1084 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1086 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1092 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1093 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1100 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1101 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1106 size_t bytes,
unsigned &flags)
1108 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1110 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1116 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1117 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1124 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1125 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1130 size_t bytes,
unsigned &flags)
1132 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1134 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1139 {
return mm.GetAliasHostPtr(h_ptr, bytes,
false); }
1140 else {
return mm.GetHostPtr(h_ptr, bytes,
false); }
1146 {
return mm.GetAliasDevicePtr(h_ptr, bytes,
false); }
1147 else {
return mm.GetDevicePtr(h_ptr, bytes,
false); }
1151void MemoryManager::SyncAlias_(
const void *base_h_ptr,
void *alias_h_ptr,
1152 size_t alias_bytes,
unsigned base_flags,
1153 unsigned &alias_flags)
1157 MFEM_ASSERT(alias_flags &
Mem::ALIAS,
"not an alias");
1160 mm.GetAliasHostPtr(alias_h_ptr, alias_bytes,
true);
1166 mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags &
Mem::ALIAS);
1170 mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes,
true);
1176MemoryType MemoryManager::GetDeviceMemoryType_(
void *h_ptr,
bool alias)
1182 auto iter = maps->memories.find(h_ptr);
1183 MFEM_ASSERT(iter != maps->memories.end(),
"internal error");
1184 return iter->second.d_mt;
1187 auto iter = maps->aliases.find(h_ptr);
1188 MFEM_ASSERT(iter != maps->aliases.end(),
"internal error");
1189 return iter->second.mem->d_mt;
1191 MFEM_ABORT(
"internal error");
1192 return MemoryManager::host_mem_type;
1195MemoryType MemoryManager::GetHostMemoryType_(
void *h_ptr)
1197 if (!
mm.exists) {
return MemoryManager::host_mem_type; }
1198 if (
mm.
IsKnown(h_ptr)) {
return maps->memories.at(h_ptr).h_mt; }
1199 if (
mm.
IsAlias(h_ptr)) {
return maps->aliases.at(h_ptr).h_mt; }
1200 return MemoryManager::host_mem_type;
1203void MemoryManager::Copy_(
void *dst_h_ptr,
const void *src_h_ptr,
1204 size_t bytes,
unsigned src_flags,
1205 unsigned &dst_flags)
1215 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1216 MFEM_ASSERT(dst_h_ptr !=
nullptr,
"invalid dst_h_ptr = nullptr");
1217 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1219 const bool dst_on_host =
1224 dst_flags = dst_flags &
1227 const bool src_on_host =
1232 const void *src_d_ptr =
1233 src_on_host ? NULL :
1235 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1236 mm.GetDevicePtr(src_h_ptr, bytes,
false));
1242 if (dst_h_ptr != src_h_ptr && bytes != 0)
1244 MFEM_ASSERT((
const char*)dst_h_ptr + bytes <= src_h_ptr ||
1245 (
const char*)src_h_ptr + bytes <= dst_h_ptr,
1247 std::memcpy(dst_h_ptr, src_h_ptr, bytes);
1252 if (dst_h_ptr != src_d_ptr && bytes != 0)
1255 maps->aliases.at(src_h_ptr).mem->d_mt :
1256 maps->memories.at(src_h_ptr).d_mt;
1257 ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
1263 void *dest_d_ptr = (dst_flags &
Mem::ALIAS) ?
1264 mm.GetAliasDevicePtr(dst_h_ptr, bytes,
false) :
1265 mm.GetDevicePtr(dst_h_ptr, bytes,
false);
1268 const bool known =
mm.
IsKnown(dst_h_ptr);
1270 MFEM_VERIFY(alias||known,
"");
1272 maps->memories.at(dst_h_ptr).d_mt :
1273 maps->aliases.at(dst_h_ptr).mem->d_mt;
1274 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1278 if (dest_d_ptr != src_d_ptr && bytes != 0)
1280 const bool known =
mm.
IsKnown(dst_h_ptr);
1282 MFEM_VERIFY(alias||known,
"");
1284 maps->memories.at(dst_h_ptr).d_mt :
1285 maps->aliases.at(dst_h_ptr).mem->d_mt;
1286 ctrl->Device(d_mt)->DtoD(dest_d_ptr, src_d_ptr, bytes);
1292void MemoryManager::CopyToHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1293 size_t bytes,
unsigned src_flags)
1295 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1296 MFEM_ASSERT(dest_h_ptr !=
nullptr,
"invalid dest_h_ptr = nullptr");
1297 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1302 if (dest_h_ptr != src_h_ptr && bytes != 0)
1304 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1305 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1307 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1312 MFEM_ASSERT(IsKnown_(src_h_ptr),
"internal error");
1313 const void *src_d_ptr = (src_flags &
Mem::ALIAS) ?
1314 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1315 mm.GetDevicePtr(src_h_ptr, bytes,
false);
1317 maps->aliases.at(src_h_ptr).mem->d_mt :
1318 maps->memories.at(src_h_ptr).d_mt;
1319 ctrl->Device(src_d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
1323void MemoryManager::CopyFromHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1324 size_t bytes,
unsigned &dest_flags)
1326 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1327 MFEM_ASSERT(dest_h_ptr !=
nullptr,
"invalid dest_h_ptr = nullptr");
1328 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1333 if (dest_h_ptr != src_h_ptr && bytes != 0)
1335 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1336 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1338 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1343 void *dest_d_ptr = (dest_flags &
Mem::ALIAS) ?
1344 mm.GetAliasDevicePtr(dest_h_ptr, bytes,
false) :
1345 mm.GetDevicePtr(dest_h_ptr, bytes,
false);
1347 maps->aliases.at(dest_h_ptr).mem->d_mt :
1348 maps->memories.at(dest_h_ptr).d_mt;
1349 ctrl->Device(dest_d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1351 dest_flags = dest_flags &
1355bool MemoryManager::IsKnown_(
const void *h_ptr)
1357 return maps->memories.find(h_ptr) != maps->memories.end();
1360bool MemoryManager::IsAlias_(
const void *h_ptr)
1362 return maps->aliases.find(h_ptr) != maps->aliases.end();
1365void MemoryManager::Insert(
void *h_ptr,
size_t bytes,
1368#ifdef MFEM_TRACK_MEM_MANAGER
1369 mfem::out <<
"[mfem memory manager]: registering h_ptr: " << h_ptr
1370 <<
", bytes: " << bytes << std::endl;
1374 MFEM_VERIFY(bytes == 0,
"Trying to add NULL with size " << bytes);
1377 MFEM_VERIFY_TYPES(h_mt, d_mt);
1381 maps->memories.emplace(h_ptr, internal::Memory(h_ptr, bytes, h_mt, d_mt));
1383 if (res.second ==
false)
1385 auto &m = res.first->second;
1386 MFEM_VERIFY(m.bytes >= bytes && m.h_mt == h_mt &&
1392 "Address already present with different attributes!");
1393#ifdef MFEM_TRACK_MEM_MANAGER
1394 mfem::out <<
"[mfem memory manager]: repeated registration of h_ptr: "
1395 << h_ptr << std::endl;
1401void MemoryManager::InsertDevice(
void *d_ptr,
void *h_ptr,
size_t bytes,
1405 MFEM_ASSERT(h_ptr != NULL,
"internal error");
1406 Insert(h_ptr, bytes, h_mt, d_mt);
1407 internal::Memory &mem = maps->memories.at(h_ptr);
1408 if (d_ptr == NULL && bytes != 0) { ctrl->Device(d_mt)->Alloc(mem); }
1409 else { mem.d_ptr = d_ptr; }
1412void MemoryManager::InsertAlias(
const void *base_ptr,
void *alias_ptr,
1413 const size_t bytes,
const bool base_is_alias)
1415 size_t offset =
static_cast<size_t>(
static_cast<const char*
>(alias_ptr) -
1416 static_cast<const char*
>(base_ptr));
1417#ifdef MFEM_TRACK_MEM_MANAGER
1418 mfem::out <<
"[mfem memory manager]: registering alias of base_ptr: "
1419 << base_ptr <<
", offset: " << offset <<
", bytes: " << bytes
1420 <<
", base is alias: " << base_is_alias << std::endl;
1424 MFEM_VERIFY(offset == 0,
1425 "Trying to add alias to NULL at offset " << offset);
1430 const internal::Alias &alias = maps->aliases.at(base_ptr);
1431 MFEM_ASSERT(alias.mem,
"");
1432 base_ptr = alias.mem->h_ptr;
1433 offset += alias.offset;
1434#ifdef MFEM_TRACK_MEM_MANAGER
1435 mfem::out <<
"[mfem memory manager]: real base_ptr: " << base_ptr
1439 internal::Memory &mem = maps->memories.at(base_ptr);
1440 MFEM_VERIFY(offset + bytes <= mem.bytes,
"invalid alias");
1442 maps->aliases.emplace(alias_ptr,
1443 internal::Alias{&mem, offset, 1, mem.h_mt});
1444 if (res.second ==
false)
1446 internal::Alias &alias = res.first->second;
1449 alias.offset = offset;
1450 alias.h_mt = mem.h_mt;
1455void MemoryManager::Erase(
void *h_ptr,
bool free_dev_ptr)
1457#ifdef MFEM_TRACK_MEM_MANAGER
1458 mfem::out <<
"[mfem memory manager]: un-registering h_ptr: " << h_ptr
1461 if (!h_ptr) {
return; }
1462 auto mem_map_iter = maps->memories.find(h_ptr);
1463 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1464 internal::Memory &mem = mem_map_iter->second;
1465 if (mem.d_ptr && free_dev_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1466 maps->memories.erase(mem_map_iter);
1469void MemoryManager::EraseDevice(
void *h_ptr)
1471 if (!h_ptr) {
return; }
1472 auto mem_map_iter = maps->memories.find(h_ptr);
1473 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1474 internal::Memory &mem = mem_map_iter->second;
1475 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1476 mem.d_ptr =
nullptr;
1479void MemoryManager::EraseAlias(
void *alias_ptr)
1481#ifdef MFEM_TRACK_MEM_MANAGER
1482 mfem::out <<
"[mfem memory manager]: un-registering alias_ptr: " << alias_ptr
1485 if (!alias_ptr) {
return; }
1486 auto alias_map_iter = maps->aliases.find(alias_ptr);
1487 if (alias_map_iter == maps->aliases.end()) {
mfem_error(
"Unknown alias!"); }
1488 internal::Alias &alias = alias_map_iter->second;
1489 if (--alias.counter) {
return; }
1490 maps->aliases.erase(alias_map_iter);
1493void *MemoryManager::GetDevicePtr(
const void *h_ptr,
size_t bytes,
1498 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1501 internal::Memory &mem = maps->memories.at(h_ptr);
1504 MFEM_VERIFY_TYPES(h_mt, d_mt);
1508 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1511 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1514 MFEM_ASSERT(bytes <= mem.bytes,
"invalid copy size");
1515 if (bytes) { ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes); }
1517 ctrl->Host(h_mt)->Protect(mem, bytes);
1521void *MemoryManager::GetAliasDevicePtr(
const void *alias_ptr,
size_t bytes,
1526 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1529 auto &alias_map = maps->aliases;
1530 auto alias_map_iter = alias_map.find(alias_ptr);
1531 if (alias_map_iter == alias_map.end()) {
mfem_error(
"alias not found"); }
1532 const internal::Alias &alias = alias_map_iter->second;
1533 const size_t offset = alias.offset;
1534 internal::Memory &mem = *alias.mem;
1537 MFEM_VERIFY_TYPES(h_mt, d_mt);
1541 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1543 void *alias_h_ptr =
static_cast<char*
>(mem.h_ptr) + offset;
1544 void *alias_d_ptr =
static_cast<char*
>(mem.d_ptr) + offset;
1545 MFEM_ASSERT(alias_h_ptr == alias_ptr,
"internal error");
1546 MFEM_ASSERT(offset + bytes <= mem.bytes,
"internal error");
1547 mem.d_rw = mem.h_rw =
false;
1548 if (mem.d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1549 ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
1550 if (copy && mem.d_ptr)
1551 { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
1552 ctrl->Host(h_mt)->AliasProtect(alias_ptr, bytes);
1556void *MemoryManager::GetHostPtr(
const void *ptr,
size_t bytes,
bool copy)
1558 const internal::Memory &mem = maps->memories.at(ptr);
1559 MFEM_ASSERT(mem.h_ptr == ptr,
"internal error");
1560 MFEM_ASSERT(bytes <= mem.bytes,
"internal error")
1563 MFEM_VERIFY_TYPES(h_mt, d_mt);
1565 ctrl->Host(h_mt)->Unprotect(mem, bytes);
1566 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1567 if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
1568 if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
1572void *MemoryManager::GetAliasHostPtr(
const void *ptr,
size_t bytes,
1575 const internal::Alias &alias = maps->aliases.at(ptr);
1576 const internal::Memory *
const mem = alias.mem;
1579 MFEM_VERIFY_TYPES(h_mt, d_mt);
1580 void *alias_h_ptr =
static_cast<char*
>(mem->h_ptr) + alias.offset;
1581 void *alias_d_ptr =
static_cast<char*
>(mem->d_ptr) + alias.offset;
1582 MFEM_ASSERT(alias_h_ptr == ptr,
"internal error");
1584 ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
1585 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1586 if (copy_data && mem->d_ptr)
1587 { ctrl->Device(d_mt)->DtoH(
const_cast<void*
>(ptr), alias_d_ptr, bytes); }
1588 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasProtect(alias_d_ptr, bytes); }
1594 if (exists) {
return; }
1595 maps =
new internal::Maps();
1596 ctrl =
new internal::Ctrl();
1607 MFEM_VERIFY(!configured,
"changing the dual MemoryTypes is not allowed after"
1608 " MemoryManager configuration!");
1609 UpdateDualMemoryType(mt, dual_mt);
1615 "invalid MemoryType, mt = " << (
int)mt);
1617 "invalid dual MemoryType, dual_mt = " << (
int)dual_mt);
1622 dual_map[(int)mt] = dual_mt;
1630 "invalid (mt, dual_mt) pair: ("
1639 MemoryManager::UpdateDualMemoryType(host_mt, device_mt);
1640 MemoryManager::UpdateDualMemoryType(device_mt, host_mt);
1645 MemoryManager::UpdateDualMemoryType(
1650 host_mem_type = host_mt;
1651 device_mem_type = device_mt;
1657 MFEM_VERIFY(exists,
"MemoryManager has already been destroyed!");
1658#ifdef MFEM_TRACK_MEM_MANAGER
1659 size_t num_memories = maps->memories.size();
1660 size_t num_aliases = maps->aliases.size();
1661 if (num_memories != 0 || num_aliases != 0)
1663 MFEM_WARNING(
"...\n\t number of registered pointers: " << num_memories
1664 <<
"\n\t number of registered aliases : " << num_aliases);
1669 mfem::out <<
"Destroying the MemoryManager ...\n"
1670 <<
"remaining registered pointers : "
1671 << maps->memories.size() <<
'\n'
1672 <<
"remaining registered aliases : "
1673 << maps->aliases.size() <<
'\n';
1675 for (
auto& n : maps->memories)
1677 internal::Memory &mem = n.second;
1679 if (mem_h_ptr) { ctrl->Host(mem.h_mt)->Dealloc(mem.h_ptr); }
1680 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem); }
1682 delete maps; maps =
nullptr;
1683 delete ctrl; ctrl =
nullptr;
1704 for (
const auto& n : maps->memories)
1706 const internal::Memory &mem = n.second;
1707 os <<
"\nkey " << n.first <<
", "
1708 <<
"h_ptr " << mem.h_ptr <<
", "
1709 <<
"d_ptr " << mem.d_ptr;
1712 if (maps->memories.size() > 0) { os << std::endl; }
1719 for (
const auto& n : maps->aliases)
1721 const internal::Alias &alias = n.second;
1722 os <<
"\nalias: key " << n.first <<
", "
1723 <<
"h_ptr " << alias.mem->h_ptr <<
", "
1724 <<
"offset " << alias.offset <<
", "
1725 <<
"counter " << alias.counter;
1728 if (maps->aliases.size() > 0) { os << std::endl; }
1732int MemoryManager::CompareHostAndDevice_(
void *h_ptr,
size_t size,
1736 mm.GetAliasDevicePtr(h_ptr, size,
false) :
1737 mm.GetDevicePtr(h_ptr, size,
false);
1738 char *h_buf =
new char[size];
1739#if defined(MFEM_USE_CUDA)
1741#elif defined(MFEM_USE_HIP)
1744 std::memcpy(h_buf, d_ptr, size);
1746 int res = std::memcmp(h_ptr, h_buf, size);
1756 <<
"\n registered = " << bool(flags & Mem::Registered)
1757 <<
"\n owns host = " << bool(flags & Mem::OWNS_HOST)
1758 <<
"\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
1759 <<
"\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
1760 <<
"\n valid host = " << bool(flags & Mem::VALID_HOST)
1761 <<
"\n valid device = " << bool(flags & Mem::VALID_DEVICE)
1762 <<
"\n device flag = " << bool(flags & Mem::USE_DEVICE)
1763 <<
"\n alias = " << bool(flags & Mem::ALIAS)