Apply formating to all files. CLeanup
This commit is contained in:
parent
43e374f269
commit
744c01c5d0
928 changed files with 14515 additions and 21480 deletions
|
|
@ -3,25 +3,22 @@
|
|||
|
||||
#include <cstdlib>
|
||||
|
||||
static void deinit(const tp::ModuleManifest* self) {
|
||||
tp::HeapAllocGlobal::checkLeaks();
|
||||
}
|
||||
static void deinit(const tp::ModuleManifest* self) { tp::HeapAllocGlobal::checkLeaks(); }
|
||||
|
||||
static tp::ModuleManifest* sModuleDependencies[] = { &tp::gModuleUtils, nullptr };
|
||||
tp::ModuleManifest tp::gModuleAllocators = ModuleManifest("Allocators", nullptr, deinit, sModuleDependencies);
|
||||
|
||||
|
||||
void* operator new(size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
|
||||
void* operator new[](size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
|
||||
void operator delete(void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
|
||||
void operator delete[](void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
|
||||
void operator delete(void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
|
||||
void operator delete[](void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
|
||||
|
||||
void* operator new(size_t aSize, tp::HeapAlloc& aAlloc) { return aAlloc.allocate(aSize); }
|
||||
void* operator new[](size_t aSize, tp::HeapAlloc& aAlloc) { return aAlloc.allocate(aSize); }
|
||||
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
|
||||
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
|
||||
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
|
||||
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
|
||||
|
||||
void* operator new(size_t aSize, tp::HeapAllocGlobal& aAlloc) { return tp::HeapAllocGlobal::allocate(aSize); }
|
||||
void* operator new[](size_t aSize, tp::HeapAllocGlobal& aAlloc) { return tp::HeapAllocGlobal::allocate(aSize); }
|
||||
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }
|
||||
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }
|
||||
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }
|
||||
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }
|
||||
|
|
@ -1,70 +1,69 @@
|
|||
|
||||
|
||||
#include "HeapAllocator.hpp"
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
|
||||
#include "PrivateConfig.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
#if not defined(MEM_DEBUG)
|
||||
|
||||
// ----------------------- Release Implementation ---------------------------- //
|
||||
void* HeapAlloc::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
|
||||
void HeapAlloc::deallocate(void* aPtr) { free(aPtr); }
|
||||
HeapAlloc::~HeapAlloc() {}
|
||||
|
||||
#else
|
||||
|
||||
namespace tp {
|
||||
struct MemHeadLocal {
|
||||
MemHeadLocal* mPrev;
|
||||
MemHeadLocal* mNext;
|
||||
};
|
||||
}
|
||||
|
||||
void* HeapAlloc::allocate(ualni aBlockSize) {
|
||||
auto head = (MemHeadLocal*) HeapAllocGlobal::allocate(aBlockSize + sizeof(MemHeadLocal));
|
||||
auto out = head + 1;
|
||||
|
||||
mNumAllocations++;
|
||||
if (mEntry) {
|
||||
DEBUG_ASSERT(!mEntry->mNext)
|
||||
head->mNext = nullptr;
|
||||
head->mPrev = mEntry;
|
||||
mEntry->mNext = head;
|
||||
} else {
|
||||
head->mNext = nullptr;
|
||||
head->mPrev = nullptr;
|
||||
}
|
||||
mEntry = head;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void HeapAlloc::deallocate(void* aPtr) {
|
||||
auto head = ((MemHeadLocal*)(aPtr)) - 1;
|
||||
|
||||
mNumAllocations--;
|
||||
DEBUG_ASSERT(!mEntry->mNext)
|
||||
if (head->mNext) head->mNext->mPrev = head->mPrev;
|
||||
if (head->mPrev) head->mPrev->mNext = head->mNext;
|
||||
if (head == mEntry) {
|
||||
mEntry = head->mPrev;
|
||||
}
|
||||
|
||||
HeapAllocGlobal::deallocate(head);
|
||||
}
|
||||
|
||||
HeapAlloc::~HeapAlloc() {
|
||||
if (mNumAllocations) {
|
||||
DEBUG_BREAK("Destruction of not freed Allocator")
|
||||
|
||||
#ifdef MEM_STACK_TRACE
|
||||
// TODO : log leaks and free them up
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "HeapAllocator.hpp"
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
|
||||
#include "PrivateConfig.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
#if not defined(MEM_DEBUG)
|
||||
|
||||
// ----------------------- Release Implementation ---------------------------- //
|
||||
void* HeapAlloc::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
|
||||
void HeapAlloc::deallocate(void* aPtr) { free(aPtr); }
|
||||
HeapAlloc::~HeapAlloc() {}
|
||||
|
||||
#else
|
||||
|
||||
namespace tp {
|
||||
struct MemHeadLocal {
|
||||
MemHeadLocal* mPrev;
|
||||
MemHeadLocal* mNext;
|
||||
};
|
||||
}
|
||||
|
||||
void* HeapAlloc::allocate(ualni aBlockSize) {
|
||||
auto head = (MemHeadLocal*) HeapAllocGlobal::allocate(aBlockSize + sizeof(MemHeadLocal));
|
||||
auto out = head + 1;
|
||||
|
||||
mNumAllocations++;
|
||||
if (mEntry) {
|
||||
DEBUG_ASSERT(!mEntry->mNext)
|
||||
head->mNext = nullptr;
|
||||
head->mPrev = mEntry;
|
||||
mEntry->mNext = head;
|
||||
} else {
|
||||
head->mNext = nullptr;
|
||||
head->mPrev = nullptr;
|
||||
}
|
||||
mEntry = head;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void HeapAlloc::deallocate(void* aPtr) {
|
||||
auto head = ((MemHeadLocal*) (aPtr)) - 1;
|
||||
|
||||
mNumAllocations--;
|
||||
DEBUG_ASSERT(!mEntry->mNext)
|
||||
if (head->mNext) head->mNext->mPrev = head->mPrev;
|
||||
if (head->mPrev) head->mPrev->mNext = head->mNext;
|
||||
if (head == mEntry) {
|
||||
mEntry = head->mPrev;
|
||||
}
|
||||
|
||||
HeapAllocGlobal::deallocate(head);
|
||||
}
|
||||
|
||||
HeapAlloc::~HeapAlloc() {
|
||||
if (mNumAllocations) {
|
||||
DEBUG_BREAK("Destruction of not freed Allocator")
|
||||
|
||||
#ifdef MEM_STACK_TRACE
|
||||
// TODO : log leaks and free them up
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,198 +1,196 @@
|
|||
|
||||
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "PrivateConfig.hpp"
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "Debugging.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
#if not defined(MEM_DEBUG)
|
||||
|
||||
// ----------------------- Release Implementation ---------------------------- //
|
||||
|
||||
void* HeapAllocGlobal::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
|
||||
void HeapAllocGlobal::deallocate(void* aPtr) { free(aPtr); }
|
||||
HeapAllocGlobal::~HeapAllocGlobal() = default;
|
||||
|
||||
#else
|
||||
|
||||
tp::MemHead* tp::HeapAllocGlobal::mEntry = nullptr;
|
||||
tp::ualni tp::HeapAllocGlobal::mNumAllocations = 0;
|
||||
tp::Mutex tp::HeapAllocGlobal::mMutex;
|
||||
bool tp::HeapAllocGlobal::mIgnore;
|
||||
|
||||
// ----------------------- Debug Implementation ---------------------------- //
|
||||
// |----------------|
|
||||
// | MemHead |
|
||||
// |----------------|
|
||||
// | wrap top |
|
||||
// |----------------| - Allocated Block Layout
|
||||
// | data |
|
||||
// |----------------|
|
||||
// | wrap bottom |
|
||||
// |----------------|
|
||||
|
||||
namespace tp {
|
||||
struct MemHead {
|
||||
MemHead* mPrev;
|
||||
MemHead* mNext;
|
||||
uhalni mBlockSize;
|
||||
uhalni mIgnored;
|
||||
#ifdef MEM_STACK_TRACE
|
||||
const CallStackCapture::CallStack* mCallStack;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
enum : ualni {
|
||||
ALIGNED_SIZE = ENV_ALNI_SIZE_B,
|
||||
WRAP_SIZE = MEM_WRAP_SIZE * ALIGNED_SIZE,
|
||||
WRAP_VAL = MEM_WRAP_FILL_VAL,
|
||||
HEAD_SIZE = sizeof(MemHead),
|
||||
CLEAR_ALLOC_VAL = MEM_CLEAR_ON_ALLOC_VAL,
|
||||
CLEAR_DEALLOC_VAL = MEM_CLEAR_ON_DEALLOC_VAL,
|
||||
};
|
||||
|
||||
void* HeapAllocGlobal::allocate(ualni aBlockSize) {
|
||||
|
||||
static_assert(HEAD_SIZE % ALIGNED_SIZE == 0, "Heap Allocator Configuration Error");
|
||||
|
||||
if (aBlockSize % ALIGNED_SIZE) {
|
||||
aBlockSize = (aBlockSize / ALIGNED_SIZE + 1) * ALIGNED_SIZE;
|
||||
}
|
||||
|
||||
// 1) Allocate the block
|
||||
ALLOCATE:
|
||||
auto head = (MemHead*)malloc(aBlockSize + WRAP_SIZE * 2 + HEAD_SIZE);
|
||||
if (!head) {
|
||||
printf("WARNING : Cant allocate memory. Trying again\n");
|
||||
goto ALLOCATE; // Just freeze if no memory is available
|
||||
}
|
||||
|
||||
auto wrap_top = (int1*)(head + 1);
|
||||
auto data = wrap_top + WRAP_SIZE;
|
||||
auto wrap_bottom = data + aBlockSize;
|
||||
|
||||
head->mBlockSize = aBlockSize;
|
||||
head->mIgnored = mIgnore;
|
||||
|
||||
// 2) Link with existing blocks
|
||||
mMutex.lock();
|
||||
mNumAllocations++;
|
||||
if (mEntry) {
|
||||
DEBUG_ASSERT(mEntry->mNext == nullptr)
|
||||
head->mNext = nullptr;
|
||||
head->mPrev = mEntry;
|
||||
mEntry->mNext = head;
|
||||
} else {
|
||||
head->mNext = nullptr;
|
||||
head->mPrev = nullptr;
|
||||
}
|
||||
mEntry = head;
|
||||
|
||||
|
||||
// 3) Trace the stack
|
||||
#ifdef MEM_STACK_TRACE
|
||||
head->mCallStack = gCSCapture->getSnapshot();
|
||||
#endif
|
||||
|
||||
mMutex.unlock();
|
||||
|
||||
// 4) Wrap fill
|
||||
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
|
||||
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
|
||||
|
||||
// 5) clear data
|
||||
#ifdef MEM_CLEAR_ON_ALLOC
|
||||
memSetVal(data, aBlockSize, CLEAR_ALLOC_VAL);
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void HeapAllocGlobal::deallocate(void* aPtr) {
|
||||
if (!aPtr) return;
|
||||
|
||||
// 1) Restore the pointers
|
||||
auto head = ((MemHead*)((int1*)aPtr - WRAP_SIZE)) - 1;
|
||||
auto wrap_top = (int1*)(head + 1);
|
||||
auto data = wrap_top + WRAP_SIZE;
|
||||
auto wrap_bottom = data + head->mBlockSize;
|
||||
|
||||
// 2) Unlink with blocks
|
||||
mMutex.lock();
|
||||
mNumAllocations--;
|
||||
DEBUG_ASSERT(!mEntry->mNext)
|
||||
if (head->mNext) head->mNext->mPrev = head->mPrev;
|
||||
if (head->mPrev) head->mPrev->mNext = head->mNext;
|
||||
if (head == mEntry) {
|
||||
mEntry = head->mPrev;
|
||||
}
|
||||
mMutex.unlock();
|
||||
|
||||
if (!head->mIgnored) {
|
||||
// 3) Check the wrap
|
||||
if (memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL)) {
|
||||
CallStackCapture::printSnapshot(head->mCallStack);
|
||||
ASSERT(!"Allocated Block Wrap Corrupted!")
|
||||
}
|
||||
|
||||
if (memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL)) {
|
||||
CallStackCapture::printSnapshot(head->mCallStack);
|
||||
ASSERT(!"Allocated Block Wrap Corrupted!")
|
||||
}
|
||||
|
||||
// 4) clear data
|
||||
#ifdef MEM_CLEAR_ON_ALLOC
|
||||
memSetVal(data, head->mBlockSize, CLEAR_DEALLOC_VAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 5) free the block
|
||||
free(head);
|
||||
}
|
||||
|
||||
bool HeapAllocGlobal::checkLeaks() {
|
||||
ualni ignoredCount = 0;
|
||||
for (auto iter = mEntry; iter; iter = iter->mPrev) {
|
||||
ignoredCount += iter->mIgnored;
|
||||
}
|
||||
|
||||
// 1) Check for not deallocated memory
|
||||
if (mNumAllocations && ignoredCount < mNumAllocations) {
|
||||
|
||||
#ifdef MEM_STACK_TRACE
|
||||
for (auto iter = mEntry; iter; iter = iter->mPrev) {
|
||||
if (!iter->mIgnored) CallStackCapture::printSnapshot(iter->mCallStack);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf(" Count : %llu", mNumAllocations - ignoredCount);
|
||||
|
||||
ASSERT(!"Destruction of not freed Allocator")
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HeapAllocGlobal::startIgnore() {
|
||||
mMutex.lock();
|
||||
mIgnore = true;
|
||||
mMutex.unlock();
|
||||
}
|
||||
|
||||
void HeapAllocGlobal::stopIgnore() {
|
||||
mMutex.lock();
|
||||
mIgnore = false;
|
||||
mMutex.unlock();
|
||||
}
|
||||
|
||||
HeapAllocGlobal::~HeapAllocGlobal() = default;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "PrivateConfig.hpp"
|
||||
|
||||
#include "Debugging.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
#if not defined(MEM_DEBUG)
|
||||
|
||||
// ----------------------- Release Implementation ---------------------------- //
|
||||
|
||||
void* HeapAllocGlobal::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
|
||||
void HeapAllocGlobal::deallocate(void* aPtr) { free(aPtr); }
|
||||
HeapAllocGlobal::~HeapAllocGlobal() = default;
|
||||
|
||||
#else
|
||||
|
||||
tp::MemHead* tp::HeapAllocGlobal::mEntry = nullptr;
|
||||
tp::ualni tp::HeapAllocGlobal::mNumAllocations = 0;
|
||||
tp::Mutex tp::HeapAllocGlobal::mMutex;
|
||||
bool tp::HeapAllocGlobal::mIgnore;
|
||||
|
||||
// ----------------------- Debug Implementation ---------------------------- //
|
||||
// |----------------|
|
||||
// | MemHead |
|
||||
// |----------------|
|
||||
// | wrap top |
|
||||
// |----------------| - Allocated Block Layout
|
||||
// | data |
|
||||
// |----------------|
|
||||
// | wrap bottom |
|
||||
// |----------------|
|
||||
|
||||
namespace tp {
|
||||
struct MemHead {
|
||||
MemHead* mPrev;
|
||||
MemHead* mNext;
|
||||
uhalni mBlockSize;
|
||||
uhalni mIgnored;
|
||||
#ifdef MEM_STACK_TRACE
|
||||
const CallStackCapture::CallStack* mCallStack;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
enum : ualni {
|
||||
ALIGNED_SIZE = ENV_ALNI_SIZE_B,
|
||||
WRAP_SIZE = MEM_WRAP_SIZE * ALIGNED_SIZE,
|
||||
WRAP_VAL = MEM_WRAP_FILL_VAL,
|
||||
HEAD_SIZE = sizeof(MemHead),
|
||||
CLEAR_ALLOC_VAL = MEM_CLEAR_ON_ALLOC_VAL,
|
||||
CLEAR_DEALLOC_VAL = MEM_CLEAR_ON_DEALLOC_VAL,
|
||||
};
|
||||
|
||||
void* HeapAllocGlobal::allocate(ualni aBlockSize) {
|
||||
|
||||
static_assert(HEAD_SIZE % ALIGNED_SIZE == 0, "Heap Allocator Configuration Error");
|
||||
|
||||
if (aBlockSize % ALIGNED_SIZE) {
|
||||
aBlockSize = (aBlockSize / ALIGNED_SIZE + 1) * ALIGNED_SIZE;
|
||||
}
|
||||
|
||||
// 1) Allocate the block
|
||||
ALLOCATE:
|
||||
auto head = (MemHead*) malloc(aBlockSize + WRAP_SIZE * 2 + HEAD_SIZE);
|
||||
if (!head) {
|
||||
printf("WARNING : Cant allocate memory. Trying again\n");
|
||||
goto ALLOCATE; // Just freeze if no memory is available
|
||||
}
|
||||
|
||||
auto wrap_top = (int1*) (head + 1);
|
||||
auto data = wrap_top + WRAP_SIZE;
|
||||
auto wrap_bottom = data + aBlockSize;
|
||||
|
||||
head->mBlockSize = aBlockSize;
|
||||
head->mIgnored = mIgnore;
|
||||
|
||||
// 2) Link with existing blocks
|
||||
mMutex.lock();
|
||||
mNumAllocations++;
|
||||
if (mEntry) {
|
||||
DEBUG_ASSERT(mEntry->mNext == nullptr)
|
||||
head->mNext = nullptr;
|
||||
head->mPrev = mEntry;
|
||||
mEntry->mNext = head;
|
||||
} else {
|
||||
head->mNext = nullptr;
|
||||
head->mPrev = nullptr;
|
||||
}
|
||||
mEntry = head;
|
||||
|
||||
// 3) Trace the stack
|
||||
#ifdef MEM_STACK_TRACE
|
||||
head->mCallStack = gCSCapture->getSnapshot();
|
||||
#endif
|
||||
|
||||
mMutex.unlock();
|
||||
|
||||
// 4) Wrap fill
|
||||
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
|
||||
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
|
||||
|
||||
// 5) clear data
|
||||
#ifdef MEM_CLEAR_ON_ALLOC
|
||||
memSetVal(data, aBlockSize, CLEAR_ALLOC_VAL);
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void HeapAllocGlobal::deallocate(void* aPtr) {
|
||||
if (!aPtr) return;
|
||||
|
||||
// 1) Restore the pointers
|
||||
auto head = ((MemHead*) ((int1*) aPtr - WRAP_SIZE)) - 1;
|
||||
auto wrap_top = (int1*) (head + 1);
|
||||
auto data = wrap_top + WRAP_SIZE;
|
||||
auto wrap_bottom = data + head->mBlockSize;
|
||||
|
||||
// 2) Unlink with blocks
|
||||
mMutex.lock();
|
||||
mNumAllocations--;
|
||||
DEBUG_ASSERT(!mEntry->mNext)
|
||||
if (head->mNext) head->mNext->mPrev = head->mPrev;
|
||||
if (head->mPrev) head->mPrev->mNext = head->mNext;
|
||||
if (head == mEntry) {
|
||||
mEntry = head->mPrev;
|
||||
}
|
||||
mMutex.unlock();
|
||||
|
||||
if (!head->mIgnored) {
|
||||
// 3) Check the wrap
|
||||
if (memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL)) {
|
||||
CallStackCapture::printSnapshot(head->mCallStack);
|
||||
ASSERT(!"Allocated Block Wrap Corrupted!")
|
||||
}
|
||||
|
||||
if (memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL)) {
|
||||
CallStackCapture::printSnapshot(head->mCallStack);
|
||||
ASSERT(!"Allocated Block Wrap Corrupted!")
|
||||
}
|
||||
|
||||
// 4) clear data
|
||||
#ifdef MEM_CLEAR_ON_ALLOC
|
||||
memSetVal(data, head->mBlockSize, CLEAR_DEALLOC_VAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 5) free the block
|
||||
free(head);
|
||||
}
|
||||
|
||||
bool HeapAllocGlobal::checkLeaks() {
|
||||
ualni ignoredCount = 0;
|
||||
for (auto iter = mEntry; iter; iter = iter->mPrev) {
|
||||
ignoredCount += iter->mIgnored;
|
||||
}
|
||||
|
||||
// 1) Check for not deallocated memory
|
||||
if (mNumAllocations && ignoredCount < mNumAllocations) {
|
||||
|
||||
#ifdef MEM_STACK_TRACE
|
||||
for (auto iter = mEntry; iter; iter = iter->mPrev) {
|
||||
if (!iter->mIgnored) CallStackCapture::printSnapshot(iter->mCallStack);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf(" Count : %llu", mNumAllocations - ignoredCount);
|
||||
|
||||
ASSERT(!"Destruction of not freed Allocator")
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HeapAllocGlobal::startIgnore() {
|
||||
mMutex.lock();
|
||||
mIgnore = true;
|
||||
mMutex.unlock();
|
||||
}
|
||||
|
||||
void HeapAllocGlobal::stopIgnore() {
|
||||
mMutex.lock();
|
||||
mIgnore = false;
|
||||
mMutex.unlock();
|
||||
}
|
||||
|
||||
HeapAllocGlobal::~HeapAllocGlobal() = default;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "HeapAllocator.hpp"
|
||||
#include "ChunkAllocator.hpp"
|
||||
#include "HeapAllocator.hpp"
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "PoolAllocator.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
|
@ -13,15 +13,15 @@ namespace tp {
|
|||
|
||||
void* operator new(std::size_t aSize);
|
||||
void* operator new[](std::size_t aSize);
|
||||
void operator delete(void* aPtr) noexcept;
|
||||
void operator delete[](void* aPtr) noexcept;
|
||||
void operator delete(void* aPtr) noexcept;
|
||||
void operator delete[](void* aPtr) noexcept;
|
||||
|
||||
void* operator new(std::size_t aSize, tp::HeapAlloc& aAlloc);
|
||||
void* operator new[](std::size_t aSize, tp::HeapAlloc& aAlloc);
|
||||
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc);
|
||||
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc);
|
||||
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc);
|
||||
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc);
|
||||
|
||||
void* operator new(std::size_t aSize, tp::HeapAllocGlobal& aAlloc);
|
||||
void* operator new[](std::size_t aSize, tp::HeapAllocGlobal& aAlloc);
|
||||
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc);
|
||||
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc);
|
||||
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc);
|
||||
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc);
|
||||
|
|
@ -14,8 +14,8 @@
|
|||
* 2) updating list entry to that block.
|
||||
*/
|
||||
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "Environment.hpp"
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "PrivateConfig.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
|
@ -23,7 +23,7 @@ namespace tp {
|
|||
// Chunk Allocator
|
||||
// Constant time allocations and de-allocations in any order.
|
||||
// Memory blocks are fixed in size and number of blocks can not exceed given parameter.
|
||||
template<typename tType, ualni tNumBlocks>
|
||||
template <typename tType, ualni tNumBlocks>
|
||||
class ChunkAlloc {
|
||||
|
||||
enum : ualni {
|
||||
|
|
@ -76,24 +76,24 @@ namespace tp {
|
|||
|
||||
// 2) Find free block and update next free block
|
||||
auto data = mNextBlock;
|
||||
mNextBlock = (ualni*)(*data);
|
||||
mNextBlock = (ualni*) (*data);
|
||||
mNumFreeBlocks--;
|
||||
|
||||
#ifdef MEM_DEBUG
|
||||
// 3) Fill Wrap and offset data
|
||||
auto wrap_top = data;
|
||||
auto wrap_bottom = data + WRAP_SIZE_ALN + dataSize();
|
||||
#ifdef MEM_DEBUG
|
||||
// 3) Fill Wrap and offset data
|
||||
auto wrap_top = data;
|
||||
auto wrap_bottom = data + WRAP_SIZE_ALN + dataSize();
|
||||
|
||||
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
|
||||
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
|
||||
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
|
||||
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
|
||||
|
||||
// 4) Clear data
|
||||
#ifdef MEM_CLEAR_ON_ALLOC
|
||||
memSetVal(data + WRAP_SIZE_ALN, dataSize() * ALIGNED_SIZE, CLEAR_ALLOC_VAL);
|
||||
#endif
|
||||
// 4) Clear data
|
||||
#ifdef MEM_CLEAR_ON_ALLOC
|
||||
memSetVal(data + WRAP_SIZE_ALN, dataSize() * ALIGNED_SIZE, CLEAR_ALLOC_VAL);
|
||||
#endif
|
||||
|
||||
data += WRAP_SIZE_ALN;
|
||||
#endif
|
||||
data += WRAP_SIZE_ALN;
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -101,26 +101,26 @@ namespace tp {
|
|||
void deallocate(void* aPtr) {
|
||||
DEBUG_ASSERT(aPtr >= mBuff && aPtr < mBuff + tNumBlocks * blockSize())
|
||||
|
||||
auto block = (ualni*)aPtr;
|
||||
auto block = (ualni*) aPtr;
|
||||
|
||||
#ifdef MEM_DEBUG
|
||||
// 3) Check Wrap and offset data
|
||||
auto wrap_bottom = block + dataSize();
|
||||
auto wrap_top = block - WRAP_SIZE_ALN;
|
||||
block = wrap_top;
|
||||
#ifdef MEM_DEBUG
|
||||
// 3) Check Wrap and offset data
|
||||
auto wrap_bottom = block + dataSize();
|
||||
auto wrap_top = block - WRAP_SIZE_ALN;
|
||||
block = wrap_top;
|
||||
|
||||
// 3) Check the wrap
|
||||
ASSERT(!memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
|
||||
ASSERT(!memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
|
||||
// 3) Check the wrap
|
||||
ASSERT(!memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
|
||||
ASSERT(!memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
|
||||
|
||||
// 4) Clear data
|
||||
#ifdef MEM_CLEAR_ON_ALLOC
|
||||
memSetVal(block, blockSize() * ALIGNED_SIZE, CLEAR_DEALLOC_VAL);
|
||||
#endif
|
||||
// 4) Clear data
|
||||
#ifdef MEM_CLEAR_ON_ALLOC
|
||||
memSetVal(block, blockSize() * ALIGNED_SIZE, CLEAR_DEALLOC_VAL);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
(*block) = (ualni)mNextBlock;
|
||||
(*block) = (ualni) mNextBlock;
|
||||
mNextBlock = block;
|
||||
mNumFreeBlocks++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ namespace tp {
|
|||
|
||||
// Pool Allocator
|
||||
// Overcomes chunk allocator fixed number of max allocations
|
||||
template<typename tType, ualni tNumBlocks>
|
||||
template <typename tType, ualni tNumBlocks>
|
||||
class PoolAlloc {
|
||||
|
||||
typedef ChunkAlloc<tType, tNumBlocks> Chunk;
|
||||
|
||||
struct Chunks {
|
||||
|
||||
void add(Chunk* aChunk){
|
||||
void add(Chunk* aChunk) {
|
||||
|
||||
if (!mBuff) {
|
||||
mLen = 16;
|
||||
|
|
@ -57,7 +57,7 @@ namespace tp {
|
|||
}
|
||||
}
|
||||
|
||||
void remove(Chunk** del_address){
|
||||
void remove(Chunk** del_address) {
|
||||
if (mUsedLen == 1) {
|
||||
mLen = 0;
|
||||
mUsedLen = 0;
|
||||
|
|
@ -74,18 +74,16 @@ namespace tp {
|
|||
mUsedLen--;
|
||||
|
||||
// check for buff low usage
|
||||
if ((halnf)mUsedLen / (halnf)mLen < 0.25f) {
|
||||
if ((halnf) mUsedLen / (halnf) mLen < 0.25f) {
|
||||
auto prevBuff = mBuff;
|
||||
mBuff = (Chunk**)HeapAllocGlobal::allocate(sizeof(Chunk*) * mLen / 2);
|
||||
mBuff = (Chunk**) HeapAllocGlobal::allocate(sizeof(Chunk*) * mLen / 2);
|
||||
memCopy(mBuff, prevBuff, sizeof(Chunk*) * mUsedLen);
|
||||
mLen /= 2;
|
||||
HeapAllocGlobal::deallocate(prevBuff);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] Chunk** find(void* aPtr) {
|
||||
return findUtil(mBuff, mBuff + mUsedLen, aPtr) - 1;
|
||||
}
|
||||
[[nodiscard]] Chunk** find(void* aPtr) { return findUtil(mBuff, mBuff + mUsedLen, aPtr) - 1; }
|
||||
|
||||
[[nodiscard]] Chunk* findNotFull() const {
|
||||
for (ualni idx = 0; idx < mUsedLen; idx++) {
|
||||
|
|
@ -137,9 +135,9 @@ namespace tp {
|
|||
auto chunk = mChunks.find(aPtr);
|
||||
(*chunk)->deallocate(aPtr);
|
||||
if ((*chunk)->isEmpty()) {
|
||||
if (mFreeChunk == *chunk) mFreeChunk = nullptr;
|
||||
HeapAllocGlobal::deallocate(*chunk);
|
||||
mChunks.remove(chunk);
|
||||
if (mFreeChunk == *chunk) mFreeChunk = nullptr;
|
||||
HeapAllocGlobal::deallocate(*chunk);
|
||||
mChunks.remove(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +151,7 @@ namespace tp {
|
|||
if (i > j) {
|
||||
ASSERT(mChunks.mBuff[i] > mChunks.mBuff[j])
|
||||
} else if (i < j) {
|
||||
ASSERT(mChunks.mBuff[i] < mChunks.mBuff[j])
|
||||
ASSERT(mChunks.mBuff[i] < mChunks.mBuff[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
#include "Tests.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
int main() {
|
||||
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, &tp::gModuleUtils, nullptr };
|
||||
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
|
||||
|
||||
if (!testModule.initialize()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
testAll();
|
||||
|
||||
testModule.deinitialize();
|
||||
}
|
||||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
#include "Tests.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
int main() {
|
||||
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, &tp::gModuleUtils, nullptr };
|
||||
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
|
||||
|
||||
if (!testModule.initialize()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
testAll();
|
||||
|
||||
testModule.deinitialize();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "Testing.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
void testAll();
|
||||
|
|
@ -1,248 +1,245 @@
|
|||
|
||||
#include "Utils.hpp"
|
||||
#include "Testing.hpp"
|
||||
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "HeapAllocator.hpp"
|
||||
#include "ChunkAllocator.hpp"
|
||||
#include "PoolAllocator.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
struct TestStruct {
|
||||
alni val = 0;
|
||||
|
||||
TestStruct() : val(0) {}
|
||||
explicit TestStruct(alni val) : val(val) {}
|
||||
TestStruct(const TestStruct& in) : val(in.val) {}
|
||||
|
||||
~TestStruct() { val = -1; }
|
||||
|
||||
bool operator==(const TestStruct& in) const {
|
||||
return in.val == val;
|
||||
}
|
||||
};
|
||||
|
||||
template <alni tSize, class tAllocator>
|
||||
class TestBenches {
|
||||
|
||||
tAllocator mAlloc{};
|
||||
TestStruct mData[tSize]{};
|
||||
TestStruct* mLoaded[tSize]{};
|
||||
bool mIsLoaded[tSize]{};
|
||||
alni mLoadedNum = 0;
|
||||
|
||||
public:
|
||||
TestBenches() {
|
||||
for (alni i = 0; i < tSize; i++) {
|
||||
mData[i].val = i;
|
||||
mIsLoaded[i] = false;
|
||||
mLoaded[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void runTests() {
|
||||
try {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
} catch (...) {
|
||||
ASSERT(false)
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
alni randomIdx(bool state, Range<alni> range = { 0, tSize }) {
|
||||
RAND:
|
||||
auto idx = alni(alnf(range.idxBegin()) + randomFloat() * alnf(range.idxDiff() + 1));
|
||||
idx = clamp(idx, alni(0), tSize - 1);
|
||||
if (state == mIsLoaded[idx]) goto RAND;
|
||||
return idx;
|
||||
}
|
||||
|
||||
void verifyIntegrity() {
|
||||
mAlloc.checkValid();
|
||||
ASSERT(!mAlloc.checkWrap())
|
||||
for (alni i = 0; i < tSize; i++) {
|
||||
if (mIsLoaded[i]) {
|
||||
ASSERT(*mLoaded[i] == mData[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadItem(alni idx) {
|
||||
if (mIsLoaded[idx]) return;
|
||||
verifyIntegrity();
|
||||
mLoaded[idx] = new (mAlloc.allocate(sizeof(TestStruct))) TestStruct(mData[idx]);
|
||||
TEST(mLoaded[idx]);
|
||||
mIsLoaded[idx] = true;
|
||||
mLoadedNum++;
|
||||
verifyIntegrity();
|
||||
}
|
||||
|
||||
void unloadItem(alni idx) {
|
||||
if (!mIsLoaded[idx]) return;
|
||||
verifyIntegrity();
|
||||
mLoaded[idx]->~TestStruct();
|
||||
mAlloc.deallocate(mLoaded[idx]);
|
||||
mIsLoaded[idx] = false;
|
||||
mLoadedNum--;
|
||||
verifyIntegrity();
|
||||
}
|
||||
|
||||
void changeStates(Range<alni> rg, bool load, bool reversed = false, bool random = false) {
|
||||
for (auto i : rg) {
|
||||
alni idx = i;
|
||||
if (random) {
|
||||
idx = randomIdx(load, rg);
|
||||
} else if (reversed) {
|
||||
idx = rg.idxEnd() - i - 1;
|
||||
}
|
||||
(load) ? loadItem(idx) : unloadItem(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// full down-up load then up-down unload
|
||||
void test1() {
|
||||
changeStates({ 0, tSize }, true);
|
||||
changeStates({ 0, tSize }, false, true);
|
||||
}
|
||||
|
||||
// full down-up load then down-up unload
|
||||
void test2() {
|
||||
changeStates({0, tSize}, true);
|
||||
changeStates({0, tSize}, false);
|
||||
}
|
||||
|
||||
// full random load then random unload
|
||||
void test3() {
|
||||
changeStates({0, tSize}, true, false, true);
|
||||
changeStates({0, tSize}, false, false, true);
|
||||
}
|
||||
|
||||
// combo tests 1-3
|
||||
void test4() {
|
||||
test1();
|
||||
test1();
|
||||
|
||||
test2();
|
||||
test2();
|
||||
|
||||
test3();
|
||||
test3();
|
||||
}
|
||||
|
||||
static alnf sineUpFunction(alnf aSize, alnf aX, bool aReverse) {
|
||||
alnf end = 4 * 3.14159;
|
||||
alnf a = (2 / 7.f) * aSize;
|
||||
alnf b = end / aSize;
|
||||
|
||||
alni c = ((-1 * aReverse) + (1 * !aReverse));
|
||||
alnf c1 = (aX - (end * aReverse)) / b;
|
||||
alnf c2 = (a * sin(aX - (end * aReverse)));
|
||||
alnf out = c1 + c2;
|
||||
return (alnf) c * out;
|
||||
}
|
||||
|
||||
// sin load & sin unload with ~1/2 drop factor
|
||||
void test5() {
|
||||
alnf end = 4 * 3.14159;
|
||||
alnf step = end / 4.f;
|
||||
|
||||
for (char i = 0; i < 2; i++) {
|
||||
for (alnf x = 0; x <= end; x += step) {
|
||||
|
||||
alni target_alloc_count = (alni) ceil(sineUpFunction(tSize, x, i));
|
||||
target_alloc_count = clamp(target_alloc_count, alni(0), tSize);
|
||||
|
||||
while (mLoadedNum > target_alloc_count) {
|
||||
unloadItem(randomIdx(0));
|
||||
}
|
||||
while (mLoadedNum < target_alloc_count) {
|
||||
loadItem(randomIdx(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkWrap(ualni offset, bool after) {
|
||||
offset = clamp(offset, (ualni) 1, (ualni) MEM_WRAP_SIZE);
|
||||
|
||||
TestStruct* ts = mLoaded[randomIdx(0)];
|
||||
ualni shift = (sizeof(TestStruct) * after) + (offset - 1) * after - offset * (!after);
|
||||
uint1* address = (((uint1*)ts) + shift);
|
||||
|
||||
uint1 val = *address;
|
||||
*address = 5;
|
||||
|
||||
TEST(!mAlloc.checkWrap());
|
||||
|
||||
*address = val;
|
||||
}
|
||||
|
||||
// mem guards test
|
||||
void test6() {
|
||||
changeStates({0, tSize}, 1);
|
||||
#ifdef MEM_DEBUG
|
||||
for (alni after = 0; after < 2; after++) {
|
||||
for (alni offset = 1; offset <= MEM_WRAP_SIZE; offset++) {
|
||||
checkWrap(offset, after);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
changeStates({0, tSize}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const ualni size = 1000;
|
||||
|
||||
template<typename Alloc>
|
||||
void testAlloc() {
|
||||
try {
|
||||
TestBenches<size, Alloc> heapTests{};
|
||||
heapTests.runTests();
|
||||
} catch (...) {
|
||||
TEST(false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(GlobalHeap) {
|
||||
testAlloc<HeapAllocGlobal>();
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(Heap) {
|
||||
testAlloc<HeapAlloc>();
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(Chunk) {
|
||||
testAlloc<ChunkAlloc<TestStruct, size>>();
|
||||
testAlloc<ChunkAlloc<TestStruct, size * 2>>();
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(Pool) {
|
||||
testAlloc<PoolAlloc<TestStruct, 1>>();
|
||||
testAlloc<PoolAlloc<TestStruct, size / 100>>();
|
||||
testAlloc<PoolAlloc<TestStruct, size>>();
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(Simple) {
|
||||
auto a = new TestStruct(-1);
|
||||
delete a;
|
||||
}
|
||||
|
||||
TEST_DEF(All) {
|
||||
testSimple();
|
||||
|
||||
testGlobalHeap();
|
||||
testHeap();
|
||||
testChunk();
|
||||
testPool();
|
||||
|
||||
// TEST(HeapAllocGlobal::checkLeaks());
|
||||
// TEST(false);
|
||||
|
||||
#include "Testing.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include "ChunkAllocator.hpp"
|
||||
#include "HeapAllocator.hpp"
|
||||
#include "HeapAllocatorGlobal.hpp"
|
||||
#include "PoolAllocator.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
struct TestStruct {
|
||||
alni val = 0;
|
||||
|
||||
TestStruct() :
|
||||
val(0) {}
|
||||
explicit TestStruct(alni val) :
|
||||
val(val) {}
|
||||
TestStruct(const TestStruct& in) :
|
||||
val(in.val) {}
|
||||
|
||||
~TestStruct() { val = -1; }
|
||||
|
||||
bool operator==(const TestStruct& in) const { return in.val == val; }
|
||||
};
|
||||
|
||||
template <alni tSize, class tAllocator>
|
||||
class TestBenches {
|
||||
|
||||
tAllocator mAlloc{};
|
||||
TestStruct mData[tSize]{};
|
||||
TestStruct* mLoaded[tSize]{};
|
||||
bool mIsLoaded[tSize]{};
|
||||
alni mLoadedNum = 0;
|
||||
|
||||
public:
|
||||
TestBenches() {
|
||||
for (alni i = 0; i < tSize; i++) {
|
||||
mData[i].val = i;
|
||||
mIsLoaded[i] = false;
|
||||
mLoaded[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void runTests() {
|
||||
try {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
} catch (...) {
|
||||
ASSERT(false)
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
alni randomIdx(bool state, Range<alni> range = { 0, tSize }) {
|
||||
RAND:
|
||||
auto idx = alni(alnf(range.idxBegin()) + randomFloat() * alnf(range.idxDiff() + 1));
|
||||
idx = clamp(idx, alni(0), tSize - 1);
|
||||
if (state == mIsLoaded[idx]) goto RAND;
|
||||
return idx;
|
||||
}
|
||||
|
||||
void verifyIntegrity() {
|
||||
mAlloc.checkValid();
|
||||
ASSERT(!mAlloc.checkWrap())
|
||||
for (alni i = 0; i < tSize; i++) {
|
||||
if (mIsLoaded[i]) {
|
||||
ASSERT(*mLoaded[i] == mData[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadItem(alni idx) {
|
||||
if (mIsLoaded[idx]) return;
|
||||
verifyIntegrity();
|
||||
mLoaded[idx] = new (mAlloc.allocate(sizeof(TestStruct))) TestStruct(mData[idx]);
|
||||
TEST(mLoaded[idx]);
|
||||
mIsLoaded[idx] = true;
|
||||
mLoadedNum++;
|
||||
verifyIntegrity();
|
||||
}
|
||||
|
||||
void unloadItem(alni idx) {
|
||||
if (!mIsLoaded[idx]) return;
|
||||
verifyIntegrity();
|
||||
mLoaded[idx]->~TestStruct();
|
||||
mAlloc.deallocate(mLoaded[idx]);
|
||||
mIsLoaded[idx] = false;
|
||||
mLoadedNum--;
|
||||
verifyIntegrity();
|
||||
}
|
||||
|
||||
void changeStates(Range<alni> rg, bool load, bool reversed = false, bool random = false) {
|
||||
for (auto i : rg) {
|
||||
alni idx = i;
|
||||
if (random) {
|
||||
idx = randomIdx(load, rg);
|
||||
} else if (reversed) {
|
||||
idx = rg.idxEnd() - i - 1;
|
||||
}
|
||||
(load) ? loadItem(idx) : unloadItem(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// full down-up load then up-down unload
|
||||
void test1() {
|
||||
changeStates({ 0, tSize }, true);
|
||||
changeStates({ 0, tSize }, false, true);
|
||||
}
|
||||
|
||||
// full down-up load then down-up unload
|
||||
void test2() {
|
||||
changeStates({ 0, tSize }, true);
|
||||
changeStates({ 0, tSize }, false);
|
||||
}
|
||||
|
||||
// full random load then random unload
|
||||
void test3() {
|
||||
changeStates({ 0, tSize }, true, false, true);
|
||||
changeStates({ 0, tSize }, false, false, true);
|
||||
}
|
||||
|
||||
// combo tests 1-3
|
||||
void test4() {
|
||||
test1();
|
||||
test1();
|
||||
|
||||
test2();
|
||||
test2();
|
||||
|
||||
test3();
|
||||
test3();
|
||||
}
|
||||
|
||||
static alnf sineUpFunction(alnf aSize, alnf aX, bool aReverse) {
|
||||
alnf end = 4 * 3.14159;
|
||||
alnf a = (2 / 7.f) * aSize;
|
||||
alnf b = end / aSize;
|
||||
|
||||
alni c = ((-1 * aReverse) + (1 * !aReverse));
|
||||
alnf c1 = (aX - (end * aReverse)) / b;
|
||||
alnf c2 = (a * sin(aX - (end * aReverse)));
|
||||
alnf out = c1 + c2;
|
||||
return (alnf) c * out;
|
||||
}
|
||||
|
||||
// sin load & sin unload with ~1/2 drop factor
|
||||
void test5() {
|
||||
alnf end = 4 * 3.14159;
|
||||
alnf step = end / 4.f;
|
||||
|
||||
for (char i = 0; i < 2; i++) {
|
||||
for (alnf x = 0; x <= end; x += step) {
|
||||
|
||||
alni target_alloc_count = (alni) ceil(sineUpFunction(tSize, x, i));
|
||||
target_alloc_count = clamp(target_alloc_count, alni(0), tSize);
|
||||
|
||||
while (mLoadedNum > target_alloc_count) {
|
||||
unloadItem(randomIdx(0));
|
||||
}
|
||||
while (mLoadedNum < target_alloc_count) {
|
||||
loadItem(randomIdx(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkWrap(ualni offset, bool after) {
|
||||
offset = clamp(offset, (ualni) 1, (ualni) MEM_WRAP_SIZE);
|
||||
|
||||
TestStruct* ts = mLoaded[randomIdx(0)];
|
||||
ualni shift = (sizeof(TestStruct) * after) + (offset - 1) * after - offset * (!after);
|
||||
uint1* address = (((uint1*) ts) + shift);
|
||||
|
||||
uint1 val = *address;
|
||||
*address = 5;
|
||||
|
||||
TEST(!mAlloc.checkWrap());
|
||||
|
||||
*address = val;
|
||||
}
|
||||
|
||||
// mem guards test
|
||||
void test6() {
|
||||
changeStates({ 0, tSize }, 1);
|
||||
#ifdef MEM_DEBUG
|
||||
for (alni after = 0; after < 2; after++) {
|
||||
for (alni offset = 1; offset <= MEM_WRAP_SIZE; offset++) {
|
||||
checkWrap(offset, after);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
changeStates({ 0, tSize }, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const ualni size = 1000;
|
||||
|
||||
template <typename Alloc>
|
||||
void testAlloc() {
|
||||
try {
|
||||
TestBenches<size, Alloc> heapTests{};
|
||||
heapTests.runTests();
|
||||
} catch (...) {
|
||||
TEST(false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(GlobalHeap) { testAlloc<HeapAllocGlobal>(); }
|
||||
|
||||
TEST_DEF_STATIC(Heap) { testAlloc<HeapAlloc>(); }
|
||||
|
||||
TEST_DEF_STATIC(Chunk) {
|
||||
testAlloc<ChunkAlloc<TestStruct, size>>();
|
||||
testAlloc<ChunkAlloc<TestStruct, size * 2>>();
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(Pool) {
|
||||
testAlloc<PoolAlloc<TestStruct, 1>>();
|
||||
testAlloc<PoolAlloc<TestStruct, size / 100>>();
|
||||
testAlloc<PoolAlloc<TestStruct, size>>();
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(Simple) {
|
||||
auto a = new TestStruct(-1);
|
||||
delete a;
|
||||
}
|
||||
|
||||
TEST_DEF(All) {
|
||||
testSimple();
|
||||
|
||||
testGlobalHeap();
|
||||
testHeap();
|
||||
testChunk();
|
||||
testPool();
|
||||
|
||||
// TEST(HeapAllocGlobal::checkLeaks());
|
||||
// TEST(false);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue