17 #include <unordered_map>
28 #define mfem_memalign(p,a,s) posix_memalign(p,a,s)
29 #define mfem_aligned_free free
31 #define mfem_memalign(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno)
32 #define mfem_aligned_free _aligned_free
35 #ifdef MFEM_USE_UMPIRE
36 #include <umpire/Umpire.hpp>
37 #include <umpire/strategy/QuickPool.hpp>
40 #if defined(MFEM_USE_CUDA) && !defined(UMPIRE_ENABLE_CUDA)
41 #error "CUDA is not enabled in Umpire!"
44 #if defined(MFEM_USE_HIP) && !defined(UMPIRE_ENABLE_HIP)
45 #error "HIP is not enabled in Umpire!"
47 #endif // MFEM_USE_UMPIRE
65 MFEM_VERIFY(
false,
"");
86 MFEM_ABORT(
"invalid MemoryClass");
95 "d_mt = " << (
int)d_mt);
121 MFEM_VERIFY(sync,
"");
139 return std::max(mc1, mc2);
166 mutable bool h_rw, d_rw;
168 h_ptr(p), d_ptr(nullptr), bytes(b), h_mt(h), d_mt(d),
169 h_rw(true), d_rw(true) { }
184 typedef std::unordered_map<const void*, Memory> MemoryMap;
185 typedef std::unordered_map<const void*, Alias> AliasMap;
195 static internal::Maps *maps;
201 class HostMemorySpace
204 virtual ~HostMemorySpace() { }
205 virtual void Alloc(
void **ptr,
size_t bytes) { *ptr = std::malloc(bytes); }
206 virtual void Dealloc(
void *ptr) { std::free(ptr); }
207 virtual void Protect(
const Memory&,
size_t) { }
208 virtual void Unprotect(
const Memory&,
size_t) { }
209 virtual void AliasProtect(
const void*,
size_t) { }
210 virtual void AliasUnprotect(
const void*,
size_t) { }
214 class DeviceMemorySpace
217 virtual ~DeviceMemorySpace() { }
218 virtual void Alloc(Memory &base) { base.d_ptr = std::malloc(base.bytes); }
219 virtual void Dealloc(Memory &base) { std::free(base.d_ptr); }
220 virtual void Protect(
const Memory&) { }
221 virtual void Unprotect(
const Memory&) { }
222 virtual void AliasProtect(
const void*,
size_t) { }
223 virtual void AliasUnprotect(
const void*,
size_t) { }
224 virtual void *HtoD(
void *dst,
const void *src,
size_t bytes)
225 {
return std::memcpy(dst, src, bytes); }
226 virtual void *DtoD(
void *dst,
const void *src,
size_t bytes)
227 {
return std::memcpy(dst, src, bytes); }
228 virtual void *DtoH(
void *dst,
const void *src,
size_t bytes)
229 {
return std::memcpy(dst, src, bytes); }
233 class StdHostMemorySpace :
public HostMemorySpace { };
236 struct NoHostMemorySpace :
public HostMemorySpace
238 void Alloc(
void**,
const size_t) {
mfem_error(
"! Host Alloc error"); }
242 class Aligned32HostMemorySpace :
public HostMemorySpace
245 Aligned32HostMemorySpace(): HostMemorySpace() { }
246 void Alloc(
void **ptr,
size_t bytes)
247 {
if (mfem_memalign(ptr, 32, bytes) != 0) { throw ::std::bad_alloc(); } }
248 void Dealloc(
void *ptr) { mfem_aligned_free(ptr); }
252 class Aligned64HostMemorySpace :
public HostMemorySpace
255 Aligned64HostMemorySpace(): HostMemorySpace() { }
256 void Alloc(
void **ptr,
size_t bytes)
257 {
if (mfem_memalign(ptr, 64, bytes) != 0) { throw ::std::bad_alloc(); } }
258 void Dealloc(
void *ptr) { mfem_aligned_free(ptr); }
262 static uintptr_t pagesize = 0;
263 static uintptr_t pagemask = 0;
266 inline const void *MmuAddrR(
const void *ptr)
268 const uintptr_t addr = (uintptr_t) ptr;
269 return (addr & pagemask) ? (
void*) ((addr + pagesize) & ~pagemask) : ptr;
273 inline const void *MmuAddrP(
const void *ptr)
275 const uintptr_t addr = (uintptr_t) ptr;
276 return (
void*) (addr & ~pagemask);
280 inline uintptr_t MmuLengthR(
const void *ptr,
const size_t bytes)
283 const uintptr_t
a = (uintptr_t) ptr;
284 const uintptr_t A = (uintptr_t) MmuAddrR(ptr);
285 MFEM_ASSERT(a <= A,
"");
286 const uintptr_t
b = a + bytes;
287 const uintptr_t B = b & ~pagemask;
288 MFEM_ASSERT(B <= b,
"");
289 const uintptr_t length = B > A ? B - A : 0;
290 MFEM_ASSERT(length % pagesize == 0,
"");
295 inline uintptr_t MmuLengthP(
const void *ptr,
const size_t bytes)
298 const uintptr_t a = (uintptr_t) ptr;
299 const uintptr_t A = (uintptr_t) MmuAddrP(ptr);
300 MFEM_ASSERT(A <= a,
"");
301 const uintptr_t
b = a + bytes;
302 const uintptr_t B = b & pagemask ? (b + pagesize) & ~pagemask : b;
303 MFEM_ASSERT(b <= B,
"");
304 MFEM_ASSERT(B >= A,
"");
305 const uintptr_t length = B - A;
306 MFEM_ASSERT(length % pagesize == 0,
"");
311 static void MmuError(
int, siginfo_t *si,
void*)
315 const void *ptr = si->si_addr;
316 sprintf(str,
"Error while accessing address %p!", ptr);
317 mfem::out << std::endl <<
"An illegal memory access was made!";
322 static void MmuInit()
324 if (pagesize > 0) {
return; }
326 sa.sa_flags = SA_SIGINFO;
327 sigemptyset(&sa.sa_mask);
328 sa.sa_sigaction = MmuError;
329 if (sigaction(SIGBUS, &sa, NULL) == -1) {
mfem_error(
"SIGBUS"); }
330 if (sigaction(SIGSEGV, &sa, NULL) == -1) {
mfem_error(
"SIGSEGV"); }
331 pagesize = (uintptr_t) sysconf(_SC_PAGE_SIZE);
332 MFEM_ASSERT(pagesize > 0,
"pagesize must not be less than 1");
333 pagemask = pagesize - 1;
337 inline void MmuAlloc(
void **ptr,
const size_t bytes)
339 const size_t length = bytes == 0 ? 8 : bytes;
340 const int prot = PROT_READ | PROT_WRITE;
341 const int flags = MAP_ANONYMOUS | MAP_PRIVATE;
342 *ptr = ::mmap(NULL, length, prot, flags, -1, 0);
343 if (*ptr == MAP_FAILED) { throw ::std::bad_alloc(); }
347 inline void MmuDealloc(
void *ptr,
const size_t bytes)
349 const size_t length = bytes == 0 ? 8 : bytes;
350 if (::munmap(ptr, length) == -1) {
mfem_error(
"Dealloc error!"); }
354 inline void MmuProtect(
const void *ptr,
const size_t bytes)
356 static const bool mmu_protect_error = getenv(
"MFEM_MMU_PROTECT_ERROR");
357 if (!::mprotect(const_cast<void*>(ptr), bytes, PROT_NONE)) {
return; }
358 if (mmu_protect_error) {
mfem_error(
"MMU protection (NONE) error"); }
362 inline void MmuAllow(
const void *ptr,
const size_t bytes)
364 const int RW = PROT_READ | PROT_WRITE;
365 static const bool mmu_protect_error = getenv(
"MFEM_MMU_PROTECT_ERROR");
366 if (!::mprotect(const_cast<void*>(ptr), bytes, RW)) {
return; }
367 if (mmu_protect_error) {
mfem_error(
"MMU protection (R/W) error"); }
370 inline void MmuInit() { }
371 inline void MmuAlloc(
void **ptr,
const size_t bytes) { *ptr = std::malloc(bytes); }
372 inline void MmuDealloc(
void *ptr,
const size_t) { std::free(ptr); }
373 inline void MmuProtect(
const void*,
const size_t) { }
374 inline void MmuAllow(
const void*,
const size_t) { }
375 inline const void *MmuAddrR(
const void *a) {
return a; }
376 inline const void *MmuAddrP(
const void *a) {
return a; }
377 inline uintptr_t MmuLengthR(
const void*,
const size_t) {
return 0; }
378 inline uintptr_t MmuLengthP(
const void*,
const size_t) {
return 0; }
382 class MmuHostMemorySpace :
public HostMemorySpace
385 MmuHostMemorySpace(): HostMemorySpace() { MmuInit(); }
386 void Alloc(
void **ptr,
size_t bytes) { MmuAlloc(ptr, bytes); }
387 void Dealloc(
void *ptr) { MmuDealloc(ptr, maps->memories.at(ptr).bytes); }
388 void Protect(
const Memory& mem,
size_t bytes)
389 {
if (mem.h_rw) { mem.h_rw =
false; MmuProtect(mem.h_ptr, bytes); } }
390 void Unprotect(
const Memory &mem,
size_t bytes)
391 {
if (!mem.h_rw) { mem.h_rw =
true; MmuAllow(mem.h_ptr, bytes); } }
393 void AliasProtect(
const void *ptr,
size_t bytes)
394 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
396 void AliasUnprotect(
const void *ptr,
size_t bytes)
397 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
401 class UvmHostMemorySpace :
public HostMemorySpace
404 UvmHostMemorySpace(): HostMemorySpace() { }
405 void Alloc(
void **ptr,
size_t bytes) {
CuMallocManaged(ptr, bytes == 0 ? 8 : bytes); }
406 void Dealloc(
void *ptr) {
CuMemFree(ptr); }
410 class NoDeviceMemorySpace:
public DeviceMemorySpace
413 void Alloc(internal::Memory&) {
mfem_error(
"! Device Alloc"); }
414 void Dealloc(Memory&) {
mfem_error(
"! Device Dealloc"); }
415 void *HtoD(
void*,
const void*,
size_t) {
mfem_error(
"!HtoD");
return nullptr; }
416 void *DtoD(
void*,
const void*,
size_t) {
mfem_error(
"!DtoD");
return nullptr; }
417 void *DtoH(
void*,
const void*,
size_t) {
mfem_error(
"!DtoH");
return nullptr; }
421 class StdDeviceMemorySpace :
public DeviceMemorySpace { };
424 class CudaDeviceMemorySpace:
public DeviceMemorySpace
427 CudaDeviceMemorySpace(): DeviceMemorySpace() { }
428 void Alloc(Memory &base) {
CuMemAlloc(&base.d_ptr, base.bytes); }
429 void Dealloc(Memory &base) {
CuMemFree(base.d_ptr); }
430 void *HtoD(
void *dst,
const void *src,
size_t bytes)
432 void *DtoD(
void* dst,
const void* src,
size_t bytes)
434 void *DtoH(
void *dst,
const void *src,
size_t bytes)
439 class HostPinnedMemorySpace:
public HostMemorySpace
442 HostPinnedMemorySpace(): HostMemorySpace() { }
443 void Alloc(
void ** ptr,
size_t bytes)
override
452 void Dealloc(
void *ptr)
override
464 class HipDeviceMemorySpace:
public DeviceMemorySpace
467 HipDeviceMemorySpace(): DeviceMemorySpace() { }
468 void Alloc(Memory &base) {
HipMemAlloc(&base.d_ptr, base.bytes); }
469 void Dealloc(Memory &base) {
HipMemFree(base.d_ptr); }
470 void *HtoD(
void *dst,
const void *src,
size_t bytes)
472 void *DtoD(
void* dst,
const void* src,
size_t bytes)
477 void *DtoH(
void *dst,
const void *src,
size_t bytes)
482 class UvmCudaMemorySpace :
public DeviceMemorySpace
485 void Alloc(Memory &base) { base.d_ptr = base.h_ptr; }
486 void Dealloc(Memory&) { }
487 void *HtoD(
void *dst,
const void *src,
size_t bytes)
489 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
492 void *DtoD(
void* dst,
const void* src,
size_t bytes)
494 void *DtoH(
void *dst,
const void *src,
size_t bytes)
496 if (dst == src) { MFEM_STREAM_SYNC;
return dst; }
502 class MmuDeviceMemorySpace :
public DeviceMemorySpace
505 MmuDeviceMemorySpace(): DeviceMemorySpace() { }
506 void Alloc(Memory &m) { MmuAlloc(&m.d_ptr, m.bytes); }
507 void Dealloc(Memory &m) { MmuDealloc(m.d_ptr, m.bytes); }
508 void Protect(
const Memory &m)
509 {
if (m.d_rw) { m.d_rw =
false; MmuProtect(m.d_ptr, m.bytes); } }
510 void Unprotect(
const Memory &m)
511 {
if (!m.d_rw) { m.d_rw =
true; MmuAllow(m.d_ptr, m.bytes); } }
513 void AliasProtect(
const void *ptr,
size_t bytes)
514 { MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
516 void AliasUnprotect(
const void *ptr,
size_t bytes)
517 { MmuAllow(MmuAddrP(ptr), MmuLengthP(ptr, bytes)); }
518 void *HtoD(
void *dst,
const void *src,
size_t bytes)
519 {
return std::memcpy(dst, src, bytes); }
520 void *DtoD(
void *dst,
const void *src,
size_t bytes)
521 {
return std::memcpy(dst, src, bytes); }
522 void *DtoH(
void *dst,
const void *src,
size_t bytes)
523 {
return std::memcpy(dst, src, bytes); }
526 #ifdef MFEM_USE_UMPIRE
527 class UmpireMemorySpace
530 umpire::ResourceManager &rm;
531 umpire::Allocator allocator;
532 bool owns_allocator{
false};
536 virtual ~UmpireMemorySpace() {
if (owns_allocator) { allocator.release(); } }
537 UmpireMemorySpace(
const char * name,
const char *
space)
538 : rm(umpire::ResourceManager::getInstance())
540 if (!rm.isAllocator(name))
542 allocator = rm.makeAllocator<umpire::strategy::QuickPool>(
543 name, rm.getAllocator(space));
544 owns_allocator =
true;
548 allocator = rm.getAllocator(name);
549 owns_allocator =
false;
555 class UmpireHostMemorySpace :
public HostMemorySpace,
public UmpireMemorySpace
558 umpire::strategy::AllocationStrategy *strat;
560 UmpireHostMemorySpace(
const char * name)
562 UmpireMemorySpace(name,
"HOST"),
563 strat(allocator.getAllocationStrategy()) {}
564 void Alloc(
void **ptr,
size_t bytes)
override
565 { *ptr = allocator.allocate(bytes); }
566 void Dealloc(
void *ptr)
override { allocator.deallocate(ptr); }
567 void Insert(
void *ptr,
size_t bytes)
568 { rm.registerAllocation(ptr, {ptr, bytes, strat}); }
572 #if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
573 class UmpireDeviceMemorySpace :
public DeviceMemorySpace,
574 public UmpireMemorySpace
577 UmpireDeviceMemorySpace(
const char * name)
578 : DeviceMemorySpace(),
579 UmpireMemorySpace(name,
"DEVICE") {}
580 void Alloc(Memory &base)
override
581 { base.d_ptr = allocator.allocate(base.bytes); }
582 void Dealloc(Memory &base)
override { rm.deallocate(base.d_ptr); }
583 void *HtoD(
void *dst,
const void *src,
size_t bytes)
override
593 void *DtoD(
void* dst,
const void* src,
size_t bytes)
override
606 void *DtoH(
void *dst,
const void *src,
size_t bytes)
override
618 class UmpireDeviceMemorySpace :
public NoDeviceMemorySpace
621 UmpireDeviceMemorySpace(
const char * ) {}
623 #endif // MFEM_USE_CUDA || MFEM_USE_HIP
624 #endif // MFEM_USE_UMPIRE
636 Ctrl(): host{
nullptr}, device{
nullptr} { }
642 mfem_error(
"Memory backends have already been configured!");
648 host[
static_cast<int>(
MT::HOST)] =
new StdHostMemorySpace();
649 host[
static_cast<int>(
MT::HOST_32)] =
new Aligned32HostMemorySpace();
650 host[
static_cast<int>(
MT::HOST_64)] =
new Aligned64HostMemorySpace();
654 host[
static_cast<int>(
MT::MANAGED)] =
new UvmHostMemorySpace();
658 device[
static_cast<int>(
MT::MANAGED)-shift] =
new UvmCudaMemorySpace();
668 const int mt_i =
static_cast<int>(mt);
670 if (!host[mt_i]) { host[mt_i] = NewHostCtrl(mt); }
671 MFEM_ASSERT(host[mt_i],
"Host memory controller is not configured!");
675 DeviceMemorySpace* Device(
const MemoryType mt)
678 MFEM_ASSERT(mt_i >= 0,
"");
680 if (!device[mt_i]) { device[mt_i] = NewDeviceCtrl(mt); }
681 MFEM_ASSERT(device[mt_i],
"Memory manager has not been configured!");
690 for (
int mt = mt_d; mt <
MemoryTypeSize; mt++) {
delete device[mt-mt_d]; }
694 HostMemorySpace* NewHostCtrl(
const MemoryType mt)
699 #ifdef MFEM_USE_UMPIRE
701 return new UmpireHostMemorySpace(
707 default: MFEM_ABORT(
"Unknown host memory controller!");
712 DeviceMemorySpace* NewDeviceCtrl(
const MemoryType mt)
716 #ifdef MFEM_USE_UMPIRE
718 return new UmpireDeviceMemorySpace(
721 return new UmpireDeviceMemorySpace(
730 #if defined(MFEM_USE_CUDA)
731 return new CudaDeviceMemorySpace();
732 #elif defined(MFEM_USE_HIP)
733 return new HipDeviceMemorySpace();
735 MFEM_ABORT(
"No device memory controller!");
739 default: MFEM_ABORT(
"Unknown device memory controller!");
747 static internal::Ctrl *ctrl;
749 void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType mt,
752 MFEM_ASSERT(exists,
"Internal error!");
771 void *MemoryManager::New_(
void *h_tmp,
size_t bytes,
MemoryType h_mt,
775 MFEM_ASSERT(exists,
"Internal error!");
776 MFEM_ASSERT(
IsHostMemory(h_mt),
"h_mt must be host type");
779 "d_mt must be device type, the same is h_mt, or DEFAULT");
786 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
787 else { h_ptr = h_tmp; }
791 mm.Insert(h_ptr, bytes, h_mt, d_mt);
795 CheckHostMemoryType_(h_mt, h_ptr,
false);
800 void *MemoryManager::Register_(
void *ptr,
void *h_tmp,
size_t bytes,
802 bool own,
bool alias,
unsigned &flags)
804 MFEM_CONTRACT_VAR(alias);
805 MFEM_ASSERT(exists,
"Internal error!");
806 MFEM_VERIFY(!alias,
"Cannot register an alias!");
814 MFEM_VERIFY_TYPES(h_mt, d_mt);
816 if (ptr ==
nullptr && h_tmp ==
nullptr)
818 MFEM_VERIFY(bytes == 0,
"internal error");
828 mm.Insert(h_ptr, bytes, h_mt, d_mt);
829 flags = (own ? flags |
Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST) |
834 MFEM_VERIFY(ptr || bytes == 0,
835 "cannot register NULL device pointer with bytes = " << bytes);
836 if (h_tmp ==
nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
837 else { h_ptr = h_tmp; }
838 mm.InsertDevice(ptr, h_ptr, bytes, h_mt, d_mt);
842 CheckHostMemoryType_(h_mt, h_ptr, alias);
846 void MemoryManager::Register2_(
void *h_ptr,
void *d_ptr,
size_t bytes,
848 bool own,
bool alias,
unsigned &flags)
850 MFEM_CONTRACT_VAR(alias);
851 MFEM_ASSERT(exists,
"Internal error!");
852 MFEM_ASSERT(!alias,
"Cannot register an alias!");
853 MFEM_VERIFY_TYPES(h_mt, d_mt);
855 if (h_ptr ==
nullptr && d_ptr ==
nullptr)
857 MFEM_VERIFY(bytes == 0,
"internal error");
863 MFEM_VERIFY(d_ptr || bytes == 0,
864 "cannot register NULL device pointer with bytes = " << bytes);
865 mm.InsertDevice(d_ptr, h_ptr, bytes, h_mt, d_mt);
870 CheckHostMemoryType_(h_mt, h_ptr, alias);
873 void MemoryManager::Alias_(
void *base_h_ptr,
size_t offset,
size_t bytes,
874 unsigned base_flags,
unsigned &flags)
876 mm.InsertAlias(base_h_ptr, (
char*)base_h_ptr + offset, bytes,
882 void MemoryManager::SetDeviceMemoryType_(
void *h_ptr,
unsigned flags,
885 MFEM_VERIFY(h_ptr,
"cannot set the device memory type: Memory is empty!");
886 if (!(flags & Mem::ALIAS))
888 auto mem_iter = maps->memories.find(h_ptr);
889 MFEM_VERIFY(mem_iter != maps->memories.end(),
"internal error");
890 internal::Memory &mem = mem_iter->second;
891 if (mem.d_mt == d_mt) {
return; }
892 MFEM_VERIFY(mem.d_ptr ==
nullptr,
"cannot set the device memory type:"
893 " device memory is allocated!");
898 auto alias_iter = maps->aliases.find(h_ptr);
899 MFEM_VERIFY(alias_iter != maps->aliases.end(),
"internal error");
900 internal::Alias &alias = alias_iter->second;
901 internal::Memory &base_mem = *alias.mem;
902 if (base_mem.d_mt == d_mt) {
return; }
903 MFEM_VERIFY(base_mem.d_ptr ==
nullptr,
904 "cannot set the device memory type:"
905 " alias' base device memory is allocated!");
906 base_mem.d_mt = d_mt;
917 MFEM_ASSERT(
IsHostMemory(h_mt),
"invalid h_mt = " << (
int)h_mt);
919 MFEM_ASSERT(!owns_device || owns_internal,
"invalid Memory state");
924 MFEM_ASSERT(registered || !(owns_host || owns_device || owns_internal) ||
925 (!(owns_device || owns_internal) && h_ptr ==
nullptr),
926 "invalid Memory state");
927 if (!
mm.exists || !registered) {
return h_mt; }
933 MFEM_ASSERT(h_mt == maps->aliases.at(h_ptr).h_mt,
"");
934 mm.EraseAlias(h_ptr);
940 { ctrl->Host(h_mt)->Dealloc(h_ptr); }
944 MFEM_ASSERT(h_mt == maps->memories.at(h_ptr).h_mt,
"");
945 mm.Erase(h_ptr, owns_device);
951 void MemoryManager::DeleteDevice_(
void *h_ptr,
unsigned & flags)
956 mm.EraseDevice(h_ptr);
961 bool MemoryManager::MemoryClassCheck_(
MemoryClass mc,
void *h_ptr,
967 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
971 if (!(flags & Mem::ALIAS))
973 auto iter = maps->memories.find(h_ptr);
974 MFEM_VERIFY(iter != maps->memories.end(),
"internal error");
975 d_mt = iter->second.d_mt;
979 auto iter = maps->aliases.find(h_ptr);
980 MFEM_VERIFY(iter != maps->aliases.end(),
"internal error");
981 d_mt = iter->second.mem->d_mt;
1018 size_t bytes,
unsigned &flags)
1020 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
1021 if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,
""); }
1022 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1027 if (flags & Mem::ALIAS)
1028 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1029 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1035 if (flags & Mem::ALIAS)
1036 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1037 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1042 size_t bytes,
unsigned &flags)
1044 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
1045 if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,
""); }
1046 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1051 if (flags & Mem::ALIAS)
1052 {
return mm.GetAliasHostPtr(h_ptr, bytes, copy); }
1053 else {
return mm.GetHostPtr(h_ptr, bytes, copy); }
1059 if (flags & Mem::ALIAS)
1060 {
return mm.GetAliasDevicePtr(h_ptr, bytes, copy); }
1061 else {
return mm.GetDevicePtr(h_ptr, bytes, copy); }
1066 size_t bytes,
unsigned &flags)
1068 if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
1069 if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,
""); }
1070 MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),
"");
1074 if (flags & Mem::ALIAS)
1075 {
return mm.GetAliasHostPtr(h_ptr, bytes,
false); }
1076 else {
return mm.GetHostPtr(h_ptr, bytes,
false); }
1081 if (flags & Mem::ALIAS)
1082 {
return mm.GetAliasDevicePtr(h_ptr, bytes,
false); }
1083 else {
return mm.GetDevicePtr(h_ptr, bytes,
false); }
1087 void MemoryManager::SyncAlias_(
const void *base_h_ptr,
void *alias_h_ptr,
1088 size_t alias_bytes,
unsigned base_flags,
1089 unsigned &alias_flags)
1093 MFEM_ASSERT(alias_flags & Mem::ALIAS,
"not an alias");
1094 if ((base_flags &
Mem::VALID_HOST) && !(alias_flags & Mem::VALID_HOST))
1096 mm.GetAliasHostPtr(alias_h_ptr, alias_bytes,
true);
1100 if (!(alias_flags & Mem::REGISTERED))
1102 mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags & Mem::ALIAS);
1104 ~(Mem::OWNS_HOST | Mem::OWNS_DEVICE);
1106 mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes,
true);
1112 MemoryType MemoryManager::GetDeviceMemoryType_(
void *h_ptr,
bool alias)
1118 auto iter = maps->memories.find(h_ptr);
1119 MFEM_ASSERT(iter != maps->memories.end(),
"internal error");
1120 return iter->second.d_mt;
1123 auto iter = maps->aliases.find(h_ptr);
1124 MFEM_ASSERT(iter != maps->aliases.end(),
"internal error");
1125 return iter->second.mem->d_mt;
1127 MFEM_ABORT(
"internal error");
1128 return MemoryManager::host_mem_type;
1131 MemoryType MemoryManager::GetHostMemoryType_(
void *h_ptr)
1133 if (!
mm.exists) {
return MemoryManager::host_mem_type; }
1134 if (
mm.
IsKnown(h_ptr)) {
return maps->memories.at(h_ptr).h_mt; }
1135 if (
mm.
IsAlias(h_ptr)) {
return maps->aliases.at(h_ptr).h_mt; }
1136 return MemoryManager::host_mem_type;
1139 void MemoryManager::Copy_(
void *dst_h_ptr,
const void *src_h_ptr,
1140 size_t bytes,
unsigned src_flags,
1141 unsigned &dst_flags)
1151 const bool dst_on_host =
1153 (!(dst_flags & Mem::VALID_DEVICE) ||
1156 dst_flags = dst_flags &
1159 const bool src_on_host =
1161 (!(src_flags & Mem::VALID_DEVICE) ||
1164 const void *src_d_ptr =
1165 src_on_host ? NULL :
1167 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1168 mm.GetDevicePtr(src_h_ptr, bytes,
false));
1174 if (dst_h_ptr != src_h_ptr && bytes != 0)
1176 MFEM_ASSERT((
const char*)dst_h_ptr + bytes <= src_h_ptr ||
1177 (
const char*)src_h_ptr + bytes <= dst_h_ptr,
1179 std::memcpy(dst_h_ptr, src_h_ptr, bytes);
1184 if (dst_h_ptr != src_d_ptr && bytes != 0)
1186 internal::Memory &src_d_base = maps->memories.at(src_h_ptr);
1188 ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
1194 void *dest_d_ptr = (dst_flags &
Mem::ALIAS) ?
1195 mm.GetAliasDevicePtr(dst_h_ptr, bytes,
false) :
1196 mm.GetDevicePtr(dst_h_ptr, bytes,
false);
1199 const bool known =
mm.
IsKnown(dst_h_ptr);
1201 MFEM_VERIFY(alias||known,
"");
1203 maps->memories.at(dst_h_ptr).d_mt :
1204 maps->aliases.at(dst_h_ptr).mem->d_mt;
1205 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1209 if (dest_d_ptr != src_d_ptr && bytes != 0)
1211 const bool known =
mm.
IsKnown(dst_h_ptr);
1213 MFEM_VERIFY(alias||known,
"");
1215 maps->memories.at(dst_h_ptr).d_mt :
1216 maps->aliases.at(dst_h_ptr).mem->d_mt;
1217 ctrl->Device(d_mt)->DtoD(dest_d_ptr, src_d_ptr, bytes);
1223 void MemoryManager::CopyToHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1224 size_t bytes,
unsigned src_flags)
1229 if (dest_h_ptr != src_h_ptr && bytes != 0)
1231 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1232 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1234 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1239 MFEM_ASSERT(IsKnown_(src_h_ptr),
"internal error");
1240 const void *src_d_ptr = (src_flags &
Mem::ALIAS) ?
1241 mm.GetAliasDevicePtr(src_h_ptr, bytes,
false) :
1242 mm.GetDevicePtr(src_h_ptr, bytes,
false);
1243 const internal::Memory &base = maps->memories.at(dest_h_ptr);
1245 ctrl->Device(d_mt)->DtoH(dest_h_ptr, src_d_ptr, bytes);
1249 void MemoryManager::CopyFromHost_(
void *dest_h_ptr,
const void *src_h_ptr,
1250 size_t bytes,
unsigned &dest_flags)
1255 if (dest_h_ptr != src_h_ptr && bytes != 0)
1257 MFEM_ASSERT((
char*)dest_h_ptr + bytes <= src_h_ptr ||
1258 (
const char*)src_h_ptr + bytes <= dest_h_ptr,
1260 std::memcpy(dest_h_ptr, src_h_ptr, bytes);
1265 void *dest_d_ptr = (dest_flags &
Mem::ALIAS) ?
1266 mm.GetAliasDevicePtr(dest_h_ptr, bytes,
false) :
1267 mm.GetDevicePtr(dest_h_ptr, bytes,
false);
1268 const internal::Memory &base = maps->memories.at(dest_h_ptr);
1270 ctrl->Device(d_mt)->HtoD(dest_d_ptr, src_h_ptr, bytes);
1272 dest_flags = dest_flags &
1276 bool MemoryManager::IsKnown_(
const void *h_ptr)
1278 return maps->memories.find(h_ptr) != maps->memories.end();
1281 bool MemoryManager::IsAlias_(
const void *h_ptr)
1283 return maps->aliases.find(h_ptr) != maps->aliases.end();
1286 void MemoryManager::Insert(
void *h_ptr,
size_t bytes,
1289 #ifdef MFEM_TRACK_MEM_MANAGER
1290 mfem::out <<
"[mfem memory manager]: registering h_ptr: " << h_ptr
1291 <<
", bytes: " << bytes << std::endl;
1295 MFEM_VERIFY(bytes == 0,
"Trying to add NULL with size " << bytes);
1298 MFEM_VERIFY_TYPES(h_mt, d_mt);
1302 maps->memories.emplace(h_ptr, internal::Memory(h_ptr, bytes, h_mt, d_mt));
1304 if (res.second ==
false)
1306 auto &m = res.first->second;
1307 MFEM_VERIFY(m.bytes >= bytes && m.h_mt == h_mt &&
1310 "Address already present with different attributes!");
1311 #ifdef MFEM_TRACK_MEM_MANAGER
1312 mfem::out <<
"[mfem memory manager]: repeated registration of h_ptr: "
1313 << h_ptr << std::endl;
1319 void MemoryManager::InsertDevice(
void *d_ptr,
void *h_ptr,
size_t bytes,
1323 MFEM_ASSERT(h_ptr != NULL,
"internal error");
1324 Insert(h_ptr, bytes, h_mt, d_mt);
1325 internal::Memory &mem = maps->memories.at(h_ptr);
1326 if (d_ptr == NULL && bytes != 0) { ctrl->Device(d_mt)->Alloc(mem); }
1327 else { mem.d_ptr = d_ptr; }
1330 void MemoryManager::InsertAlias(
const void *base_ptr,
void *alias_ptr,
1331 const size_t bytes,
const bool base_is_alias)
1333 size_t offset =
static_cast<size_t>(
static_cast<const char*
>(alias_ptr) -
1334 static_cast<const char*>(base_ptr));
1335 #ifdef MFEM_TRACK_MEM_MANAGER
1336 mfem::out <<
"[mfem memory manager]: registering alias of base_ptr: "
1337 << base_ptr <<
", offset: " << offset <<
", bytes: " << bytes
1338 <<
", base is alias: " << base_is_alias << std::endl;
1342 MFEM_VERIFY(offset == 0,
1343 "Trying to add alias to NULL at offset " << offset);
1348 const internal::Alias &alias = maps->aliases.at(base_ptr);
1349 MFEM_ASSERT(alias.mem,
"");
1350 base_ptr = alias.mem->h_ptr;
1351 offset += alias.offset;
1352 #ifdef MFEM_TRACK_MEM_MANAGER
1353 mfem::out <<
"[mfem memory manager]: real base_ptr: " << base_ptr
1357 internal::Memory &mem = maps->memories.at(base_ptr);
1358 MFEM_VERIFY(offset + bytes <= mem.bytes,
"invalid alias");
1360 maps->aliases.emplace(alias_ptr,
1361 internal::Alias{&mem, offset, 1, mem.h_mt});
1362 if (res.second ==
false)
1364 internal::Alias &alias = res.first->second;
1367 alias.offset = offset;
1368 alias.h_mt = mem.h_mt;
1373 void MemoryManager::Erase(
void *h_ptr,
bool free_dev_ptr)
1375 #ifdef MFEM_TRACK_MEM_MANAGER
1376 mfem::out <<
"[mfem memory manager]: un-registering h_ptr: " << h_ptr
1379 if (!h_ptr) {
return; }
1380 auto mem_map_iter = maps->memories.find(h_ptr);
1381 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1382 internal::Memory &mem = mem_map_iter->second;
1383 if (mem.d_ptr && free_dev_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1384 maps->memories.erase(mem_map_iter);
1387 void MemoryManager::EraseDevice(
void *h_ptr)
1389 if (!h_ptr) {
return; }
1390 auto mem_map_iter = maps->memories.find(h_ptr);
1391 if (mem_map_iter == maps->memories.end()) {
mfem_error(
"Unknown pointer!"); }
1392 internal::Memory &mem = mem_map_iter->second;
1393 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
1394 mem.d_ptr =
nullptr;
1397 void MemoryManager::EraseAlias(
void *alias_ptr)
1399 #ifdef MFEM_TRACK_MEM_MANAGER
1400 mfem::out <<
"[mfem memory manager]: un-registering alias_ptr: " << alias_ptr
1403 if (!alias_ptr) {
return; }
1404 auto alias_map_iter = maps->aliases.find(alias_ptr);
1405 if (alias_map_iter == maps->aliases.end()) {
mfem_error(
"Unknown alias!"); }
1406 internal::Alias &alias = alias_map_iter->second;
1407 if (--alias.counter) {
return; }
1408 maps->aliases.erase(alias_map_iter);
1411 void *MemoryManager::GetDevicePtr(
const void *h_ptr,
size_t bytes,
1416 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1419 internal::Memory &mem = maps->memories.at(h_ptr);
1422 MFEM_VERIFY_TYPES(h_mt, d_mt);
1426 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1429 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1432 MFEM_ASSERT(bytes <= mem.bytes,
"invalid copy size");
1433 if (bytes) { ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes); }
1435 ctrl->Host(h_mt)->Protect(mem, bytes);
1439 void *MemoryManager::GetAliasDevicePtr(
const void *alias_ptr,
size_t bytes,
1444 MFEM_VERIFY(bytes == 0,
"Trying to access NULL with size " << bytes);
1447 auto &alias_map = maps->aliases;
1448 auto alias_map_iter = alias_map.find(alias_ptr);
1449 if (alias_map_iter == alias_map.end()) {
mfem_error(
"alias not found"); }
1450 const internal::Alias &alias = alias_map_iter->second;
1451 const size_t offset = alias.offset;
1452 internal::Memory &mem = *alias.mem;
1455 MFEM_VERIFY_TYPES(h_mt, d_mt);
1459 if (mem.bytes) { ctrl->Device(d_mt)->Alloc(mem); }
1461 void *alias_h_ptr =
static_cast<char*
>(mem.h_ptr) + offset;
1462 void *alias_d_ptr =
static_cast<char*
>(mem.d_ptr) + offset;
1463 MFEM_ASSERT(alias_h_ptr == alias_ptr,
"internal error");
1464 MFEM_ASSERT(offset + bytes <= mem.bytes,
"internal error");
1465 mem.d_rw = mem.h_rw =
false;
1466 if (mem.d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1467 ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
1468 if (copy && mem.d_ptr)
1469 { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
1470 ctrl->Host(h_mt)->AliasProtect(alias_ptr, bytes);
1474 void *MemoryManager::GetHostPtr(
const void *ptr,
size_t bytes,
bool copy)
1476 const internal::Memory &mem = maps->memories.at(ptr);
1477 MFEM_ASSERT(mem.h_ptr == ptr,
"internal error");
1478 MFEM_ASSERT(bytes <= mem.bytes,
"internal error")
1481 MFEM_VERIFY_TYPES(h_mt, d_mt);
1483 ctrl->Host(h_mt)->Unprotect(mem, bytes);
1484 if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
1485 if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
1486 if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
1490 void *MemoryManager::GetAliasHostPtr(
const void *ptr,
size_t bytes,
1493 const internal::Alias &alias = maps->aliases.at(ptr);
1494 const internal::Memory *
const mem = alias.mem;
1497 MFEM_VERIFY_TYPES(h_mt, d_mt);
1498 void *alias_h_ptr =
static_cast<char*
>(mem->h_ptr) + alias.offset;
1499 void *alias_d_ptr = static_cast<char*>(mem->d_ptr) + alias.offset;
1500 MFEM_ASSERT(alias_h_ptr == ptr,
"internal error");
1502 ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
1503 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
1504 if (copy_data && mem->d_ptr)
1505 { ctrl->Device(d_mt)->DtoH(const_cast<void*>(ptr), alias_d_ptr, bytes); }
1506 if (mem->d_ptr) { ctrl->Device(d_mt)->AliasProtect(alias_d_ptr, bytes); }
1512 if (exists) {
return; }
1513 maps =
new internal::Maps();
1514 ctrl =
new internal::Ctrl();
1525 MFEM_VERIFY(!configured,
"changing the dual MemoryTypes is not allowed after"
1526 " MemoryManager configuration!");
1527 UpdateDualMemoryType(mt, dual_mt);
1533 "invalid MemoryType, mt = " << (
int)mt);
1535 "invalid dual MemoryType, dual_mt = " << (
int)dual_mt);
1540 dual_map[(int)mt] = dual_mt;
1548 "invalid (mt, dual_mt) pair: ("
1557 MemoryManager::UpdateDualMemoryType(host_mt, device_mt);
1558 MemoryManager::UpdateDualMemoryType(device_mt, host_mt);
1563 MemoryManager::UpdateDualMemoryType(
1568 host_mem_type = host_mt;
1569 device_mem_type = device_mt;
1575 MFEM_VERIFY(exists,
"MemoryManager has already been destroyed!");
1576 #ifdef MFEM_TRACK_MEM_MANAGER
1577 size_t num_memories = maps->memories.size();
1578 size_t num_aliases = maps->aliases.size();
1579 if (num_memories != 0 || num_aliases != 0)
1581 MFEM_WARNING(
"...\n\t number of registered pointers: " << num_memories
1582 <<
"\n\t number of registered aliases : " << num_aliases);
1587 mfem::out <<
"Destroying the MemoryManager ...\n"
1588 <<
"remaining registered pointers : "
1589 << maps->memories.size() <<
'\n'
1590 <<
"remaining registered aliases : "
1591 << maps->aliases.size() <<
'\n';
1593 for (
auto& n : maps->memories)
1595 internal::Memory &mem = n.second;
1597 if (mem_h_ptr) { ctrl->Host(mem.h_mt)->Dealloc(mem.h_ptr); }
1598 if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem); }
1600 delete maps; maps =
nullptr;
1601 delete ctrl; ctrl =
nullptr;
1622 for (
const auto& n : maps->memories)
1624 const internal::Memory &mem = n.second;
1625 os <<
"\nkey " << n.first <<
", "
1626 <<
"h_ptr " << mem.h_ptr <<
", "
1627 <<
"d_ptr " << mem.d_ptr;
1630 if (maps->memories.size() > 0) { os << std::endl; }
1637 for (
const auto& n : maps->aliases)
1639 const internal::Alias &alias = n.second;
1640 os <<
"\nalias: key " << n.first <<
", "
1641 <<
"h_ptr " << alias.mem->h_ptr <<
", "
1642 <<
"offset " << alias.offset <<
", "
1643 <<
"counter " << alias.counter;
1646 if (maps->aliases.size() > 0) { os << std::endl; }
1650 int MemoryManager::CompareHostAndDevice_(
void *h_ptr,
size_t size,
1654 mm.GetAliasDevicePtr(h_ptr, size,
false) :
1655 mm.GetDevicePtr(h_ptr, size,
false);
1656 char *h_buf =
new char[size];
1657 #ifdef MFEM_USE_CUDA
1662 std::memcpy(h_buf, d_ptr, size);
1664 int res = std::memcmp(h_ptr, h_buf, size);
1674 <<
"\n registered = " << bool(flags & Mem::REGISTERED)
1675 <<
"\n owns host = " << bool(flags & Mem::OWNS_HOST)
1676 <<
"\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
1677 <<
"\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
1678 <<
"\n valid host = " << bool(flags & Mem::VALID_HOST)
1679 <<
"\n valid device = " << bool(flags & Mem::VALID_DEVICE)
1680 <<
"\n device flag = " << bool(flags & Mem::USE_DEVICE)
1681 <<
"\n alias = " << bool(flags & Mem::ALIAS)
1685 void MemoryManager::CheckHostMemoryType_(
MemoryType h_mt,
void *h_ptr,
1688 if (!
mm.exists) {
return;}
1691 auto it = maps->memories.find(h_ptr);
1692 MFEM_VERIFY(it != maps->memories.end(),
1693 "host pointer is not registered: h_ptr = " << h_ptr);
1694 MFEM_VERIFY(h_mt == it->second.h_mt,
"host pointer MemoryType mismatch");
1698 auto it = maps->aliases.find(h_ptr);
1699 MFEM_VERIFY(it != maps->aliases.end(),
1700 "alias pointer is not registered: h_ptr = " << h_ptr);
1701 MFEM_VERIFY(h_mt == it->second.h_mt,
"alias pointer MemoryType mismatch");
1707 bool MemoryManager::exists =
false;
1708 bool MemoryManager::configured =
false;
1725 MemoryType::HOST_UMPIRE
1728 #ifdef MFEM_USE_UMPIRE
1729 const char * MemoryManager::h_umpire_name =
"MFEM_HOST";
1730 const char * MemoryManager::d_umpire_name =
"MFEM_DEVICE";
1731 const char * MemoryManager::d_umpire_2_name =
"MFEM_DEVICE_2";
1737 "host-std",
"host-32",
"host-64",
"host-debug",
"host-umpire",
"host-pinned",
1738 #if defined(MFEM_USE_CUDA)
1741 #elif defined(MFEM_USE_HIP)
1749 #if defined(MFEM_USE_CUDA)
1752 #elif defined(MFEM_USE_HIP)
void * CuMemcpyHtoD(void *dst, const void *src, size_t bytes)
Copies memory from Host to Device and returns destination ptr.
void * CuMemFree(void *dptr)
Frees device memory and returns destination ptr.
Host memory; aligned at 64 bytes.
bool IsHostMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::HOST.
Device memory; using CUDA or HIP *Malloc and *Free.
void * CuMemFreeHostPinned(void *ptr)
Frees page-locked (pinned) host memory and returns destination ptr.
void PrintFlags() const
Print the internal flags.
static const char * GetUmpireHostAllocatorName()
Get the host Umpire allocator name used with MemoryType::HOST_UMPIRE.
const char * MemoryTypeName[MemoryTypeSize]
Memory type names, used during Device:: configuration.
static MemoryType GetHostMemoryType()
Host memory; allocated from a "host-debug" pool.
void Configure(const MemoryType h_mt, const MemoryType d_mt)
Configure the Memory manager with given default host and device types. This method will be called whe...
Host memory: pinned (page-locked)
int PrintAliases(std::ostream &out=mfem::out)
int CompareHostAndDevice(int size) const
If both the host and the device data are valid, compare their contents.
bool IsAlias(const void *h_ptr)
Return true if the pointer is known by the memory manager as an alias.
bool MemoryClassContainsType(MemoryClass mc, MemoryType mt)
Return true iff the MemoryType mt is contained in the MemoryClass mc.
void * HipMemcpyDtoDAsync(void *dst, const void *src, size_t bytes)
Copies memory from Device to Device.
void * HipMemFreeHostPinned(void *ptr)
Frees page-locked (pinned) host memory and returns destination ptr.
void * CuMallocManaged(void **dptr, size_t bytes)
Allocates managed device memory.
Host memory; aligned at 32 bytes.
static MemoryType GetDualMemoryType(MemoryType mt)
Return the dual MemoryType of the given one, mt.
constexpr int DeviceMemoryType
static const char * GetUmpireDeviceAllocatorName()
Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE.
void * HipMemAllocHostPinned(void **ptr, size_t bytes)
Allocates page-locked (pinned) host memory.
constexpr int HostMemoryType
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
static MemoryType GetDeviceMemoryType()
void * HipMemFree(void *dptr)
Frees device memory.
Ownership flag for internal Memory data.
void Destroy()
Free all the device memories.
int PrintPtrs(std::ostream &out=mfem::out)
The host pointer will be deleted by Delete()
void * CuMemcpyDtoD(void *dst, const void *src, size_t bytes)
Copies memory from Device to Device.
void RegisterCheck(void *h_ptr)
Check if the host pointer has been registered in the memory manager.
constexpr int MemoryTypeSize
Static casts to 'int' and sizes of some useful memory types.
void * HipMemcpyDtoH(void *dst, const void *src, size_t bytes)
Copies memory from Device to Host.
static const char * GetUmpireDevice2AllocatorName()
Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2.
void * HipMemAlloc(void **dptr, size_t bytes)
Allocates device memory.
double p(const Vector &x, double t)
static void SetDualMemoryType(MemoryType mt, MemoryType dual_mt)
Set the dual memory type of mt to be dual_mt.
void Init()
Initialize the memory manager.
MemoryType
Memory types supported by MFEM.
bool IsKnown(const void *h_ptr)
Return true if the pointer is known by the memory manager.
constexpr int HostMemoryTypeSize
bool IsDeviceMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::DEVICE.
MemoryManager mm
The (single) global memory manager object.
Host memory; using new[] and delete[].
void * HipMemcpyHtoD(void *dst, const void *src, size_t bytes)
Copies memory from Host to Device.
MemoryType GetMemoryType(MemoryClass mc)
Return a suitable MemoryType for a given MemoryClass.
void * CuMemAllocHostPinned(void **ptr, size_t bytes)
Allocates page-locked (pinned) host memory.
constexpr int DeviceMemoryTypeSize
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
MemoryClass operator*(MemoryClass mc1, MemoryClass mc2)
Return a suitable MemoryClass from a pair of MemoryClasses.
void * CuMemAlloc(void **dptr, size_t bytes)
Allocates device memory and returns destination ptr.
MemoryClass
Memory classes identify sets of memory types.
void * CuMemcpyDtoH(void *dst, const void *src, size_t bytes)
Copies memory from Device to Host.
void MemoryPrintFlags(unsigned flags)
Print the state of a Memory object based on its internal flags. Useful in a debugger. See also Memory<T>::PrintFlags().