Allocators Testing Added. Pull and Chunk allocators updates.
This commit is contained in:
parent
4a2ab6f5d0
commit
9e5ac1e975
30 changed files with 704 additions and 701 deletions
|
|
@ -1,302 +1,20 @@
|
|||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "Tests.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
int main() {
|
||||
|
||||
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleAllocators, NULL };
|
||||
tp::ModuleManifest TestModule("Test", NULL, NULL, ModuleDependencies);
|
||||
if (!TestModule.initialize()) {
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, &tp::gModuleUtils, nullptr };
|
||||
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
|
||||
|
||||
if (!testModule.initialize()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
tp::HeapAllocGlobal alloc;
|
||||
testAll();
|
||||
|
||||
int* val = new(alloc) int();
|
||||
delete(alloc, val);
|
||||
testModule.deinitialize();
|
||||
}
|
||||
|
||||
struct test_struct {
|
||||
tp::alni val = 0;
|
||||
|
||||
test_struct() { val = 1; }
|
||||
~test_struct() { val = -1; }
|
||||
|
||||
bool operator==(const test_struct& in) { return in.val == val; }
|
||||
};
|
||||
|
||||
template <tp::alni size>
|
||||
struct allocator_test {
|
||||
test_struct data[size];
|
||||
bool is_allocated[size];
|
||||
tp::alni n_loaded = 0;
|
||||
|
||||
test_struct* allocations[size];
|
||||
|
||||
tp::AbstractAllocator* alloc;
|
||||
tp::AbstractAllocator* parent_alloc;
|
||||
const char* allocator_name = NULL;
|
||||
|
||||
tp::alni rand_idx(bool state) {
|
||||
RAND:
|
||||
|
||||
tp::alni idx = (tp::alni)(tp::randf() * (size + 1));
|
||||
CLAMP(idx, 0, size - 1);
|
||||
|
||||
if (state == is_allocated[idx]) {
|
||||
goto RAND;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
allocator_test(tp::AbstractAllocator* palloc, const char* pallocator_name, tp::AbstractAllocator* p_parent_alloc) {
|
||||
allocator_name = pallocator_name;
|
||||
parent_alloc = p_parent_alloc;
|
||||
alloc = palloc;
|
||||
for (tp::alni i = 0; i < size; i++) {
|
||||
RAND:
|
||||
tp::alni val = tp::alni(tp::randf() * (size + 100.f));
|
||||
for (tp::alni check_idx = 0; check_idx < size; check_idx++) {
|
||||
if (data[check_idx].val == val) {
|
||||
goto RAND;
|
||||
}
|
||||
}
|
||||
|
||||
data[i].val = val;
|
||||
is_allocated[i] = false;
|
||||
allocations[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void verify_integrity() {
|
||||
// verify data integrity
|
||||
for (tp::alni i = 0; i < size; i++) {
|
||||
if (is_allocated[i]) {
|
||||
assert(*allocations[i] == data[i] && "data is currupted\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc->isWrapSupport()) assert(!alloc->isWrapCorrupted());
|
||||
if (parent_alloc && parent_alloc->isWrapSupport())
|
||||
assert(!parent_alloc->isWrapCorrupted());
|
||||
|
||||
verify_sizes();
|
||||
}
|
||||
|
||||
void verify_sizes() {
|
||||
return;
|
||||
#ifdef MEM_TRACE
|
||||
assert(alloc->sizeInuse() == n_loaded * sizeof(test_struct) &&
|
||||
"invalid inuse size\n");
|
||||
assert(alloc->sizeReserved() >= n_loaded * (tp::alni)sizeof(test_struct) &&
|
||||
"invalid reserved size\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void load_item(tp::alni idx) {
|
||||
if (!is_allocated[idx]) {
|
||||
allocations[idx] = new (alloc) test_struct();
|
||||
|
||||
assert(allocations[idx] && "allocator returned NULL");
|
||||
|
||||
allocations[idx]->val = data[idx].val;
|
||||
is_allocated[idx] = true;
|
||||
n_loaded++;
|
||||
verify_integrity();
|
||||
}
|
||||
}
|
||||
|
||||
void unload_item(tp::alni idx) {
|
||||
if (is_allocated[idx]) {
|
||||
verify_integrity();
|
||||
delete allocations[idx];
|
||||
is_allocated[idx] = false;
|
||||
n_loaded--;
|
||||
verify_integrity();
|
||||
}
|
||||
}
|
||||
|
||||
void change_states(tp::Range<tp::alni> rg, bool state, bool reversed = false, bool random = false) {
|
||||
for (auto i : rg) {
|
||||
tp::alni idx = i;
|
||||
|
||||
if (random) {
|
||||
idx = rand_idx(state);
|
||||
}
|
||||
else if (reversed) {
|
||||
idx = size - i - 1;
|
||||
}
|
||||
|
||||
(state) ? load_item(idx) : unload_item(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// full down-up load then up-down unload
|
||||
void test1() {
|
||||
change_states({ 0, size }, 1);
|
||||
change_states({ 0, size }, 0, true);
|
||||
}
|
||||
|
||||
// full down-up load then down-up unload
|
||||
void test2() {
|
||||
change_states({ 0, size }, 1);
|
||||
change_states({ 0, size }, 0);
|
||||
}
|
||||
|
||||
// full random load then random unload
|
||||
void test3() {
|
||||
change_states({ 0, size }, 1, 0, 1);
|
||||
change_states({ 0, size }, 0, 0, 1);
|
||||
}
|
||||
|
||||
// multipul tests 1-3
|
||||
void test4() {
|
||||
test1();
|
||||
test1();
|
||||
|
||||
test2();
|
||||
test2();
|
||||
|
||||
test3();
|
||||
test3();
|
||||
}
|
||||
|
||||
static tp::alnf sineupf(tp::alnf asize, tp::alnf x, bool reverse) {
|
||||
tp::alnf end = 4 * PI;
|
||||
tp::alnf a = (2 / 7.f) * asize;
|
||||
tp::alnf b = end / asize;
|
||||
|
||||
tp::alni c = ((-1 * reverse) + (1 * !reverse));
|
||||
tp::alnf c1 = (x - (end * reverse)) / b;
|
||||
tp::alnf c2 = (a * sin(x - (end * reverse)));
|
||||
tp::alnf out = c1 + c2;
|
||||
return c * out;
|
||||
}
|
||||
|
||||
// sin load & sin unload with ~1/2 drop factor
|
||||
void test5() {
|
||||
tp::alnf end = 4 * PI;
|
||||
tp::alnf step = end / 4.f;
|
||||
|
||||
for (char i = 0; i < 2; i++) {
|
||||
for (tp::alnf x = 0; x <= end; x += step) {
|
||||
tp::alni target_alloc_count = (tp::alni)ceil(sineupf(size, x, i));
|
||||
CLAMP(target_alloc_count, 0, size);
|
||||
|
||||
while (n_loaded > target_alloc_count) {
|
||||
unload_item(rand_idx(0));
|
||||
}
|
||||
while (n_loaded < target_alloc_count) {
|
||||
load_item(rand_idx(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MEM_WRAP
|
||||
void check_wrap(tp::alni offset, bool after) {
|
||||
CLAMP(offset, 1, WRAP_LEN);
|
||||
|
||||
test_struct* ts = allocations[rand_idx(0)];
|
||||
tp::alni shift = (sizeof(test_struct) * after) + (offset - 1) * after -
|
||||
offset * (!after);
|
||||
tp::uint1* address = (((tp::uint1*)ts) + shift);
|
||||
|
||||
tp::uint1 val = *address;
|
||||
*address = 5;
|
||||
assert(alloc->isWrapCorrupted());
|
||||
*address = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
// mem guards test
|
||||
void test6() {
|
||||
change_states({ 0, size }, 1);
|
||||
|
||||
#ifdef MEM_WRAP
|
||||
for (tp::alni after = 0; after < 2; after++) {
|
||||
for (tp::alni offset = 1; offset <= WRAP_LEN; offset++) {
|
||||
check_wrap(offset, after);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
change_states({ 0, size }, 0);
|
||||
}
|
||||
|
||||
void run_tests() {
|
||||
try {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
if (alloc->isWrapSupport()) {
|
||||
test6();
|
||||
}
|
||||
|
||||
printf("%s - passed\n", allocator_name);
|
||||
if (!alloc->isWrapSupport()) {
|
||||
printf(" WARNING: %s has no wrap support!! \n", allocator_name);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
printf("%s - failed\n", allocator_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void heap_alloc_test() {
|
||||
tp::alloc_init(); {
|
||||
try {
|
||||
allocator_test<150> hatest(tp::heapalloc, "heap allocator", NULL);
|
||||
hatest.run_tests();
|
||||
}
|
||||
catch (...) {
|
||||
printf("heap alloc failed\n");
|
||||
}
|
||||
} tp::alloc_uninit();
|
||||
}
|
||||
|
||||
void chunk_alloc_test() {
|
||||
tp::alloc_init(); {
|
||||
try {
|
||||
tp::ChunkAlloc calloc(sizeof(test_struct), 50);
|
||||
allocator_test<50> ca_test(&calloc, "chunk allocator", tp::heapalloc);
|
||||
ca_test.run_tests();
|
||||
}
|
||||
catch (...) {
|
||||
printf("chunk alloc failed\n");
|
||||
}
|
||||
} tp::alloc_uninit();
|
||||
}
|
||||
|
||||
void pool_alloc_test() {
|
||||
tp::alloc_init(); {
|
||||
try {
|
||||
tp::PoolAlloc palloc(sizeof(test_struct), 50);
|
||||
allocator_test<150> pa_test(&palloc, "pool allocator", tp::heapalloc);
|
||||
pa_test.run_tests();
|
||||
}
|
||||
catch (...) {
|
||||
printf("chunk alloc failed\n");
|
||||
}
|
||||
} tp::alloc_uninit();
|
||||
}
|
||||
|
||||
void allocators_test() {
|
||||
printf("running tests on alocators:\n");
|
||||
|
||||
heap_alloc_test();
|
||||
chunk_alloc_test();
|
||||
pool_alloc_test();
|
||||
}
|
||||
|
||||
|
||||
CROSSPLATFORM_MAIN;
|
||||
int main(int argc, char* argv[]) {
|
||||
tp::print_env_info();
|
||||
allocators_test();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "Testing.hpp"
|
||||
|
||||
void testAll();
|
||||
248
Allocators/tests/TestsAll.cpp
Normal file
248
Allocators/tests/TestsAll.cpp
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
|
||||
#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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue