diff options
Diffstat (limited to 'src/zencore/memory/mallocmimalloc.cpp')
| -rw-r--r-- | src/zencore/memory/mallocmimalloc.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/zencore/memory/mallocmimalloc.cpp b/src/zencore/memory/mallocmimalloc.cpp new file mode 100644 index 000000000..1919af3bf --- /dev/null +++ b/src/zencore/memory/mallocmimalloc.cpp @@ -0,0 +1,197 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include <zencore/intmath.h> +#include <zencore/memory/align.h> +#include <zencore/memory/mallocmimalloc.h> + +#if ZEN_MIMALLOC_ENABLED + +# include <mimalloc.h> + +/** Value we fill a memory block with after it is free, in UE_BUILD_DEBUG **/ +# define DEBUG_FILL_FREED (0xdd) + +/** Value we fill a new memory block with, in UE_BUILD_DEBUG **/ +# define DEBUG_FILL_NEW (0xcd) + +# define ZEN_ENABLE_DEBUG_FILL 1 + +namespace zen { + +// Dramatically reduce memory zeroing and page faults during alloc intense workloads +// by keeping freed pages for a little while instead of releasing them +// right away to the OS, effectively acting like a scratch buffer +// until pages are both freed and inactive for the delay specified +// in milliseconds. +int32_t GMiMallocMemoryResetDelay = 10000; + +FMallocMimalloc::FMallocMimalloc() +{ + mi_option_set(mi_option_reset_delay, GMiMallocMemoryResetDelay); +} + +void* +FMallocMimalloc::TryMalloc(size_t Size, uint32_t Alignment) +{ + void* NewPtr = nullptr; + + if (Alignment != DEFAULT_ALIGNMENT) + { + Alignment = Max(uint32_t(Size >= 16 ? 16 : 8), Alignment); + NewPtr = mi_malloc_aligned(Size, Alignment); + } + else + { + NewPtr = mi_malloc_aligned(Size, uint32_t(Size >= 16 ? 16 : 8)); + } + +# if ZEN_BUILD_DEBUG && ZEN_ENABLE_DEBUG_FILL + if (Size && NewPtr != nullptr) + { + memset(NewPtr, DEBUG_FILL_NEW, mi_usable_size(NewPtr)); + } +# endif + + return NewPtr; +} + +void* +FMallocMimalloc::Malloc(size_t Size, uint32_t Alignment) +{ + void* Result = TryMalloc(Size, Alignment); + + if (Result == nullptr && Size) + { + OutOfMemory(Size, Alignment); + } + + return Result; +} + +void* +FMallocMimalloc::TryRealloc(void* Ptr, size_t NewSize, uint32_t Alignment) +{ +# if ZEN_BUILD_DEBUG && ZEN_ENABLE_DEBUG_FILL + size_t OldSize = 0; + if (Ptr) + { + OldSize = mi_malloc_size(Ptr); + if (NewSize < OldSize) + { + memset((uint8_t*)Ptr + NewSize, DEBUG_FILL_FREED, OldSize - NewSize); + } + } +# endif + void* NewPtr = nullptr; + + if (NewSize == 0) + { + mi_free(Ptr); + + return nullptr; + } + +# if ZEN_PLATFORM_MAC + // macOS expects all allocations to be aligned to 16 bytes, so on Mac we always have to use mi_realloc_aligned + Alignment = AlignArbitrary(Max((uint32_t)16, Alignment), (uint32_t)16); + NewPtr = mi_realloc_aligned(Ptr, NewSize, Alignment); +# else + if (Alignment != DEFAULT_ALIGNMENT) + { + Alignment = Max(NewSize >= 16 ? (uint32_t)16 : (uint32_t)8, Alignment); + NewPtr = mi_realloc_aligned(Ptr, NewSize, Alignment); + } + else + { + NewPtr = mi_realloc(Ptr, NewSize); + } +# endif + +# if ZEN_BUILD_DEBUG && ZEN_ENABLE_DEBUG_FILL + if (NewPtr && NewSize > OldSize) + { + memset((uint8_t*)NewPtr + OldSize, DEBUG_FILL_NEW, mi_usable_size(NewPtr) - OldSize); + } +# endif + + return NewPtr; +} + +void* +FMallocMimalloc::Realloc(void* Ptr, size_t NewSize, uint32_t Alignment) +{ + void* Result = TryRealloc(Ptr, NewSize, Alignment); + + if (Result == nullptr && NewSize) + { + OutOfMemory(NewSize, Alignment); + } + + return Result; +} + +void +FMallocMimalloc::Free(void* Ptr) +{ + if (!Ptr) + { + return; + } + +# if ZEN_BUILD_DEBUG && ZEN_ENABLE_DEBUG_FILL + memset(Ptr, DEBUG_FILL_FREED, mi_usable_size(Ptr)); +# endif + + mi_free(Ptr); +} + +void* +FMallocMimalloc::MallocZeroed(size_t Size, uint32_t Alignment) +{ + void* Result = TryMallocZeroed(Size, Alignment); + + if (Result == nullptr && Size) + { + OutOfMemory(Size, Alignment); + } + + return Result; +} + +void* +FMallocMimalloc::TryMallocZeroed(size_t Size, uint32_t Alignment) +{ + void* NewPtr = nullptr; + + if (Alignment != DEFAULT_ALIGNMENT) + { + Alignment = Max(uint32_t(Size >= 16 ? 16 : 8), Alignment); + NewPtr = mi_zalloc_aligned(Size, Alignment); + } + else + { + NewPtr = mi_zalloc_aligned(Size, uint32_t(Size >= 16 ? 16 : 8)); + } + + return NewPtr; +} + +bool +FMallocMimalloc::GetAllocationSize(void* Original, size_t& SizeOut) +{ + SizeOut = mi_malloc_size(Original); + return true; +} + +void +FMallocMimalloc::Trim(bool bTrimThreadCaches) +{ + mi_collect(bTrimThreadCaches); +} + +# undef DEBUG_FILL_FREED +# undef DEBUG_FILL_NEW + +} // namespace zen + +#endif // MIMALLOC_ENABLED |