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;
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)
override { MmuAlloc(ptr, bytes); }
393 void Dealloc(
void *ptr)
override { MmuDealloc(ptr, maps->memories.at(ptr).bytes); }
394 void Protect(
const Memory& mem,
size_t bytes)
override
395 {
if (mem.h_rw) { mem.h_rw =
false; MmuProtect(mem.h_ptr, bytes); } }
396 void Unprotect(
const Memory &mem,
size_t bytes)
override
397 {
if (!mem.h_rw) { mem.h_rw =
true; MmuAllow(mem.h_ptr, bytes); } }
399 void AliasProtect(
const void *ptr,
size_t bytes)
override
400 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
402 void AliasUnprotect(
const void *ptr,
size_t bytes)
override
403 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
407class UvmHostMemorySpace :
public HostMemorySpace
410 UvmHostMemorySpace(): HostMemorySpace() { }
412 void Alloc(
void **ptr,
size_t bytes)
override
422 void Dealloc(
void *ptr)
override
434class NoDeviceMemorySpace:
public DeviceMemorySpace
437 void Alloc(internal::Memory&)
override {
mfem_error(
"! Device Alloc"); }
438 void Dealloc(Memory&)
override {
mfem_error(
"! Device Dealloc"); }
439 void *HtoD(
void*,
const void*,
size_t)
override {
mfem_error(
"!HtoD");
return nullptr; }
440 void *DtoD(
void*,
const void*,
size_t)
override {
mfem_error(
"!DtoD");
return nullptr; }
441 void *DtoH(
void*,
const void*,
size_t)
override {
mfem_error(
"!DtoH");
return nullptr; }
445class StdDeviceMemorySpace :
public DeviceMemorySpace { };
448class CudaDeviceMemorySpace:
public DeviceMemorySpace
451 CudaDeviceMemorySpace(): DeviceMemorySpace() { }
452 void Alloc(Memory &base)
override {
CuMemAlloc(&base.d_ptr, base.bytes); }
453 void Dealloc(Memory &base)
override {
CuMemFree(base.d_ptr); }
454 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
456 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
458 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
463class HostPinnedMemorySpace:
public HostMemorySpace
466 HostPinnedMemorySpace(): HostMemorySpace() { }
467 void Alloc(
void ** ptr,
size_t bytes)
override
476 void Dealloc(
void *ptr)
override
488class HipDeviceMemorySpace:
public DeviceMemorySpace
491 HipDeviceMemorySpace(): DeviceMemorySpace() { }
492 void Alloc(Memory &base)
override {
HipMemAlloc(&base.d_ptr, base.bytes); }
493 void Dealloc(Memory &base)
override {
HipMemFree(base.d_ptr); }
494 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
496 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
501 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
506class UvmCudaMemorySpace :
public DeviceMemorySpace
509 void Alloc(Memory &base)
override { base.d_ptr = base.h_ptr; }
510 void Dealloc(Memory&)
override { }
511 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
513 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
516 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
518 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
520 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
525class UvmHipMemorySpace :
public DeviceMemorySpace
528 void Alloc(Memory &base) { base.d_ptr = base.h_ptr; }
529 void Dealloc(Memory&) { }
530 void *HtoD(
void *dst,
const void *src,
size_t bytes)
532 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
535 void *DtoD(
void* dst,
const void* src,
size_t bytes)
537 void *DtoH(
void *dst,
const void *src,
size_t bytes)
539 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
545class MmuDeviceMemorySpace :
public DeviceMemorySpace
548 MmuDeviceMemorySpace(): DeviceMemorySpace() { }
549 void Alloc(Memory &m)
override { MmuAlloc(&m.d_ptr, m.bytes); }
550 void Dealloc(Memory &m)
override { MmuDealloc(m.d_ptr, m.bytes); }
551 void Protect(
const Memory &m)
override
552 {
if (m.d_rw) { m.d_rw =
false; MmuProtect(m.d_ptr, m.bytes); } }
553 void Unprotect(
const Memory &m)
override
554 {
if (!m.d_rw) { m.d_rw =
true; MmuAllow(m.d_ptr, m.bytes); } }
556 void AliasProtect(
const void *ptr,
size_t bytes)
override
557 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
559 void AliasUnprotect(
const void *ptr,
size_t bytes)
override
560 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
561 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
562 {
return std::memcpy(dst, src, bytes); }
563 void *DtoD(
void *dst,
const void *src,
size_t bytes)
override
564 {
return std::memcpy(dst, src, bytes); }
565 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
566 {
return std::memcpy(dst, src, bytes); }
569#ifdef MFEM_USE_UMPIRE
570class UmpireMemorySpace
573 umpire::ResourceManager &rm;
574 umpire::Allocator allocator;
575 bool owns_allocator{
false};
579 virtual ~UmpireMemorySpace() {
if (owns_allocator) { allocator.release(); } }
580 UmpireMemorySpace(
const char * name,
const char *
space)
581 : rm(umpire::ResourceManager::getInstance())
583 if (!rm.isAllocator(name))
585 allocator = rm.makeAllocator<umpire::strategy::QuickPool>(
586 name, rm.getAllocator(
space));
587 owns_allocator =
true;
591 allocator = rm.getAllocator(name);
592 owns_allocator =
false;
598class UmpireHostMemorySpace :
public HostMemorySpace,
public UmpireMemorySpace
601 umpire::strategy::AllocationStrategy *strat;
603 UmpireHostMemorySpace(
const char * name)
605 UmpireMemorySpace(name,
"HOST"),
606 strat(allocator.getAllocationStrategy()) {}
607 void Alloc(
void **ptr,
size_t bytes)
override
608 { *ptr = allocator.allocate(bytes); }
609 void Dealloc(
void *ptr)
override { allocator.deallocate(ptr); }
610 void Insert(
void *ptr,
size_t bytes)
611 { rm.registerAllocation(ptr, {ptr, bytes, strat}); }
615#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
616class UmpireDeviceMemorySpace :
public DeviceMemorySpace,
617 public UmpireMemorySpace
620 UmpireDeviceMemorySpace(
const char * name)
621 : DeviceMemorySpace(),
622 UmpireMemorySpace(name,
"DEVICE") {}
623 void Alloc(Memory &base)
override
624 { base.d_ptr = allocator.allocate(base.bytes); }
625 void Dealloc(Memory &base)
override { rm.deallocate(base.d_ptr); }
626 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
636 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
649 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
661class UmpireDeviceMemorySpace :
public NoDeviceMemorySpace
664 UmpireDeviceMemorySpace(
const char * ) {}
679 Ctrl(): host{nullptr}, device{nullptr} { }
683 if (host[HostMemoryType])
685 mfem_error(
"Memory backends have already been configured!");
691 host[
static_cast<int>(MT::HOST)] =
new StdHostMemorySpace();
692 host[
static_cast<int>(MT::HOST_32)] =
new Aligned32HostMemorySpace();
693 host[
static_cast<int>(MT::HOST_64)] =
new Aligned64HostMemorySpace();
695 host[
static_cast<int>(MT::HOST_DEBUG)] =
nullptr;
696 host[
static_cast<int>(MT::HOST_UMPIRE)] =
nullptr;
697 host[
static_cast<int>(MT::MANAGED)] =
new UvmHostMemorySpace();
701#if defined(MFEM_USE_CUDA)
702 device[
static_cast<int>(MT::MANAGED)-shift] =
new UvmCudaMemorySpace();
703#elif defined(MFEM_USE_HIP)
704 device[
static_cast<int>(MT::MANAGED)-shift] =
new UvmHipMemorySpace();
707 device[
static_cast<int>(MT::MANAGED)-shift] =
new UvmCudaMemorySpace();
711 device[
static_cast<int>(MemoryType::DEVICE)-shift] =
nullptr;
712 device[
static_cast<int>(MT::DEVICE_DEBUG)-shift] =
nullptr;
713 device[
static_cast<int>(MT::DEVICE_UMPIRE)-shift] =
nullptr;
714 device[
static_cast<int>(MT::DEVICE_UMPIRE_2)-shift] =
nullptr;
717 HostMemorySpace* Host(
const MemoryType mt)
719 const int mt_i =
static_cast<int>(mt);
721 if (!host[mt_i]) { host[mt_i] = NewHostCtrl(mt); }
722 MFEM_ASSERT(host[mt_i],
"Host memory controller is not configured!");
726 DeviceMemorySpace* Device(
const MemoryType mt)
728 const int mt_i =
static_cast<int>(mt) - DeviceMemoryType;
729 MFEM_ASSERT(mt_i >= 0,
"");
731 if (!device[mt_i]) { device[mt_i] = NewDeviceCtrl(mt); }
732 MFEM_ASSERT(device[mt_i],
"Memory manager has not been configured!");
741 for (
int mt = mt_d; mt <
MemoryTypeSize; mt++) {
delete device[mt-mt_d]; }
745 HostMemorySpace* NewHostCtrl(
const MemoryType mt)
749 case MT::HOST_DEBUG:
return new MmuHostMemorySpace();
750#ifdef MFEM_USE_UMPIRE
751 case MT::HOST_UMPIRE:
752 return new UmpireHostMemorySpace(
753 MemoryManager::GetUmpireHostAllocatorName());
755 case MT::HOST_UMPIRE:
return new NoHostMemorySpace();
757 case MT::HOST_PINNED:
return new HostPinnedMemorySpace();
758 default: MFEM_ABORT(
"Unknown host memory controller!");
763 DeviceMemorySpace* NewDeviceCtrl(
const MemoryType mt)
767#ifdef MFEM_USE_UMPIRE
768 case MT::DEVICE_UMPIRE:
769 return new UmpireDeviceMemorySpace(
770 MemoryManager::GetUmpireDeviceAllocatorName());
771 case MT::DEVICE_UMPIRE_2:
772 return new UmpireDeviceMemorySpace(
773 MemoryManager::GetUmpireDevice2AllocatorName());
775 case MT::DEVICE_UMPIRE:
return new NoDeviceMemorySpace();
776 case MT::DEVICE_UMPIRE_2:
return new NoDeviceMemorySpace();
778 case MT::DEVICE_DEBUG:
return new MmuDeviceMemorySpace();
781#if defined(MFEM_USE_CUDA)
782 return new CudaDeviceMemorySpace();
783#elif defined(MFEM_USE_HIP)
784 return new HipDeviceMemorySpace();
786 MFEM_ABORT(
"No device memory controller!");
790 default: MFEM_ABORT(
"Unknown device memory controller!");
798static internal::Ctrl *ctrl;
800void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType mt,
803 MFEM_ASSERT(exists,
"Internal error!");
822void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType h_mt,
826 MFEM_ASSERT(exists,
"Internal error!");
827 MFEM_ASSERT(
IsHostMemory(h_mt),
"h_mt must be host type");
830 "d_mt must be device type, the same is h_mt, or DEFAULT");
837 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
838 else { h_ptr = h_tmp; }
842 mm.Insert(h_ptr, bytes, h_mt, d_mt);
846 CheckHostMemoryType_(h_mt, h_ptr,
false);
851void *MemoryManager::Register_(
void *ptr,
void *h_tmp,
size_t bytes,
853 bool own,
bool alias,
unsigned &flags)
855 MFEM_ASSERT(exists,
"Internal error!");
863 MFEM_VERIFY_TYPES(h_mt, d_mt);
865 if (ptr ==
nullptr && h_tmp ==
nullptr)
867 MFEM_VERIFY(bytes == 0,
"internal error");
871 MFEM_VERIFY(!alias,
"Cannot register an alias!");
879 mm.Insert(h_ptr, bytes, h_mt, d_mt);
880 flags = (own ? flags |
Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST) |
885 MFEM_VERIFY(ptr || bytes == 0,
886 "cannot register NULL device pointer with bytes = " << bytes);
887 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
888 else { h_ptr = h_tmp; }
889 mm.InsertDevice(ptr, h_ptr, bytes, h_mt, d_mt);
893 CheckHostMemoryType_(h_mt, h_ptr, alias);
897void MemoryManager::Register2_(
void *h_ptr,
void *d_ptr,
size_t bytes,
899 bool own,
bool alias,
unsigned &flags,
900 unsigned valid_flags)
902 MFEM_CONTRACT_VAR(alias);
903 MFEM_ASSERT(exists,
"Internal error!");
904 MFEM_ASSERT(!alias,
"Cannot register an alias!");
905 MFEM_VERIFY_TYPES(h_mt, d_mt);
907 if (h_ptr ==
nullptr && d_ptr ==
nullptr)
909 MFEM_VERIFY(bytes == 0,
"internal error");
915 MFEM_VERIFY(d_ptr || bytes == 0,
916 "cannot register NULL device pointer with bytes = " << bytes);
917 mm.InsertDevice(d_ptr, h_ptr, bytes, h_mt, d_mt);
919 flags & ~(Mem::OWNS_HOST | Mem::OWNS_DEVICE)) |
922 CheckHostMemoryType_(h_mt, h_ptr, alias);
925void MemoryManager::Alias_(
void *base_h_ptr,
size_t offset,
size_t bytes,
926 unsigned base_flags,
unsigned &flags)
928 mm.InsertAlias(base_h_ptr, (
char*)base_h_ptr + offset, bytes,
934void MemoryManager::SetDeviceMemoryType_(
void *h_ptr,
unsigned flags,
937 MFEM_VERIFY(h_ptr,
"cannot set the device memory type: Memory is empty!");
940 auto mem_iter = maps->memories.find(h_ptr);
941 MFEM_VERIFY(mem_iter != maps->memories.end(),
"internal error");
942 internal::Memory &mem = mem_iter->second;
943 if (mem.d_mt == d_mt) {
return; }
944 MFEM_VERIFY(mem.d_ptr ==
nullptr,
"cannot set the device memory type:"
945 " device memory is allocated!");
950 auto alias_iter = maps->aliases.find(h_ptr);
951 MFEM_VERIFY(alias_iter != maps->aliases.end(),
"internal error");
952 internal::Alias &alias = alias_iter->second;
953 internal::Memory &base_mem = *alias.mem;
954 if (base_mem.d_mt == d_mt) {
return; }
955 MFEM_VERIFY(base_mem.d_ptr ==
nullptr,
956 "cannot set the device memory type:"
957 " alias' base device memory is allocated!");
958 base_mem.d_mt = d_mt;
962void MemoryManager::Delete_(
void *h_ptr,
MemoryType h_mt,
unsigned flags)
969 MFEM_ASSERT(
IsHostMemory(h_mt),
"invalid h_mt = " << (
int)h_mt);
971 MFEM_ASSERT(!owns_device || owns_internal,
"invalid Memory state");
976 MFEM_ASSERT(registered || !(owns_host || owns_device || owns_internal) ||
977 (!(owns_device || owns_internal) && h_ptr ==
nullptr),
978 "invalid Memory state");
979 if (!
mm.exists || !registered) {
return; }
985 MFEM_ASSERT(h_mt == maps->aliases.at(h_ptr).h_mt,
"");
986 mm.EraseAlias(h_ptr);
992 { ctrl->Host(h_mt)->Dealloc(h_ptr); }
996 MFEM_ASSERT(h_mt == maps->memories.at(h_ptr).h_mt,
"");
997 mm.Erase(h_ptr, owns_device);
1002void MemoryManager::DeleteDevice_(
void *h_ptr,
unsigned & flags)
1007 mm.EraseDevice(h_ptr);
1012bool MemoryManager::MemoryClassCheck_(
MemoryClass mc,
void *h_ptr,
1018 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1024 auto iter = maps->memories.find(h_ptr);
1025 MFEM_VERIFY(iter != maps->memories.end(),
"internal error");
1026 d_mt = iter->second.d_mt;
1030 auto iter = maps->aliases.find(h_ptr);
1031 MFEM_VERIFY(iter != maps->aliases.end(),
"internal error");
1032 d_mt = iter->second.mem->d_mt;
1069 size_t bytes,
unsigned &flags)
1071 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1073 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1079 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1080 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1087 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1088 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1093 size_t bytes,
unsigned &flags)
1095 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1097 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1103 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1104 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1111 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1112 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1117 size_t bytes,
unsigned &flags)
1119 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags &
Mem::ALIAS); }
1121 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1126 {
return mm.GetAliasHostPtr(h_ptr, bytes,
false); }
1127 else {
return mm.GetHostPtr(h_ptr, bytes,
false); }
1133 {
return mm.GetAliasDevicePtr(h_ptr, bytes,
false); }
1134 else {
return mm.GetDevicePtr(h_ptr, bytes,
false); }
1138void MemoryManager::SyncAlias_(
const void *base_h_ptr,
void *alias_h_ptr,
1139 size_t alias_bytes,
unsigned base_flags,
1140 unsigned &alias_flags)
1144 MFEM_ASSERT(alias_flags &
Mem::ALIAS,
"not an alias");
1147 mm.GetAliasHostPtr(alias_h_ptr, alias_bytes,
true);
1153 mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags &
Mem::ALIAS);
1157 mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes,
true);
1163MemoryType MemoryManager::GetDeviceMemoryType_(
void *h_ptr,
bool alias)
1169 auto iter = maps->memories.find(h_ptr);
1170 MFEM_ASSERT(iter != maps->memories.end(),
"internal error");
1171 return iter->second.d_mt;
1174 auto iter = maps->aliases.find(h_ptr);
1175 MFEM_ASSERT(iter != maps->aliases.end(),
"internal error");
1176 return iter->second.mem->d_mt;
1178 MFEM_ABORT(
"internal error");
1179 return MemoryManager::host_mem_type;
1182MemoryType MemoryManager::GetHostMemoryType_(
void *h_ptr)
1184 if (!
mm.exists) {
return MemoryManager::host_mem_type; }
1185 if (
mm.
IsKnown(h_ptr)) {
return maps->memories.at(h_ptr).h_mt; }
1186 if (
mm.
IsAlias(h_ptr)) {
return maps->aliases.at(h_ptr).h_mt; }
1187 return MemoryManager::host_mem_type;
1190void MemoryManager::Copy_(
void *dst_h_ptr,
const void *src_h_ptr,
1191 size_t bytes,
unsigned src_flags,
1192 unsigned &dst_flags)
1202 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1203 MFEM_ASSERT(dst_h_ptr !=
nullptr,
"invalid dst_h_ptr = nullptr");
1204 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1206 const bool dst_on_host =
1211 dst_flags = dst_flags &
1214 const bool src_on_host =
1219 const void *src_d_ptr =
1220 src_on_host ? NULL :
1222 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1223 mm.GetDevicePtr(src_h_ptr, bytes,
false));
1229 if (dst_h_ptr != src_h_ptr && bytes != 0)
1231 MFEM_ASSERT((
const char*)dst_h_ptr + bytes <= src_h_ptr ||
1232 (
const char*)src_h_ptr + bytes <= dst_h_ptr,
1234 std::memcpy(dst_h_ptr, src_h_ptr, bytes);
1239 if (dst_h_ptr != src_d_ptr && bytes != 0)
1242 maps->aliases.at(src_h_ptr).mem->d_mt :
1243 maps->memories.at(src_h_ptr).d_mt;
1244 ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
1250 void *dest_d_ptr = (dst_flags &
Mem::ALIAS) ?
1251 mm.GetAliasDevicePtr(dst_h_ptr, bytes,
false) :
1252 mm.GetDevicePtr(dst_h_ptr, bytes,
false);
1255 const bool known =
mm.
IsKnown(dst_h_ptr);
1257 MFEM_VERIFY(alias||known,
"");
1259 maps->memories.at(dst_h_ptr).d_mt :
1260 maps->aliases.at(dst_h_ptr).mem->d_mt;
1261 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1265 if (dest_d_ptr != src_d_ptr && bytes != 0)
1267 const bool known =
mm.
IsKnown(dst_h_ptr);
1269 MFEM_VERIFY(alias||known,
"");
1271 maps->memories.at(dst_h_ptr).d_mt :
1272 maps->aliases.at(dst_h_ptr).mem->d_mt;
1273 ctrl->Device(d_mt)->DtoD(dest_d_ptr, src_d_ptr, bytes);
1279void MemoryManager::CopyToHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1280 size_t bytes,
unsigned src_flags)
1282 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1283 MFEM_ASSERT(dest_h_ptr !=
nullptr,
"invalid dest_h_ptr = nullptr");
1284 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1289 if (dest_h_ptr != src_h_ptr && bytes != 0)
1291 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1292 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1294 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1299 MFEM_ASSERT(IsKnown_(src_h_ptr),
"internal error");
1300 const void *src_d_ptr = (src_flags &
Mem::ALIAS) ?
1301 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1302 mm.GetDevicePtr(src_h_ptr, bytes,
false);
1304 maps->aliases.at(src_h_ptr).mem->d_mt :
1305 maps->memories.at(src_h_ptr).d_mt;
1306 ctrl->Device(src_d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
1310void MemoryManager::CopyFromHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1311 size_t bytes,
unsigned &dest_flags)
1313 MFEM_ASSERT(bytes != 0,
"this method should not be called with bytes = 0");
1314 MFEM_ASSERT(dest_h_ptr !=
nullptr,
"invalid dest_h_ptr = nullptr");
1315 MFEM_ASSERT(src_h_ptr !=
nullptr,
"invalid src_h_ptr = nullptr");
1320 if (dest_h_ptr != src_h_ptr && bytes != 0)
1322 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1323 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1325 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1330 void *dest_d_ptr = (dest_flags &
Mem::ALIAS) ?
1331 mm.GetAliasDevicePtr(dest_h_ptr, bytes,
false) :
1332 mm.GetDevicePtr(dest_h_ptr, bytes,
false);
1334 maps->aliases.at(dest_h_ptr).mem->d_mt :
1335 maps->memories.at(dest_h_ptr).d_mt;
1336 ctrl->Device(dest_d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1338 dest_flags = dest_flags &
1342bool MemoryManager::IsKnown_(
const void *h_ptr)
1344 return maps->memories.find(h_ptr) != maps->memories.end();
1347bool MemoryManager::IsAlias_(
const void *h_ptr)
1349 return maps->aliases.find(h_ptr) != maps->aliases.end();
1352void MemoryManager::Insert(
void *h_ptr,
size_t bytes,
1355#ifdef MFEM_TRACK_MEM_MANAGER
1356 mfem::out <<
"[mfem memory manager]: registering h_ptr: " << h_ptr
1357 <<
", bytes: " << bytes << std::endl;
1361 MFEM_VERIFY(bytes == 0,
"Trying to add NULL with size " << bytes);
1364 MFEM_VERIFY_TYPES(h_mt, d_mt);
1368 maps->memories.emplace(h_ptr, internal::Memory(h_ptr, bytes, h_mt, d_mt));
1370 if (res.second ==
false)
1372 auto &m = res.first->second;
1373 MFEM_VERIFY(m.bytes >= bytes && m.h_mt == h_mt &&
1376 "Address already present with different attributes!");
1377#ifdef MFEM_TRACK_MEM_MANAGER
1378 mfem::out <<
"[mfem memory manager]: repeated registration of h_ptr: "
1379 << h_ptr << std::endl;
1385void MemoryManager::InsertDevice(
void *d_ptr,
void *h_ptr,
size_t bytes,
1389 MFEM_ASSERT(h_ptr != NULL,
"internal error");
1390 Insert(h_ptr, bytes, h_mt, d_mt);
1391 internal::Memory &mem = maps->memories.at(h_ptr);
1392 if (d_ptr == NULL && bytes != 0) { ctrl->Device(d_mt)->Alloc(mem); }
1393 else { mem.d_ptr = d_ptr; }
1396void MemoryManager::InsertAlias(
const void *base_ptr,
void *alias_ptr,
1397 const size_t bytes,
const bool base_is_alias)
1399 size_t offset =
static_cast<size_t>(
static_cast<const char*
>(alias_ptr) -
1400 static_cast<const char*
>(base_ptr));
1401#ifdef MFEM_TRACK_MEM_MANAGER
1402 mfem::out <<
"[mfem memory manager]: registering alias of base_ptr: "
1403 << base_ptr <<
", offset: " << offset <<
", bytes: " << bytes
1404 <<
", base is alias: " << base_is_alias << std::endl;
1408 MFEM_VERIFY(offset == 0,
1409 "Trying to add alias to NULL at offset " << offset);
1414 const internal::Alias &alias = maps->aliases.at(base_ptr);
1415 MFEM_ASSERT(alias.mem,
"");
1416 base_ptr = alias.mem->h_ptr;
1417 offset += alias.offset;
1418#ifdef MFEM_TRACK_MEM_MANAGER
1419 mfem::out <<
"[mfem memory manager]: real base_ptr: " << base_ptr
1423 internal::Memory &mem = maps->memories.at(base_ptr);
1424 MFEM_VERIFY(offset + bytes <= mem.bytes,
"invalid alias");
1426 maps->aliases.emplace(alias_ptr,
1427 internal::Alias{&mem, offset, 1, mem.h_mt});
1428 if (res.second ==
false)
1430 internal::Alias &alias = res.first->second;
1433 alias.offset = offset;
1434 alias.h_mt = mem.h_mt;
1439void MemoryManager::Erase(
void *h_ptr,
bool free_dev_ptr)
1441#ifdef MFEM_TRACK_MEM_MANAGER
1442 mfem::out <<
"[mfem memory manager]: un-registering h_ptr: " << h_ptr
1445 if (!h_ptr) {
return; }
1446 auto mem_map_iter = maps->memories.find(h_ptr);
1447 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1448 internal::Memory &mem = mem_map_iter->second;
1449 if (mem.d_ptr && free_dev_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1450 maps->memories.erase(mem_map_iter);
1453void MemoryManager::EraseDevice(
void *h_ptr)
1455 if (!h_ptr) {
return; }
1456 auto mem_map_iter = maps->memories.find(h_ptr);
1457 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1458 internal::Memory &mem = mem_map_iter->second;
1459 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1460 mem.d_ptr =
nullptr;
1463void MemoryManager::EraseAlias(
void *alias_ptr)
1465#ifdef MFEM_TRACK_MEM_MANAGER
1466 mfem::out <<
"[mfem memory manager]: un-registering alias_ptr: " << alias_ptr
1469 if (!alias_ptr) {
return; }
1470 auto alias_map_iter = maps->aliases.find(alias_ptr);
1471 if (alias_map_iter == maps->aliases.end()) {
mfem_error(
"Unknown alias!"); }
1472 internal::Alias &alias = alias_map_iter->second;
1473 if (--alias.counter) {
return; }
1474 maps->aliases.erase(alias_map_iter);
1477void *MemoryManager::GetDevicePtr(
const void *h_ptr,
size_t bytes,
1482 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1485 internal::Memory &mem = maps->memories.at(h_ptr);
1488 MFEM_VERIFY_TYPES(h_mt, d_mt);
1492 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1495 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1498 MFEM_ASSERT(bytes <= mem.bytes,
"invalid copy size");
1499 if (bytes) { ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes); }
1501 ctrl->Host(h_mt)->Protect(mem, bytes);
1505void *MemoryManager::GetAliasDevicePtr(
const void *alias_ptr,
size_t bytes,
1510 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1513 auto &alias_map = maps->aliases;
1514 auto alias_map_iter = alias_map.find(alias_ptr);
1515 if (alias_map_iter == alias_map.end()) {
mfem_error(
"alias not found"); }
1516 const internal::Alias &alias = alias_map_iter->second;
1517 const size_t offset = alias.offset;
1518 internal::Memory &mem = *alias.mem;
1521 MFEM_VERIFY_TYPES(h_mt, d_mt);
1525 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1527 void *alias_h_ptr =
static_cast<char*
>(mem.h_ptr) + offset;
1528 void *alias_d_ptr =
static_cast<char*
>(mem.d_ptr) + offset;
1529 MFEM_ASSERT(alias_h_ptr == alias_ptr,
"internal error");
1530 MFEM_ASSERT(offset + bytes <= mem.bytes,
"internal error");
1531 mem.d_rw = mem.h_rw =
false;
1532 if (mem.d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1533 ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
1534 if (copy && mem.d_ptr)
1535 { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
1536 ctrl->Host(h_mt)->AliasProtect(alias_ptr, bytes);
1540void *MemoryManager::GetHostPtr(
const void *ptr,
size_t bytes,
bool copy)
1542 const internal::Memory &mem = maps->memories.at(ptr);
1543 MFEM_ASSERT(mem.h_ptr == ptr,
"internal error");
1544 MFEM_ASSERT(bytes <= mem.bytes,
"internal error")
1547 MFEM_VERIFY_TYPES(h_mt, d_mt);
1549 ctrl->Host(h_mt)->Unprotect(mem, bytes);
1550 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1551 if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
1552 if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
1556void *MemoryManager::GetAliasHostPtr(
const void *ptr,
size_t bytes,
1559 const internal::Alias &alias = maps->aliases.at(ptr);
1560 const internal::Memory *
const mem = alias.mem;
1563 MFEM_VERIFY_TYPES(h_mt, d_mt);
1564 void *alias_h_ptr =
static_cast<char*
>(mem->h_ptr) + alias.offset;
1565 void *alias_d_ptr =
static_cast<char*
>(mem->d_ptr) + alias.offset;
1566 MFEM_ASSERT(alias_h_ptr == ptr,
"internal error");
1568 ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
1569 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1570 if (copy_data && mem->d_ptr)
1571 { ctrl->Device(d_mt)->DtoH(
const_cast<void*
>(ptr), alias_d_ptr, bytes); }
1572 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasProtect(alias_d_ptr, bytes); }
1578 if (exists) {
return; }
1579 maps =
new internal::Maps();
1580 ctrl =
new internal::Ctrl();
1591 MFEM_VERIFY(!configured,
"changing the dual MemoryTypes is not allowed after"
1592 " MemoryManager configuration!");
1593 UpdateDualMemoryType(mt, dual_mt);
1599 "invalid MemoryType, mt = " << (
int)mt);
1601 "invalid dual MemoryType, dual_mt = " << (
int)dual_mt);
1606 dual_map[(int)mt] = dual_mt;
1614 "invalid (mt, dual_mt) pair: ("
1623 MemoryManager::UpdateDualMemoryType(host_mt, device_mt);
1624 MemoryManager::UpdateDualMemoryType(device_mt, host_mt);
1629 MemoryManager::UpdateDualMemoryType(
1634 host_mem_type = host_mt;
1635 device_mem_type = device_mt;
1641 MFEM_VERIFY(exists,
"MemoryManager has already been destroyed!");
1642#ifdef MFEM_TRACK_MEM_MANAGER
1643 size_t num_memories = maps->memories.size();
1644 size_t num_aliases = maps->aliases.size();
1645 if (num_memories != 0 || num_aliases != 0)
1647 MFEM_WARNING(
"...\n\t number of registered pointers: " << num_memories
1648 <<
"\n\t number of registered aliases : " << num_aliases);
1653 mfem::out <<
"Destroying the MemoryManager ...\n"
1654 <<
"remaining registered pointers : "
1655 << maps->memories.size() <<
'\n'
1656 <<
"remaining registered aliases : "
1657 << maps->aliases.size() <<
'\n';
1659 for (
auto& n : maps->memories)
1661 internal::Memory &mem = n.second;
1663 if (mem_h_ptr) { ctrl->Host(mem.h_mt)->Dealloc(mem.h_ptr); }
1664 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem); }
1666 delete maps; maps =
nullptr;
1667 delete ctrl; ctrl =
nullptr;
1688 for (
const auto& n : maps->memories)
1690 const internal::Memory &mem = n.second;
1691 os <<
"\nkey " << n.first <<
", "
1692 <<
"h_ptr " << mem.h_ptr <<
", "
1693 <<
"d_ptr " << mem.d_ptr;
1696 if (maps->memories.size() > 0) { os << std::endl; }
1703 for (
const auto& n : maps->aliases)
1705 const internal::Alias &alias = n.second;
1706 os <<
"\nalias: key " << n.first <<
", "
1707 <<
"h_ptr " << alias.mem->h_ptr <<
", "
1708 <<
"offset " << alias.offset <<
", "
1709 <<
"counter " << alias.counter;
1712 if (maps->aliases.size() > 0) { os << std::endl; }
1716int MemoryManager::CompareHostAndDevice_(
void *h_ptr,
size_t size,
1720 mm.GetAliasDevicePtr(h_ptr, size,
false) :
1721 mm.GetDevicePtr(h_ptr, size,
false);
1722 char *h_buf =
new char[size];
1723#if defined(MFEM_USE_CUDA)
1725#elif defined(MFEM_USE_HIP)
1728 std::memcpy(h_buf, d_ptr, size);
1730 int res = std::memcmp(h_ptr, h_buf, size);
1740 <<
"\n registered = " << bool(flags & Mem::Registered)
1741 <<
"\n owns host = " << bool(flags & Mem::OWNS_HOST)
1742 <<
"\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
1743 <<
"\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
1744 <<
"\n valid host = " << bool(flags & Mem::VALID_HOST)
1745 <<
"\n valid device = " << bool(flags & Mem::VALID_DEVICE)
1746 <<
"\n device flag = " << bool(flags & Mem::USE_DEVICE)
1747 <<
"\n alias = " << bool(flags & Mem::ALIAS)