[+] Aurora::Memory::HeapProxy[Ex]
[*] Heap improvements [+] Heap::NewClassArray
This commit is contained in:
parent
997d4a2eca
commit
c3e0418e1a
@ -9,10 +9,12 @@
|
|||||||
|
|
||||||
namespace Aurora::Memory
|
namespace Aurora::Memory
|
||||||
{
|
{
|
||||||
|
struct ProxyHeap;
|
||||||
|
|
||||||
struct Heap
|
struct Heap
|
||||||
{
|
{
|
||||||
virtual AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment = 32) = 0;
|
virtual AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment = 32) = 0;
|
||||||
virtual Types::size_t GetChunkSize(const void *head) = 0;
|
virtual Types::size_t GetChunkSize(const void *pHead) = 0;
|
||||||
virtual HeapStats &GetStats() = 0;
|
virtual HeapStats &GetStats() = 0;
|
||||||
|
|
||||||
template<typename T = void *>
|
template<typename T = void *>
|
||||||
@ -59,51 +61,56 @@ namespace Aurora::Memory
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T ZRealloc(T in, Types::size_t length)
|
T ZRealloc(T pHead, Types::size_t length)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), length));
|
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(pHead), length));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T ZRealloc(T in, Types::size_t length, Types::size_t alloc)
|
T ZRealloc(T pHead, Types::size_t length, Types::size_t alloc)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), length), alloc);
|
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(pHead), length), alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T FRealloc(T in, Types::size_t length)
|
T FRealloc(T pHead, Types::size_t length)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), length));
|
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(pHead), length));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T FRealloc(T in, Types::size_t length, Types::size_t alloc)
|
T FRealloc(T pHead, Types::size_t length, Types::size_t alloc)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), length), alloc);
|
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(pHead), length), alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Free(T in)
|
void Free(T pHead)
|
||||||
{
|
{
|
||||||
_Free(reinterpret_cast<void *>(in));
|
_Free(reinterpret_cast<void *>(pHead));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class ...Args>
|
template <class T, class ...Args>
|
||||||
AuSPtr<T> NewClass(Args &&...args)
|
AuSPtr<T> NewClass(Args &&...args)
|
||||||
{
|
{
|
||||||
void *pPtr;
|
static const auto kAlignment = AuMax(alignof(T), sizeof(void *));
|
||||||
|
AuUInt8 *pPtr;
|
||||||
|
|
||||||
if constexpr (AuIsClass_v<T>)
|
if constexpr (AuIsClass_v<T>
|
||||||
|
#if !defined(AURT_HEAP_NO_STL)
|
||||||
|
&& !std::is_trivially_constructible_v<T>
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
pPtr = this->FAlloc<void *>(sizeof(T));
|
pPtr = this->FAlloc<AuUInt8 *>(sizeof(T) + kAlignment, kAlignment);
|
||||||
if (pPtr)
|
if (pPtr)
|
||||||
{
|
{
|
||||||
new (pPtr) T(AuForward<Args &&>(args)...);
|
new (pPtr + kAlignment) T(AuForward<Args &&>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pPtr = this->ZAlloc<void *>(sizeof(T));
|
pPtr = this->ZAlloc<AuUInt8 *>(sizeof(T) + kAlignment, kAlignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pPtr)
|
if (!pPtr)
|
||||||
@ -111,45 +118,155 @@ namespace Aurora::Memory
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return ToSmartPointer((T *)pPtr, true);
|
auto pThat = this->GetSelfReferenceRaw();
|
||||||
|
if (pThat &&
|
||||||
|
pThat != this)
|
||||||
|
{
|
||||||
|
*(void **)pPtr = pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(void **)pPtr = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuSPtr<T>((T *)(pPtr + kAlignment), &Heap::DeleteThat<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class ...Args>
|
||||||
|
AuSPtr<T> NewClassArray(AuUInt uElements, Args &&... fillCtr)
|
||||||
|
{
|
||||||
|
static const auto kAlignment = AuMax(alignof(T), sizeof(void *) * 2);
|
||||||
|
AuUInt8 *pPtr;
|
||||||
|
|
||||||
|
if (!uElements)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (AuIsClass_v<T>
|
||||||
|
#if !defined(AURT_HEAP_NO_STL)
|
||||||
|
&& !std::is_trivially_constructible_v<T>
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (bool(pPtr = this->FAlloc<AuUInt8 *>((sizeof(T) * uElements) + kAlignment, kAlignment)))
|
||||||
|
{
|
||||||
|
for (AU_ITERATE_N(i, uElements))
|
||||||
|
{
|
||||||
|
new (pPtr + kAlignment + (sizeof(T) * i)) T(AuForward<Args &&>(fillCtr)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (bool(pPtr = this->ZAlloc<AuUInt8 *>((sizeof(T) * uElements) + kAlignment, kAlignment)))
|
||||||
|
{
|
||||||
|
if constexpr (sizeof...(Args) != 0)
|
||||||
|
{
|
||||||
|
#if defined(AURT_HEAP_NO_STL)
|
||||||
|
static_assert(false);
|
||||||
|
#else
|
||||||
|
auto pElements = (T *)(pPtr + kAlignment);
|
||||||
|
std::fill(pElements, pElements + uElements, AuForward<Args &&>(fillCtr)...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pPtr)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pVoids = (void **)pPtr;
|
||||||
|
auto pThat = this->GetSelfReferenceRaw();
|
||||||
|
if (pThat &&
|
||||||
|
pThat != this)
|
||||||
|
{
|
||||||
|
pVoids[0] = pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pVoids[0] = this;
|
||||||
|
}
|
||||||
|
pVoids[1] = (void *)uElements;
|
||||||
|
|
||||||
|
return AuSPtr<T>((T *)(pPtr + kAlignment), &Heap::DeleteThatArray<T>);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
AuSPtr<T> ToSmartPointer(T *in, bool bPinThis)
|
static AuSPtr<T> ToSmartPointer(AuSPtr<Heap> heap,
|
||||||
|
T *pHead,
|
||||||
|
bool bPinHeap = true)
|
||||||
{
|
{
|
||||||
if (in == nullptr) return {};
|
auto handle = bPinHeap ?
|
||||||
auto heapHandle = bPinThis ? GetSelfReference() : AuSPtr<Heap> {};
|
heap :
|
||||||
return AuSPtr<T>(in,
|
AuSPtr<Heap> {};
|
||||||
[heapHandle, in, this](T *delt)
|
auto pHeap = heap.get();
|
||||||
|
return AuSPtr<T>(pHead,
|
||||||
|
[handle, pHeap](T *pDeleteMe)
|
||||||
{
|
{
|
||||||
if constexpr (AuIsClass_v<T>)
|
if constexpr (AuIsClass_v<T>
|
||||||
|
#if !defined(AURT_HEAP_NO_STL)
|
||||||
|
&& !std::is_trivially_destructible_v<T>
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
delt->~T();
|
pDeleteMe->~T();
|
||||||
}
|
}
|
||||||
this->Free(delt);
|
|
||||||
|
pHeap->Free(pDeleteMe);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename T>
|
||||||
|
static void DeleteThat(T *pThat)
|
||||||
|
{
|
||||||
|
static const auto kAlignment = AuMax(alignof(T), sizeof(void *));
|
||||||
|
|
||||||
|
if constexpr (AuIsClass_v<T>
|
||||||
|
#if !defined(AURT_HEAP_NO_STL)
|
||||||
|
&& !std::is_trivially_destructible_v<T>
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
pThat->~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &pHeap = *(Heap **)(((char *)pThat) - kAlignment);
|
||||||
|
pHeap->_Free(&pHeap);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static AuSPtr<T> ToSmartPointer(AuSPtr<Heap> heap, T *in, bool pinHeap = true)
|
static void DeleteThatArray(T *pThat)
|
||||||
{
|
{
|
||||||
auto handle = pinHeap ? heap : AuSPtr<Heap> {};
|
static const auto kAlignment = AuMax(alignof(T), sizeof(void *) * 2);
|
||||||
auto ptr = heap.get();
|
|
||||||
return AuSPtr<T>(in,
|
auto pVoids = (void **)(((char *)pThat) - kAlignment);
|
||||||
[handle, ptr](T *delt)
|
auto pHeap = (Heap *)pVoids[0];
|
||||||
|
auto uCount = (AuUInt)pVoids[1];
|
||||||
|
|
||||||
|
if constexpr (AuIsClass_v<T>
|
||||||
|
#if !defined(AURT_HEAP_NO_STL)
|
||||||
|
&& !std::is_trivially_destructible_v<T>
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if constexpr (AuIsClass_v<T>)
|
for (AU_ITERATE_N(i, uCount))
|
||||||
{
|
{
|
||||||
delt->~T();
|
auto &refElement = pThat[i];
|
||||||
|
refElement.~T();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr->Free(delt);
|
pHeap->_Free(pVoids);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
friend struct ProxyHeap;
|
||||||
|
|
||||||
virtual AuSPtr<Heap> GetSelfReference() = 0; // may return empty/default. not all heaps are sharable.
|
virtual AuSPtr<Heap> GetSelfReference() = 0; // may return empty/default. not all heaps are sharable.
|
||||||
|
virtual Heap *GetSelfReferenceRaw() = 0;
|
||||||
|
|
||||||
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength) = 0;
|
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength) = 0;
|
||||||
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength, Types::size_t align) = 0;
|
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength, Types::size_t align) = 0;
|
||||||
@ -171,7 +288,7 @@ namespace Aurora::Memory
|
|||||||
Allocates uLength amount of contiguous virtual memory
|
Allocates uLength amount of contiguous virtual memory
|
||||||
|
|
||||||
@warning Heaps are guaranteed to outlive their allocations; heaps are the one object that effectively own a single reference count on themselves.
|
@warning Heaps are guaranteed to outlive their allocations; heaps are the one object that effectively own a single reference count on themselves.
|
||||||
Requesting termination before all of its' memory has been free will result, in at worst, a warning.
|
Requesting termination before all of its' memory has been free will result, pHead at worst, a warning.
|
||||||
Expect to leak unless all allocs have been paired by a free.
|
Expect to leak unless all allocs have been paired by a free.
|
||||||
|
|
||||||
I do not expect to implement force frees simply because all our primary use cases keep track of dtors to forcefully release leaked objects.
|
I do not expect to implement force frees simply because all our primary use cases keep track of dtors to forcefully release leaked objects.
|
||||||
@ -185,4 +302,10 @@ namespace Aurora::Memory
|
|||||||
|
|
||||||
// AllocHeap but use mimalloc (or the default allocator) instead
|
// AllocHeap but use mimalloc (or the default allocator) instead
|
||||||
AUKN_SHARED_API(AllocHeapMimalloc, Heap, AuUInt uLength);
|
AUKN_SHARED_API(AllocHeapMimalloc, Heap, AuUInt uLength);
|
||||||
|
|
||||||
|
// Proxies an existing heap with encapsulated statistics
|
||||||
|
AUKN_SHARED_API(HeapProxy, Heap, const AuSPtr<Heap> &pHead);
|
||||||
|
|
||||||
|
// Proxies an existing heap with encapsulated statistics and leak detector
|
||||||
|
AUKN_SHARED_API(HeapProxyEx, Heap, const AuSPtr<Heap> &pHead, LeakFinderAlloc_f pfAlloc, LeakFinderFree_f pfFree);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,13 @@
|
|||||||
|
|
||||||
#include <Aurora/Data/Data.hpp>
|
#include <Aurora/Data/Data.hpp>
|
||||||
|
|
||||||
|
namespace Aurora::Memory
|
||||||
|
{
|
||||||
|
using LeakFinderAlloc_f = void(__cdecl *)(void *, AuUInt);
|
||||||
|
using LeakFinderFree_f = void(__cdecl *)(void *);
|
||||||
|
using MemoryLowNotification_f = void(__cdecl *)(AuUInt, int);
|
||||||
|
}
|
||||||
|
|
||||||
#include "MemRef.hpp"
|
#include "MemRef.hpp"
|
||||||
#include "HeapStats.hpp"
|
#include "HeapStats.hpp"
|
||||||
#include "Heap.hpp"
|
#include "Heap.hpp"
|
||||||
@ -21,10 +28,6 @@
|
|||||||
|
|
||||||
namespace Aurora::Memory
|
namespace Aurora::Memory
|
||||||
{
|
{
|
||||||
using LeakFinderAlloc_f = void(__cdecl *)(void *, AuUInt);
|
|
||||||
using LeakFinderFree_f = void(__cdecl *)(void *);
|
|
||||||
using MemoryLowNotification_f = void(__cdecl *)(AuUInt, int);
|
|
||||||
|
|
||||||
AUKN_SYM void SetLeakFinder(LeakFinderAlloc_f pAlloc,
|
AUKN_SYM void SetLeakFinder(LeakFinderAlloc_f pAlloc,
|
||||||
LeakFinderFree_f pFree);
|
LeakFinderFree_f pFree);
|
||||||
|
|
||||||
|
@ -75,6 +75,11 @@ namespace Aurora::Memory
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Heap *GetSelfReferenceRaw() override
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateStats() override
|
void UpdateStats() override
|
||||||
{
|
{
|
||||||
auto other = AuDebug::gReserveHeap->GetStats();
|
auto other = AuDebug::gReserveHeap->GetStats();
|
||||||
|
@ -20,8 +20,7 @@ namespace Aurora::Memory
|
|||||||
{
|
{
|
||||||
static AuUInt32 RoundPageUp(AuUInt32 value)
|
static AuUInt32 RoundPageUp(AuUInt32 value)
|
||||||
{
|
{
|
||||||
auto pageMask = HWInfo::GetPageSize() - 1;
|
return AuPageRoundUp(value, HWInfo::GetPageSize());
|
||||||
return (value + pageMask) & ~(pageMask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *HeapLargeAllocate(AuUInt length)
|
static void *HeapLargeAllocate(AuUInt length)
|
||||||
@ -90,6 +89,7 @@ namespace Aurora::Memory
|
|||||||
void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align) override;
|
void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align) override;
|
||||||
void _Free(void *buffer) override;
|
void _Free(void *buffer) override;
|
||||||
AuSPtr<Heap> GetSelfReference() override;
|
AuSPtr<Heap> GetSelfReference() override;
|
||||||
|
Heap *GetSelfReferenceRaw() override;
|
||||||
|
|
||||||
void TryRelease();
|
void TryRelease();
|
||||||
void DecrementUsers();
|
void DecrementUsers();
|
||||||
@ -147,24 +147,35 @@ namespace Aurora::Memory
|
|||||||
bool InternalHeap::Init(AuUInt length, void *ptr)
|
bool InternalHeap::Init(AuUInt length, void *ptr)
|
||||||
{
|
{
|
||||||
SysAssert(!this->base_, "heap already initialized");
|
SysAssert(!this->base_, "heap already initialized");
|
||||||
|
|
||||||
SysAssert(length, "invalid heap allocation");
|
SysAssert(length, "invalid heap allocation");
|
||||||
this->length_ = length;
|
|
||||||
|
|
||||||
if (ptr)
|
if (ptr)
|
||||||
{
|
{
|
||||||
this->base_ = ptr;
|
this->base_ = ptr;
|
||||||
|
this->length_ = length;
|
||||||
this->ownsMemory_ = false;
|
this->ownsMemory_ = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->base_ = HeapLargeAllocate(length);
|
if (length <= 4096)
|
||||||
if (!base_) return false;
|
{
|
||||||
|
length = 4086;
|
||||||
this->ownsMemory_ = true;
|
}
|
||||||
|
|
||||||
|
if (!(this->base_ = HeapLargeAllocate(length)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->ownsMemory_ = true;
|
||||||
|
this->length_ = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(this->heap_ = o1heapInit(this->base_, length)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->heap_ = o1heapInit(this->base_, length);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +229,7 @@ namespace Aurora::Memory
|
|||||||
|
|
||||||
void *InternalHeap::_FAlloc(Types::size_t length, Types::size_t align)
|
void *InternalHeap::_FAlloc(Types::size_t length, Types::size_t align)
|
||||||
{
|
{
|
||||||
SysAssert(align < O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
SysAssert(align <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
||||||
return this->_FAlloc(length);
|
return this->_FAlloc(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +252,7 @@ namespace Aurora::Memory
|
|||||||
|
|
||||||
void *InternalHeap::_ZAlloc(Types::size_t length, Types::size_t align)
|
void *InternalHeap::_ZAlloc(Types::size_t length, Types::size_t align)
|
||||||
{
|
{
|
||||||
SysAssert(align < O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
SysAssert(align <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
||||||
return _ZAlloc(length);
|
return _ZAlloc(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +272,7 @@ namespace Aurora::Memory
|
|||||||
|
|
||||||
void *InternalHeap::_ZRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
void *InternalHeap::_ZRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||||
{
|
{
|
||||||
SysAssert(align < O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
SysAssert(align <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
||||||
return this->_ZRealloc(buffer, length);
|
return this->_ZRealloc(buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +292,7 @@ namespace Aurora::Memory
|
|||||||
|
|
||||||
void *InternalHeap::_FRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
void *InternalHeap::_FRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||||
{
|
{
|
||||||
SysAssert(align < O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
SysAssert(align <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
||||||
return this->_FRealloc(buffer, length);
|
return this->_FRealloc(buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,6 +368,11 @@ namespace Aurora::Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Heap *InternalHeap::GetSelfReferenceRaw()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
AUKN_SYM Heap *AllocHeapNew(AuUInt size)
|
AUKN_SYM Heap *AllocHeapNew(AuUInt size)
|
||||||
{
|
{
|
||||||
auto heap = _new InternalHeap();
|
auto heap = _new InternalHeap();
|
||||||
|
323
Source/Memory/HeapProxy.cpp
Normal file
323
Source/Memory/HeapProxy.cpp
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: HeapProxy.cpp
|
||||||
|
Date: 2024-1-16
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#include <Source/RuntimeInternal.hpp>
|
||||||
|
#include "Memory.hpp"
|
||||||
|
#include "Heap.hpp"
|
||||||
|
#include "HeapProxy.hpp"
|
||||||
|
|
||||||
|
namespace Aurora::Memory
|
||||||
|
{
|
||||||
|
ProxyHeap::ProxyHeap(std::shared_ptr<Heap> pHeap,
|
||||||
|
LeakFinderAlloc_f pAlloc,
|
||||||
|
LeakFinderFree_f pFree) :
|
||||||
|
pHeap(pHeap),
|
||||||
|
pAlloc(pAlloc),
|
||||||
|
pFree(pFree)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyHeap::UpdateStats()
|
||||||
|
{
|
||||||
|
auto &stats = this->pHeap->GetStats();
|
||||||
|
|
||||||
|
this->stats.uBytesLiveCounter = this->uBytesAllocated;
|
||||||
|
this->stats.qwBytesAllocatedLifetime = this->uBytesLifetime;
|
||||||
|
this->stats.uBytesPeakCounter = this->uBytesPeak;
|
||||||
|
this->stats.qwBytesFreeLifetime = this->uBytesFree;
|
||||||
|
this->stats.uBytesCapacity = stats.uBytesCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuSPtr<Heap> ProxyHeap::AllocateDivision(AuUInt32 heap, AuUInt32 alignment)
|
||||||
|
{
|
||||||
|
return this->pHeap->AllocateDivision(heap, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ProxyHeap::_ZAlloc(Types::size_t uLength)
|
||||||
|
{
|
||||||
|
if (auto pThat = this->pHeap->ZAlloc(uLength))
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pThat);
|
||||||
|
AuAtomicAdd(&this->uBytesLifetime, uLengthCurrent);
|
||||||
|
AuAtomicAdd(&this->uBytesAllocated, uLengthCurrent);
|
||||||
|
this->uBytesPeak = AuMax(this->uBytesPeak, this->uBytesAllocated);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pAlloc(pThat, uLength);
|
||||||
|
}
|
||||||
|
return pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ProxyHeap::_ZAlloc(Types::size_t uLength, Types::size_t align)
|
||||||
|
{
|
||||||
|
if (auto pThat = this->pHeap->ZAlloc(uLength, align))
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pThat);
|
||||||
|
AuAtomicAdd(&this->uBytesLifetime, uLengthCurrent);
|
||||||
|
AuAtomicAdd(&this->uBytesAllocated, uLengthCurrent);
|
||||||
|
this->uBytesPeak = AuMax(this->uBytesPeak, this->uBytesAllocated);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pAlloc(pThat, uLength);
|
||||||
|
}
|
||||||
|
return pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::size_t ProxyHeap::GetChunkSize(const void *head)
|
||||||
|
{
|
||||||
|
return this->pHeap->GetChunkSize(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ProxyHeap::_FAlloc(Types::size_t uLength)
|
||||||
|
{
|
||||||
|
if (auto pThat = this->pHeap->_FAlloc(uLength))
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pThat);
|
||||||
|
AuAtomicAdd(&this->uBytesLifetime, uLengthCurrent);
|
||||||
|
AuAtomicAdd(&this->uBytesAllocated, uLengthCurrent);
|
||||||
|
this->uBytesPeak = AuMax(this->uBytesPeak, this->uBytesAllocated);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pAlloc(pThat, uLength);
|
||||||
|
}
|
||||||
|
return pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ProxyHeap::_FAlloc(Types::size_t uLength, Types::size_t align)
|
||||||
|
{
|
||||||
|
if (auto pThat = this->pHeap->_FAlloc(uLength, align))
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pThat);
|
||||||
|
AuAtomicAdd(&this->uBytesLifetime, uLengthCurrent);
|
||||||
|
AuAtomicAdd(&this->uBytesAllocated, uLengthCurrent);
|
||||||
|
this->uBytesPeak = AuMax(this->uBytesPeak, this->uBytesAllocated);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pAlloc(pThat, uLength);
|
||||||
|
}
|
||||||
|
return pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ProxyHeap::_ZRealloc(void *pHead, Types::size_t uLength, Types::size_t align)
|
||||||
|
{
|
||||||
|
if (pHead)
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pHead);
|
||||||
|
|
||||||
|
if (auto pThat = this->pHeap->_ZRealloc(pHead, uLength, align))
|
||||||
|
{
|
||||||
|
auto uLengthNext = this->GetChunkSize(pThat);
|
||||||
|
AuAtomicAdd(&this->uBytesFree, uLengthCurrent);
|
||||||
|
AuAtomicAdd(&this->uBytesLifetime, uLengthNext);
|
||||||
|
AuAtomicAdd(&this->uBytesAllocated, decltype(this->uBytesAllocated)(uLengthNext) - decltype(this->uBytesAllocated)(uLengthCurrent));
|
||||||
|
this->uBytesPeak = AuMax(this->uBytesPeak, this->uBytesAllocated);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pFree(pHead);
|
||||||
|
this->pAlloc(pThat, uLength);
|
||||||
|
}
|
||||||
|
return pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ProxyHeap::_ZRealloc(void *pHead, Types::size_t uLength)
|
||||||
|
{
|
||||||
|
if (pHead)
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pHead);
|
||||||
|
|
||||||
|
if (auto pThat = this->pHeap->_ZRealloc(pHead, uLength))
|
||||||
|
{
|
||||||
|
auto uLengthNext = this->GetChunkSize(pThat);
|
||||||
|
AuAtomicAdd(&this->uBytesFree, uLengthCurrent);
|
||||||
|
AuAtomicAdd(&this->uBytesLifetime, uLengthNext);
|
||||||
|
AuAtomicAdd(&this->uBytesAllocated, decltype(this->uBytesAllocated)(uLengthNext) - decltype(this->uBytesAllocated)(uLengthCurrent));
|
||||||
|
this->uBytesPeak = AuMax(this->uBytesPeak, this->uBytesAllocated);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pFree(pHead);
|
||||||
|
this->pAlloc(pThat, uLength);
|
||||||
|
}
|
||||||
|
return pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ProxyHeap::_FRealloc(void *pHead, Types::size_t uLength, Types::size_t align)
|
||||||
|
{
|
||||||
|
if (pHead)
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pHead);
|
||||||
|
|
||||||
|
if (auto pThat = this->pHeap->_FRealloc(pHead, uLength, align))
|
||||||
|
{
|
||||||
|
auto uLengthNext = this->GetChunkSize(pThat);
|
||||||
|
AuAtomicAdd(&this->uBytesFree, uLengthCurrent);
|
||||||
|
AuAtomicAdd(&this->uBytesLifetime, uLengthNext);
|
||||||
|
AuAtomicAdd(&this->uBytesAllocated, decltype(this->uBytesAllocated)(uLengthNext) - decltype(this->uBytesAllocated)(uLengthCurrent));
|
||||||
|
this->uBytesPeak = AuMax(this->uBytesPeak, this->uBytesAllocated);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pFree(pHead);
|
||||||
|
this->pAlloc(pThat, uLength);
|
||||||
|
}
|
||||||
|
return pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ProxyHeap::_FRealloc(void *pHead, Types::size_t uLength)
|
||||||
|
{
|
||||||
|
if (pHead)
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pHead);
|
||||||
|
|
||||||
|
if (auto pThat = this->pHeap->_FRealloc(pHead, uLength))
|
||||||
|
{
|
||||||
|
auto uLengthNext = this->GetChunkSize(pThat);
|
||||||
|
AuAtomicAdd(&this->uBytesFree, uLengthCurrent);
|
||||||
|
AuAtomicAdd(&this->uBytesLifetime, uLengthNext);
|
||||||
|
AuAtomicAdd(&this->uBytesAllocated, decltype(this->uBytesAllocated)(uLengthNext) - decltype(this->uBytesAllocated)(uLengthCurrent));
|
||||||
|
this->uBytesPeak = AuMax(this->uBytesPeak, this->uBytesAllocated);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pFree(pHead);
|
||||||
|
this->pAlloc(pThat, uLength);
|
||||||
|
}
|
||||||
|
return pThat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyHeap::_Free(void *pHead)
|
||||||
|
{
|
||||||
|
if (pHead)
|
||||||
|
{
|
||||||
|
auto uLengthCurrent = this->GetChunkSize(pHead);
|
||||||
|
AuAtomicAdd(&this->uBytesFree, uLengthCurrent);
|
||||||
|
AuAtomicSub(&this->uBytesAllocated, uLengthCurrent);
|
||||||
|
if (this->pAlloc)
|
||||||
|
{
|
||||||
|
this->pFree(pHead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AuSPtr<Heap> ProxyHeap::GetSelfReference()
|
||||||
|
{
|
||||||
|
return this->pHeap;
|
||||||
|
}
|
||||||
|
|
||||||
|
Heap *ProxyHeap::GetSelfReferenceRaw()
|
||||||
|
{
|
||||||
|
return this->pHeap.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM Heap *HeapProxyNew(const AuSPtr<Heap> &pHeap)
|
||||||
|
{
|
||||||
|
if (!pHeap)
|
||||||
|
{
|
||||||
|
SysPushErrorArg();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pRetHeap = _new ProxyHeap(pHeap);
|
||||||
|
if (!pRetHeap)
|
||||||
|
{
|
||||||
|
SysPushErrorMemory();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pRetHeap;
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM void HeapProxyRelease(Heap *heap)
|
||||||
|
{
|
||||||
|
AuSafeDelete<ProxyHeap *>(heap);
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM Heap *HeapProxyExNew(const AuSPtr<Heap> &pHeap,
|
||||||
|
LeakFinderAlloc_f pAlloc,
|
||||||
|
LeakFinderFree_f pFree)
|
||||||
|
{
|
||||||
|
if (!pHeap ||
|
||||||
|
!pAlloc ||
|
||||||
|
!pFree)
|
||||||
|
{
|
||||||
|
SysPushErrorArg();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pRetHeap = _new ProxyHeap(pHeap, pAlloc, pFree);
|
||||||
|
if (!pRetHeap)
|
||||||
|
{
|
||||||
|
SysPushErrorMemory();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pRetHeap;
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM void HeapProxyExRelease(Heap *heap)
|
||||||
|
{
|
||||||
|
AuSafeDelete<ProxyHeap *>(heap);
|
||||||
|
}
|
||||||
|
}
|
41
Source/Memory/HeapProxy.hpp
Normal file
41
Source/Memory/HeapProxy.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: HeapProxy.hpp
|
||||||
|
Date: 2024-1-16
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
|
||||||
|
namespace Aurora::Memory
|
||||||
|
{
|
||||||
|
struct ProxyHeap : BaseHeap
|
||||||
|
{
|
||||||
|
std::shared_ptr<Heap> pHeap;
|
||||||
|
LeakFinderAlloc_f pAlloc;
|
||||||
|
LeakFinderFree_f pFree;
|
||||||
|
AuUInt64 uBytesAllocated {}; // current
|
||||||
|
AuUInt64 uBytesPeak {}; // max
|
||||||
|
AuUInt64 uBytesFree {}; // free count
|
||||||
|
AuUInt64 uBytesLifetime {}; // alloc count
|
||||||
|
|
||||||
|
ProxyHeap(std::shared_ptr<Heap> pHeap,
|
||||||
|
LeakFinderAlloc_f pAlloc = {},
|
||||||
|
LeakFinderFree_f pFree = {});
|
||||||
|
|
||||||
|
void UpdateStats() override;
|
||||||
|
|
||||||
|
AuSPtr<Heap> GetSelfReference() override;
|
||||||
|
Heap *GetSelfReferenceRaw() override;
|
||||||
|
AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment) override;
|
||||||
|
void *_ZAlloc(Types::size_t length) override;
|
||||||
|
void *_ZAlloc(Types::size_t length, Types::size_t align) override;
|
||||||
|
Types::size_t GetChunkSize(const void *head) override;
|
||||||
|
void *_FAlloc(Types::size_t length) override;
|
||||||
|
void *_FAlloc(Types::size_t length, Types::size_t align) override;
|
||||||
|
void *_ZRealloc(void *buffer, Types::size_t length, Types::size_t align) override;
|
||||||
|
void *_ZRealloc(void *buffer, Types::size_t length) override;
|
||||||
|
void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align) override;
|
||||||
|
void *_FRealloc(void *buffer, Types::size_t length) override;
|
||||||
|
void _Free(void *buffer) override;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user