[+] Aurora::Memory::HeapProxy[Ex]
[*] Heap improvements [+] Heap::NewClassArray
This commit is contained in:
parent
997d4a2eca
commit
c3e0418e1a
@ -9,10 +9,12 @@
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct ProxyHeap;
|
||||
|
||||
struct Heap
|
||||
{
|
||||
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;
|
||||
|
||||
template<typename T = void *>
|
||||
@ -59,51 +61,56 @@ namespace Aurora::Memory
|
||||
}
|
||||
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
void Free(T in)
|
||||
void Free(T pHead)
|
||||
{
|
||||
_Free(reinterpret_cast<void *>(in));
|
||||
_Free(reinterpret_cast<void *>(pHead));
|
||||
}
|
||||
|
||||
template <class T, class ...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)
|
||||
{
|
||||
new (pPtr) T(AuForward<Args &&>(args)...);
|
||||
new (pPtr + kAlignment) T(AuForward<Args &&>(args)...);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pPtr = this->ZAlloc<void *>(sizeof(T));
|
||||
pPtr = this->ZAlloc<AuUInt8 *>(sizeof(T) + kAlignment, kAlignment);
|
||||
}
|
||||
|
||||
if (!pPtr)
|
||||
@ -111,45 +118,155 @@ namespace Aurora::Memory
|
||||
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>
|
||||
AuSPtr<T> ToSmartPointer(T *in, bool bPinThis)
|
||||
static AuSPtr<T> ToSmartPointer(AuSPtr<Heap> heap,
|
||||
T *pHead,
|
||||
bool bPinHeap = true)
|
||||
{
|
||||
if (in == nullptr) return {};
|
||||
auto heapHandle = bPinThis ? GetSelfReference() : AuSPtr<Heap> {};
|
||||
return AuSPtr<T>(in,
|
||||
[heapHandle, in, this](T *delt)
|
||||
auto handle = bPinHeap ?
|
||||
heap :
|
||||
AuSPtr<Heap> {};
|
||||
auto pHeap = heap.get();
|
||||
return AuSPtr<T>(pHead,
|
||||
[handle, pHeap](T *pDeleteMe)
|
||||
{
|
||||
if constexpr (AuIsClass_v<T>)
|
||||
{
|
||||
delt->~T();
|
||||
}
|
||||
this->Free(delt);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static AuSPtr<T> ToSmartPointer(AuSPtr<Heap> heap, T *in, bool pinHeap = true)
|
||||
{
|
||||
auto handle = pinHeap ? heap : AuSPtr<Heap> {};
|
||||
auto ptr = heap.get();
|
||||
return AuSPtr<T>(in,
|
||||
[handle, ptr](T *delt)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
ptr->Free(delt);
|
||||
pHeap->Free(pDeleteMe);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
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>
|
||||
static void DeleteThatArray(T *pThat)
|
||||
{
|
||||
static const auto kAlignment = AuMax(alignof(T), sizeof(void *) * 2);
|
||||
|
||||
auto pVoids = (void **)(((char *)pThat) - kAlignment);
|
||||
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
|
||||
)
|
||||
{
|
||||
for (AU_ITERATE_N(i, uCount))
|
||||
{
|
||||
auto &refElement = pThat[i];
|
||||
refElement.~T();
|
||||
}
|
||||
}
|
||||
|
||||
pHeap->_Free(pVoids);
|
||||
}
|
||||
|
||||
friend struct ProxyHeap;
|
||||
|
||||
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, Types::size_t align) = 0;
|
||||
@ -171,7 +288,7 @@ namespace Aurora::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.
|
||||
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.
|
||||
|
||||
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
|
||||
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>
|
||||
|
||||
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 "HeapStats.hpp"
|
||||
#include "Heap.hpp"
|
||||
@ -21,10 +28,6 @@
|
||||
|
||||
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,
|
||||
LeakFinderFree_f pFree);
|
||||
|
||||
|
@ -75,6 +75,11 @@ namespace Aurora::Memory
|
||||
return {};
|
||||
}
|
||||
|
||||
Heap *GetSelfReferenceRaw() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void UpdateStats() override
|
||||
{
|
||||
auto other = AuDebug::gReserveHeap->GetStats();
|
||||
|
@ -20,8 +20,7 @@ namespace Aurora::Memory
|
||||
{
|
||||
static AuUInt32 RoundPageUp(AuUInt32 value)
|
||||
{
|
||||
auto pageMask = HWInfo::GetPageSize() - 1;
|
||||
return (value + pageMask) & ~(pageMask);
|
||||
return AuPageRoundUp(value, HWInfo::GetPageSize());
|
||||
}
|
||||
|
||||
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 _Free(void *buffer) override;
|
||||
AuSPtr<Heap> GetSelfReference() override;
|
||||
Heap *GetSelfReferenceRaw() override;
|
||||
|
||||
void TryRelease();
|
||||
void DecrementUsers();
|
||||
@ -147,24 +147,35 @@ namespace Aurora::Memory
|
||||
bool InternalHeap::Init(AuUInt length, void *ptr)
|
||||
{
|
||||
SysAssert(!this->base_, "heap already initialized");
|
||||
|
||||
SysAssert(length, "invalid heap allocation");
|
||||
this->length_ = length;
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
this->base_ = ptr;
|
||||
this->length_ = length;
|
||||
this->ownsMemory_ = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->base_ = HeapLargeAllocate(length);
|
||||
if (!base_) return false;
|
||||
if (length <= 4096)
|
||||
{
|
||||
length = 4086;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -218,7 +229,7 @@ namespace Aurora::Memory
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -241,7 +252,7 @@ namespace Aurora::Memory
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -261,7 +272,7 @@ namespace Aurora::Memory
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -281,7 +292,7 @@ namespace Aurora::Memory
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -357,6 +368,11 @@ namespace Aurora::Memory
|
||||
}
|
||||
}
|
||||
|
||||
Heap *InternalHeap::GetSelfReferenceRaw()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
AUKN_SYM Heap *AllocHeapNew(AuUInt size)
|
||||
{
|
||||
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