mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-16 09:04:38 +00:00
Add tests for FrameAllocator and DataChunker
This commit is contained in:
parent
3781c7fae5
commit
7332dd6643
5 changed files with 597 additions and 9 deletions
|
|
@ -39,6 +39,8 @@ public:
|
||||||
ChunkSize = 16384
|
ChunkSize = 16384
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef T AlignmentType;
|
||||||
|
|
||||||
struct alignas(uintptr_t) DataBlock : public AlignedBufferAllocator<T>
|
struct alignas(uintptr_t) DataBlock : public AlignedBufferAllocator<T>
|
||||||
{
|
{
|
||||||
DataBlock* mNext;
|
DataBlock* mNext;
|
||||||
|
|
@ -129,6 +131,19 @@ public:
|
||||||
AssertFatal(mChunkHead == NULL, "Tried setting AFTER init");
|
AssertFatal(mChunkHead == NULL, "Tried setting AFTER init");
|
||||||
mChunkSize = size;
|
mChunkSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isManagedByChunker(void* ptr) const
|
||||||
|
{
|
||||||
|
U8* chkPtr = (U8*)ptr;
|
||||||
|
for (DataBlock* itr = mChunkHead; itr; itr = itr->mNext)
|
||||||
|
{
|
||||||
|
const U8* blockStart = (U8*)itr->getAlignedBuffer();
|
||||||
|
const U8* blockEnd = (U8*)itr->getAlignedBufferEnd();
|
||||||
|
if (chkPtr >= blockStart && chkPtr < blockEnd)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DataChunker : public BaseDataChunker<uintptr_t>
|
class DataChunker : public BaseDataChunker<uintptr_t>
|
||||||
|
|
@ -166,6 +181,8 @@ public:
|
||||||
class MultiTypedChunker : private BaseDataChunker<uintptr_t>
|
class MultiTypedChunker : private BaseDataChunker<uintptr_t>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef uintptr_t AlignmentType;
|
||||||
|
|
||||||
MultiTypedChunker(dsize_t size = BaseDataChunker<uintptr_t>::ChunkSize) : BaseDataChunker<uintptr_t>(std::max<uintptr_t>(sizeof(uintptr_t), size))
|
MultiTypedChunker(dsize_t size = BaseDataChunker<uintptr_t>::ChunkSize) : BaseDataChunker<uintptr_t>(std::max<uintptr_t>(sizeof(uintptr_t), size))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +212,7 @@ template<class T> struct ChunkerFreeClassList
|
||||||
mNextList = NULL;
|
mNextList = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEmpty()
|
bool isEmpty() const
|
||||||
{
|
{
|
||||||
return mNextList == NULL;
|
return mNextList == NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +265,15 @@ public:
|
||||||
void freeBlocks(bool keepOne = false)
|
void freeBlocks(bool keepOne = false)
|
||||||
{
|
{
|
||||||
BaseDataChunker<T>::freeBlocks(keepOne);
|
BaseDataChunker<T>::freeBlocks(keepOne);
|
||||||
|
mFreeListHead.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isManagedByChunker(void* ptr) const
|
||||||
|
{
|
||||||
|
return BaseDataChunker<T>::isManagedByChunker(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ChunkerFreeClassList<T>& getFreeListHead() { return mFreeListHead; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Implements a chunker which uses the data of another BaseDataChunker
|
/// Implements a chunker which uses the data of another BaseDataChunker
|
||||||
|
|
@ -390,6 +415,8 @@ public:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item.ptr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeBlocks(bool keepOne = false)
|
void freeBlocks(bool keepOne = false)
|
||||||
|
|
@ -398,4 +425,8 @@ public:
|
||||||
mT2.freeBlocks(keepOne);
|
mT2.freeBlocks(keepOne);
|
||||||
mT3.freeBlocks(keepOne);
|
mT3.freeBlocks(keepOne);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ClassChunker<K1>& getT1Chunker() { return mT1; }
|
||||||
|
inline ClassChunker<K2>& getT2Chunker() { return mT2; }
|
||||||
|
inline ClassChunker<K3>& getT3Chunker() { return mT3; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,18 @@ thread_local FrameAllocator::FrameAllocatorType FrameAllocator::smMainInstance
|
||||||
thread_local dsize_t FrameAllocator::smAllocatedBytes;
|
thread_local dsize_t FrameAllocator::smAllocatedBytes;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(TORQUE_DEBUG)
|
U32 FrameAllocator::smMaxFrameAllocation;
|
||||||
|
|
||||||
dsize_t FrameAllocator::smMaxFrameAllocation;
|
U32 FrameAllocator::getMaxFrameAllocation()
|
||||||
|
|
||||||
|
|
||||||
DefineEngineFunction(getMaxFrameAllocation, S32, (), , "")
|
|
||||||
{
|
{
|
||||||
return (S32)FrameAllocator::smMaxFrameAllocation;
|
return (S32)FrameAllocator::smMaxFrameAllocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(TORQUE_DEBUG)
|
||||||
|
|
||||||
|
DefineEngineFunction(getMaxFrameAllocation, S32, (), , "")
|
||||||
|
{
|
||||||
|
return (S32)FrameAllocator::getMaxFrameAllocation();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -103,11 +103,21 @@ public:
|
||||||
return (U32)(numBytes / sizeof(T));
|
return (U32)(numBytes / sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline U32 calcRequiredPaddedByteSize(const dsize_t numBytes)
|
||||||
|
{
|
||||||
|
return calcRequiredElementSize(numBytes) * sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
inline T* getAlignedBuffer() const
|
inline T* getAlignedBuffer() const
|
||||||
{
|
{
|
||||||
return mBuffer;
|
return mBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline T* getAlignedBufferEnd() const
|
||||||
|
{
|
||||||
|
return mBuffer + mHighWaterMark;
|
||||||
|
}
|
||||||
|
|
||||||
inline U32 getPosition() const
|
inline U32 getPosition() const
|
||||||
{
|
{
|
||||||
return mWaterMark;
|
return mWaterMark;
|
||||||
|
|
@ -153,7 +163,7 @@ public:
|
||||||
class FrameAllocator
|
class FrameAllocator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static dsize_t smMaxFrameAllocation;
|
static U32 smMaxFrameAllocation;
|
||||||
#ifdef TORQUE_MEM_DEBUG
|
#ifdef TORQUE_MEM_DEBUG
|
||||||
static thread_local dsize_t smAllocatedBytes;
|
static thread_local dsize_t smAllocatedBytes;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -220,6 +230,8 @@ public:
|
||||||
return smMainInstance.getSizeBytes();
|
return smMainInstance.getSizeBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static U32 getMaxFrameAllocation();
|
||||||
|
|
||||||
static thread_local FrameAllocatorType smMainInstance;
|
static thread_local FrameAllocatorType smMainInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -253,7 +265,7 @@ public:
|
||||||
FrameAllocator::setWaterMark(mMarker);
|
FrameAllocator::setWaterMark(mMarker);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* alloc(const U32 allocSize) const
|
void* alloc(const U32 allocSize)
|
||||||
{
|
{
|
||||||
return FrameAllocator::alloc(allocSize);
|
return FrameAllocator::alloc(allocSize);
|
||||||
}
|
}
|
||||||
|
|
@ -336,7 +348,7 @@ public:
|
||||||
const T& operator *() const { return *mMemory; }
|
const T& operator *() const { return *mMemory; }
|
||||||
|
|
||||||
T** operator &() { return &mMemory; }
|
T** operator &() { return &mMemory; }
|
||||||
const T** operator &() const { return &mMemory; }
|
T* const * operator &() const { return &mMemory; }
|
||||||
|
|
||||||
operator T* () { return mMemory; }
|
operator T* () { return mMemory; }
|
||||||
operator const T* () const { return mMemory; }
|
operator const T* () const { return mMemory; }
|
||||||
|
|
|
||||||
347
Engine/source/testing/dataChunkerTest.cpp
Normal file
347
Engine/source/testing/dataChunkerTest.cpp
Normal file
|
|
@ -0,0 +1,347 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2023-2024 tgemit contributors.
|
||||||
|
// See AUTHORS file and git repository for contributor information.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef TORQUE_TESTS_ENABLED
|
||||||
|
#include "testing/unitTesting.h"
|
||||||
|
#include "core/dataChunker.h"
|
||||||
|
|
||||||
|
struct TestClassChunkerStruct
|
||||||
|
{
|
||||||
|
U32 value;
|
||||||
|
U32 value2;
|
||||||
|
|
||||||
|
TestClassChunkerStruct()
|
||||||
|
{
|
||||||
|
value = 0xC001B33F;
|
||||||
|
value2 = 0x10101010;
|
||||||
|
}
|
||||||
|
|
||||||
|
~TestClassChunkerStruct()
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
value2 = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TEST(BaseDataChunkerTest, BaseDataChunker_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
BaseDataChunker<TestClassChunkerStruct> testChunks(1024);
|
||||||
|
BaseDataChunker<U32> testChunk4(1024);
|
||||||
|
BaseDataChunker<U64> testChunk8(1024);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunks.countUsedBlocks() == 0);
|
||||||
|
EXPECT_TRUE(testChunk4.countUsedBlocks() == 0);
|
||||||
|
EXPECT_TRUE(testChunk8.countUsedBlocks() == 0);
|
||||||
|
|
||||||
|
testChunks.alloc(1);
|
||||||
|
testChunk4.alloc(1);
|
||||||
|
testChunk8.alloc(1);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunks.countUsedBlocks() == 1);
|
||||||
|
EXPECT_TRUE(testChunk4.countUsedBlocks() == 1);
|
||||||
|
EXPECT_TRUE(testChunk8.countUsedBlocks() == 1);
|
||||||
|
|
||||||
|
testChunks.alloc(1);
|
||||||
|
testChunk4.alloc(1);
|
||||||
|
testChunk8.alloc(1);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunks.countUsedBlocks() == 1);
|
||||||
|
EXPECT_TRUE(testChunk4.countUsedBlocks() == 1);
|
||||||
|
EXPECT_TRUE(testChunk8.countUsedBlocks() == 1);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunks.countUsedBytes() == (sizeof(TestClassChunkerStruct) * 2));
|
||||||
|
EXPECT_TRUE(testChunk4.countUsedBytes() == (sizeof(U32) * 2));
|
||||||
|
EXPECT_TRUE(testChunk8.countUsedBytes() == (sizeof(U64) * 2));
|
||||||
|
|
||||||
|
testChunks.freeBlocks(true);
|
||||||
|
testChunk4.freeBlocks(true);
|
||||||
|
testChunk8.freeBlocks(true);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunks.countUsedBlocks() == 1);
|
||||||
|
EXPECT_TRUE(testChunk4.countUsedBlocks() == 1);
|
||||||
|
EXPECT_TRUE(testChunk8.countUsedBlocks() == 1);
|
||||||
|
|
||||||
|
testChunks.freeBlocks(false);
|
||||||
|
testChunk4.freeBlocks(false);
|
||||||
|
testChunk8.freeBlocks(false);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunks.countUsedBlocks() == 0);
|
||||||
|
EXPECT_TRUE(testChunk4.countUsedBlocks() == 0);
|
||||||
|
EXPECT_TRUE(testChunk8.countUsedBlocks() == 0);
|
||||||
|
|
||||||
|
testChunks.setChunkSize(sizeof(TestClassChunkerStruct));
|
||||||
|
testChunks.alloc(1);
|
||||||
|
EXPECT_TRUE(testChunks.countUsedBlocks() == 1);
|
||||||
|
testChunks.alloc(1);
|
||||||
|
EXPECT_TRUE(testChunks.countUsedBlocks() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DataChunkerTest, DataChunker_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
DataChunker testChunk(1024);
|
||||||
|
|
||||||
|
testChunk.alloc(1024);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 1);
|
||||||
|
|
||||||
|
testChunk.alloc(1024);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 2);
|
||||||
|
|
||||||
|
testChunk.alloc(4096);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBytes() == (1024+1024+4096));
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 3);
|
||||||
|
|
||||||
|
testChunk.alloc(12);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 4);
|
||||||
|
|
||||||
|
testChunk.alloc(12);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 4);
|
||||||
|
|
||||||
|
U32 reqEls = AlignedBufferAllocator<uintptr_t>::calcRequiredElementSize(12) * sizeof(uintptr_t);
|
||||||
|
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBytes() == (1024+1024+4096+reqEls+reqEls));
|
||||||
|
|
||||||
|
testChunk.freeBlocks(true);
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 1);
|
||||||
|
testChunk.freeBlocks(false);
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 0);
|
||||||
|
|
||||||
|
// Large block cases
|
||||||
|
|
||||||
|
testChunk.alloc(8192);
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 1);
|
||||||
|
testChunk.freeBlocks(true);
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 1);
|
||||||
|
|
||||||
|
testChunk.alloc(8192);
|
||||||
|
testChunk.alloc(1024);
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 2);
|
||||||
|
testChunk.freeBlocks(true);
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 1);
|
||||||
|
testChunk.freeBlocks(false);
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 0);
|
||||||
|
|
||||||
|
// Instead using the chunk size
|
||||||
|
|
||||||
|
for (U32 i=0; i<8; i++)
|
||||||
|
{
|
||||||
|
testChunk.alloc(1024);
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 8);
|
||||||
|
testChunk.freeBlocks(false);
|
||||||
|
EXPECT_TRUE(testChunk.countUsedBlocks() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ChunkerTest,Chunker_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
Chunker<TestClassChunkerStruct> foo;
|
||||||
|
TestClassChunkerStruct* value = foo.alloc();
|
||||||
|
EXPECT_TRUE(value->value != 0xC001B33F);
|
||||||
|
EXPECT_TRUE(value->value2 != 0x10101010);
|
||||||
|
// Should otherwise just act like DataChunker
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MultiTypedChunkerTest,MultiTypedChunker_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
struct TVS1
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
struct TVS2
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
int b;
|
||||||
|
int c;
|
||||||
|
};
|
||||||
|
MultiTypedChunker chunker;
|
||||||
|
TVS1* v1 = chunker.alloc<TVS1>();
|
||||||
|
TVS2* v2 = chunker.alloc<TVS2>();
|
||||||
|
TVS2* v3 = chunker.alloc<TVS2>();
|
||||||
|
|
||||||
|
EXPECT_TRUE(((U8*)v2) - ((U8*)v1) == sizeof(TVS1));
|
||||||
|
EXPECT_TRUE(((U8*)v3) - ((U8*)v2) == AlignedBufferAllocator<MultiTypedChunker::AlignmentType>::calcRequiredPaddedByteSize(sizeof(TVS2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ChunkerFreeClassListTest,ChunkerFreeClassList_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
TestClassChunkerStruct list[5];
|
||||||
|
ChunkerFreeClassList<TestClassChunkerStruct> freeListTest;
|
||||||
|
|
||||||
|
// Push & pop works as expected
|
||||||
|
EXPECT_TRUE(freeListTest.isEmpty() == true);
|
||||||
|
freeListTest.push((ChunkerFreeClassList<TestClassChunkerStruct>*)&list[0]);
|
||||||
|
EXPECT_TRUE(freeListTest.isEmpty() == false);
|
||||||
|
freeListTest.push((ChunkerFreeClassList<TestClassChunkerStruct>*)&list[4]);
|
||||||
|
EXPECT_TRUE(freeListTest.pop() == &list[4]);
|
||||||
|
EXPECT_TRUE(freeListTest.pop() == &list[0]);
|
||||||
|
EXPECT_TRUE(freeListTest.pop() == NULL);
|
||||||
|
|
||||||
|
// Reset clears list head
|
||||||
|
freeListTest.push((ChunkerFreeClassList<TestClassChunkerStruct>*)&list[4]);
|
||||||
|
freeListTest.reset();
|
||||||
|
EXPECT_TRUE(freeListTest.pop() == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(FreeListChunkerTest, FreeListChunkerTest_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
FreeListChunker<TestClassChunkerStruct> testFreeList;
|
||||||
|
|
||||||
|
TestClassChunkerStruct* s1 = testFreeList.alloc();
|
||||||
|
TestClassChunkerStruct* s2 = testFreeList.alloc();
|
||||||
|
|
||||||
|
// Allocation is sequential
|
||||||
|
EXPECT_TRUE(s2 > s1);
|
||||||
|
EXPECT_TRUE(((s2 - s1) == 1));
|
||||||
|
|
||||||
|
testFreeList.free(s1);
|
||||||
|
|
||||||
|
// But previous reallocations are reused
|
||||||
|
TestClassChunkerStruct* s3 = testFreeList.alloc();
|
||||||
|
TestClassChunkerStruct* s4 = testFreeList.alloc();
|
||||||
|
|
||||||
|
EXPECT_TRUE(s1 == s3);
|
||||||
|
EXPECT_TRUE(((s4 - s2) == 1)); // continues from previous free alloc
|
||||||
|
|
||||||
|
// Check sharing
|
||||||
|
|
||||||
|
FreeListChunker<TestClassChunkerStruct> sharedChunker(testFreeList.getChunker());
|
||||||
|
|
||||||
|
s2 = testFreeList.alloc();
|
||||||
|
EXPECT_TRUE(((s2 - s4) == 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ClassChunkerTest, ClassChunker_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
ClassChunker<TestClassChunkerStruct> testClassList;
|
||||||
|
|
||||||
|
TestClassChunkerStruct* s1 = testClassList.alloc();
|
||||||
|
TestClassChunkerStruct* s2 = testClassList.alloc();
|
||||||
|
|
||||||
|
// Allocation is sequential
|
||||||
|
EXPECT_TRUE(s2 > s1);
|
||||||
|
EXPECT_TRUE(((s2 - s1) == 1));
|
||||||
|
|
||||||
|
testClassList.free(s1);
|
||||||
|
EXPECT_TRUE(s1->value == 0);
|
||||||
|
EXPECT_TRUE(s1->value2 == 0);
|
||||||
|
|
||||||
|
// But previous reallocations are reused
|
||||||
|
TestClassChunkerStruct* s3 = testClassList.alloc();
|
||||||
|
TestClassChunkerStruct* s4 = testClassList.alloc();
|
||||||
|
|
||||||
|
EXPECT_TRUE(s1 == s3);
|
||||||
|
EXPECT_TRUE(((s4 - s2) == 1)); // continues from previous free alloc
|
||||||
|
|
||||||
|
// Values should be initialized correctly for all allocs at this point
|
||||||
|
EXPECT_TRUE(s1->value == 0xC001B33F);
|
||||||
|
EXPECT_TRUE(s1->value2 == 0x10101010);
|
||||||
|
EXPECT_TRUE(s2->value == 0xC001B33F);
|
||||||
|
EXPECT_TRUE(s2->value2 == 0x10101010);
|
||||||
|
EXPECT_TRUE(s3->value == 0xC001B33F);
|
||||||
|
EXPECT_TRUE(s3->value2 == 0x10101010);
|
||||||
|
EXPECT_TRUE(s4->value == 0xC001B33F);
|
||||||
|
EXPECT_TRUE(s4->value2 == 0x10101010);
|
||||||
|
|
||||||
|
// Should still be valid if using freeBlocks
|
||||||
|
testClassList.freeBlocks(true);
|
||||||
|
EXPECT_TRUE(s1->value == 0xC001B33F);
|
||||||
|
EXPECT_TRUE(s1->value2 == 0x10101010);
|
||||||
|
EXPECT_TRUE(s2->value == 0xC001B33F);
|
||||||
|
EXPECT_TRUE(s2->value2 == 0x10101010);
|
||||||
|
EXPECT_TRUE(s3->value == 0xC001B33F);
|
||||||
|
EXPECT_TRUE(s3->value2 == 0x10101010);
|
||||||
|
EXPECT_TRUE(s4->value == 0xC001B33F);
|
||||||
|
EXPECT_TRUE(s4->value2 == 0x10101010);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(ThreeTieredChunkerTest,ThreeTieredChunker_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
struct TThreeSA
|
||||||
|
{
|
||||||
|
uintptr_t a;
|
||||||
|
};
|
||||||
|
struct TThreeSB
|
||||||
|
{
|
||||||
|
uintptr_t a;
|
||||||
|
uintptr_t b;
|
||||||
|
};
|
||||||
|
struct TThreeSC
|
||||||
|
{
|
||||||
|
uintptr_t a;
|
||||||
|
uintptr_t b;
|
||||||
|
uintptr_t c;
|
||||||
|
};
|
||||||
|
struct TThreeSD
|
||||||
|
{
|
||||||
|
uintptr_t a;
|
||||||
|
uintptr_t b;
|
||||||
|
uintptr_t c;
|
||||||
|
uintptr_t d;
|
||||||
|
};
|
||||||
|
ThreeTieredChunker<TThreeSA, TThreeSB, TThreeSC> threeChunker;
|
||||||
|
|
||||||
|
// Alloc should alloc in the correct lists
|
||||||
|
|
||||||
|
auto h1 = threeChunker.alloc(sizeof(TThreeSA));
|
||||||
|
auto h2 = threeChunker.alloc(sizeof(TThreeSB));
|
||||||
|
auto h3 = threeChunker.alloc(sizeof(TThreeSC));
|
||||||
|
auto h4 = threeChunker.alloc(sizeof(TThreeSD));
|
||||||
|
|
||||||
|
EXPECT_TRUE(threeChunker.getT1Chunker().isManagedByChunker(h3.ptr) == false);
|
||||||
|
EXPECT_TRUE(threeChunker.getT2Chunker().isManagedByChunker(h3.ptr) == false);
|
||||||
|
EXPECT_TRUE(threeChunker.getT3Chunker().isManagedByChunker(h3.ptr) == true);
|
||||||
|
EXPECT_TRUE(h3.tier == 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(threeChunker.getT1Chunker().isManagedByChunker(h2.ptr) == false);
|
||||||
|
EXPECT_TRUE(threeChunker.getT2Chunker().isManagedByChunker(h2.ptr) == true);
|
||||||
|
EXPECT_TRUE(threeChunker.getT3Chunker().isManagedByChunker(h2.ptr) == false);
|
||||||
|
EXPECT_TRUE(h2.tier == 2);
|
||||||
|
|
||||||
|
EXPECT_TRUE(threeChunker.getT1Chunker().isManagedByChunker(h1.ptr) == true);
|
||||||
|
EXPECT_TRUE(threeChunker.getT2Chunker().isManagedByChunker(h1.ptr) == false);
|
||||||
|
EXPECT_TRUE(threeChunker.getT3Chunker().isManagedByChunker(h1.ptr) == false);
|
||||||
|
EXPECT_TRUE(h1.tier == 1);
|
||||||
|
|
||||||
|
EXPECT_TRUE(threeChunker.getT1Chunker().isManagedByChunker(h4.ptr) == false);
|
||||||
|
EXPECT_TRUE(threeChunker.getT2Chunker().isManagedByChunker(h4.ptr) == false);
|
||||||
|
EXPECT_TRUE(threeChunker.getT3Chunker().isManagedByChunker(h4.ptr) == false);
|
||||||
|
EXPECT_TRUE(h4.tier == 0);
|
||||||
|
|
||||||
|
threeChunker.free(h1);
|
||||||
|
threeChunker.free(h2);
|
||||||
|
threeChunker.free(h3);
|
||||||
|
threeChunker.free(h4);
|
||||||
|
|
||||||
|
EXPECT_TRUE(h1.ptr == NULL);
|
||||||
|
EXPECT_TRUE(h2.ptr == NULL);
|
||||||
|
EXPECT_TRUE(h3.ptr == NULL);
|
||||||
|
EXPECT_TRUE(h4.ptr == NULL);
|
||||||
|
|
||||||
|
// freeBlocks should also clear ALL the list heads
|
||||||
|
|
||||||
|
EXPECT_FALSE(threeChunker.getT1Chunker().getFreeListHead().isEmpty());
|
||||||
|
EXPECT_FALSE(threeChunker.getT2Chunker().getFreeListHead().isEmpty());
|
||||||
|
EXPECT_FALSE(threeChunker.getT3Chunker().getFreeListHead().isEmpty());
|
||||||
|
|
||||||
|
threeChunker.freeBlocks(false);
|
||||||
|
|
||||||
|
EXPECT_TRUE(threeChunker.getT1Chunker().getFreeListHead().isEmpty());
|
||||||
|
EXPECT_TRUE(threeChunker.getT2Chunker().getFreeListHead().isEmpty());
|
||||||
|
EXPECT_TRUE(threeChunker.getT3Chunker().getFreeListHead().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
195
Engine/source/testing/frameAllocatorTest.cpp
Normal file
195
Engine/source/testing/frameAllocatorTest.cpp
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2023-2024 tgemit contributors.
|
||||||
|
// See AUTHORS file and git repository for contributor information.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef TORQUE_TESTS_ENABLED
|
||||||
|
#include "testing/unitTesting.h"
|
||||||
|
#include "core/frameAllocator.h"
|
||||||
|
|
||||||
|
struct TestAlignmentStruct
|
||||||
|
{
|
||||||
|
U64 values[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(AlignedBufferAllocatorTest, AlignedBufferAllocator_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
AlignedBufferAllocator<U32> ba4;
|
||||||
|
AlignedBufferAllocator<U64> ba8;
|
||||||
|
AlignedBufferAllocator<TestAlignmentStruct> bas;
|
||||||
|
|
||||||
|
const U32 bufSize32 = (sizeof(TestAlignmentStruct) / 4) * 20;
|
||||||
|
U32 testAlignmentBuffer[bufSize32];
|
||||||
|
for (U32 i=0; i<bufSize32; i++)
|
||||||
|
{
|
||||||
|
testAlignmentBuffer[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(ba4.calcRequiredElementSize(20) == 5);
|
||||||
|
EXPECT_TRUE(ba8.calcRequiredElementSize(20) == 3);
|
||||||
|
EXPECT_TRUE(bas.calcRequiredElementSize(20) == 1);
|
||||||
|
EXPECT_TRUE(bas.calcRequiredElementSize(32) == 1);
|
||||||
|
EXPECT_TRUE(bas.calcRequiredElementSize(33) == 2);
|
||||||
|
EXPECT_TRUE(bas.calcRequiredElementSize(64) == 2);
|
||||||
|
|
||||||
|
|
||||||
|
EXPECT_TRUE(ba4.calcMaxElementSize(20) == 5);
|
||||||
|
EXPECT_TRUE(ba8.calcMaxElementSize(20) == 2);
|
||||||
|
EXPECT_TRUE(bas.calcMaxElementSize(20) == 0);
|
||||||
|
EXPECT_TRUE(bas.calcMaxElementSize(32) == 1);
|
||||||
|
EXPECT_TRUE(bas.calcMaxElementSize(33) == 1);
|
||||||
|
EXPECT_TRUE(bas.calcMaxElementSize(64) == 2);
|
||||||
|
|
||||||
|
ba4.initWithBytes((U32*)testAlignmentBuffer, sizeof(testAlignmentBuffer));
|
||||||
|
ba8.initWithBytes((U64*)testAlignmentBuffer, sizeof(testAlignmentBuffer));
|
||||||
|
bas.initWithBytes((TestAlignmentStruct*)testAlignmentBuffer, sizeof(testAlignmentBuffer));
|
||||||
|
|
||||||
|
EXPECT_TRUE(ba4.getElementsLeft() == 160);
|
||||||
|
EXPECT_TRUE(ba8.getElementsLeft() == 80);
|
||||||
|
EXPECT_TRUE(bas.getElementsLeft() == 20);
|
||||||
|
|
||||||
|
EXPECT_TRUE(ba4.getSizeBytes() == 640);
|
||||||
|
EXPECT_TRUE(ba8.getSizeBytes() == 640);
|
||||||
|
EXPECT_TRUE(bas.getSizeBytes() == 640);
|
||||||
|
|
||||||
|
EXPECT_TRUE(ba4.allocElements(1) == &testAlignmentBuffer[0]);
|
||||||
|
EXPECT_TRUE(ba4.getPosition() == 1);
|
||||||
|
EXPECT_TRUE(ba4.getPositionBytes() == 4);
|
||||||
|
EXPECT_TRUE(ba4.getElementsLeft() == 159);
|
||||||
|
|
||||||
|
EXPECT_TRUE(ba4.allocElements(7) == &testAlignmentBuffer[1]);
|
||||||
|
EXPECT_TRUE(ba4.getPosition() == 8);
|
||||||
|
EXPECT_TRUE(ba4.getPositionBytes() == 32);
|
||||||
|
EXPECT_TRUE(ba4.getElementsLeft() == 152);
|
||||||
|
|
||||||
|
ba4.setPosition(100);
|
||||||
|
|
||||||
|
EXPECT_TRUE(ba4.allocElements(1) == &testAlignmentBuffer[100]);
|
||||||
|
EXPECT_TRUE(ba4.getPosition() == 101);
|
||||||
|
EXPECT_TRUE(ba4.getPositionBytes() == 404);
|
||||||
|
EXPECT_TRUE(ba4.getElementsLeft() == 59);
|
||||||
|
|
||||||
|
ba4.setPosition(160);
|
||||||
|
EXPECT_TRUE(ba4.allocElements(1) == NULL);
|
||||||
|
EXPECT_TRUE(ba4.getPosition() == 160);
|
||||||
|
EXPECT_TRUE(ba4.getPositionBytes() == (160*4));
|
||||||
|
EXPECT_TRUE(ba4.getElementsLeft() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FrameAllocatorTest, FrameAllocator_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
// NOTE: assuming alloc and destroy already work
|
||||||
|
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == 0);
|
||||||
|
FrameAllocator::setWaterMark(100);
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == 100);
|
||||||
|
FrameAllocator::setWaterMark(104);
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == 104);
|
||||||
|
|
||||||
|
FrameAllocator::alloc(1);
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == 108);
|
||||||
|
FrameAllocator::alloc(5);
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == 116);
|
||||||
|
|
||||||
|
FrameAllocator::setWaterMark(0);
|
||||||
|
FrameAllocator::alloc(1);
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == 4);
|
||||||
|
|
||||||
|
FrameAllocator::setWaterMark(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(FrameAllocatorMarker, FrameAllocatorMarker_Should_Function_Correctly)
|
||||||
|
{
|
||||||
|
U32 markerValue = 0;
|
||||||
|
FrameAllocator::setWaterMark(8);
|
||||||
|
|
||||||
|
// Marker should act as a bookmark for the FrameAllocator
|
||||||
|
{
|
||||||
|
FrameAllocatorMarker marker;
|
||||||
|
FrameAllocator::alloc(100);
|
||||||
|
markerValue = FrameAllocator::getWaterMark();
|
||||||
|
EXPECT_TRUE(markerValue != 8);
|
||||||
|
marker.alloc(4);
|
||||||
|
EXPECT_TRUE(markerValue != FrameAllocator::getWaterMark());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Going out of scope sets watermark
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static U32 gFTDestructTest = 0;
|
||||||
|
|
||||||
|
TEST(FrameTempTest, FrameTempShould_Function_Correctly)
|
||||||
|
{
|
||||||
|
FrameAllocator::setWaterMark(0);
|
||||||
|
{
|
||||||
|
FrameTemp<TestAlignmentStruct> fooTemp(20);
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == sizeof(TestAlignmentStruct)*20);
|
||||||
|
EXPECT_TRUE(&fooTemp[0] == fooTemp.address());
|
||||||
|
EXPECT_TRUE((&fooTemp[1] - &fooTemp[0]) == 1);
|
||||||
|
EXPECT_TRUE(fooTemp.getObjectCount() == 20);
|
||||||
|
EXPECT_TRUE(fooTemp.size() == 20);
|
||||||
|
|
||||||
|
const FrameTemp<TestAlignmentStruct>& fooC = fooTemp;
|
||||||
|
EXPECT_TRUE(&fooC[0] == fooC.address());
|
||||||
|
EXPECT_TRUE((&fooC[1] - &fooC[0]) == 1);
|
||||||
|
EXPECT_TRUE(fooC.getObjectCount() == 20);
|
||||||
|
EXPECT_TRUE(fooC.size() == 20);
|
||||||
|
|
||||||
|
// Accessors should work
|
||||||
|
|
||||||
|
// Call the overloaded operators by name
|
||||||
|
TestAlignmentStruct& value = fooTemp.operator*();
|
||||||
|
TestAlignmentStruct** ptr = fooTemp.operator&();
|
||||||
|
const TestAlignmentStruct* constPtr = fooTemp.operator const TestAlignmentStruct * ();
|
||||||
|
TestAlignmentStruct& ref = fooTemp.operator TestAlignmentStruct & ();
|
||||||
|
const TestAlignmentStruct& constRef = fooTemp.operator const TestAlignmentStruct & ();
|
||||||
|
TestAlignmentStruct copy = fooTemp.operator TestAlignmentStruct();
|
||||||
|
|
||||||
|
EXPECT_TRUE(*ptr == fooTemp.address());
|
||||||
|
EXPECT_TRUE(&value == fooTemp.address());
|
||||||
|
EXPECT_TRUE(constPtr == fooTemp.address());
|
||||||
|
EXPECT_TRUE(&ref == fooTemp.address());
|
||||||
|
EXPECT_TRUE(&constRef == fooTemp.address());
|
||||||
|
EXPECT_TRUE(© != fooTemp.address());
|
||||||
|
|
||||||
|
// Same for fooC
|
||||||
|
const TestAlignmentStruct& Cvalue = fooC.operator*();
|
||||||
|
TestAlignmentStruct* const* Cptr = fooC.operator&();
|
||||||
|
const TestAlignmentStruct* CconstPtr = fooC.operator const TestAlignmentStruct * ();
|
||||||
|
const TestAlignmentStruct& CconstRef = fooC.operator const TestAlignmentStruct & ();
|
||||||
|
|
||||||
|
EXPECT_TRUE(*Cptr == fooC.address());
|
||||||
|
EXPECT_TRUE(&Cvalue == fooC.address());
|
||||||
|
EXPECT_TRUE(CconstPtr == fooC.address());
|
||||||
|
EXPECT_TRUE(&CconstRef == fooC.address());
|
||||||
|
EXPECT_TRUE(&ref == fooC.address());
|
||||||
|
EXPECT_TRUE(&constRef == fooC.address());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exiting scope sets watermark
|
||||||
|
EXPECT_TRUE(FrameAllocator::getWaterMark() == 0);
|
||||||
|
|
||||||
|
// Test the destructor actually gets called
|
||||||
|
|
||||||
|
struct FTDestructTest
|
||||||
|
{
|
||||||
|
~FTDestructTest()
|
||||||
|
{
|
||||||
|
gFTDestructTest++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
gFTDestructTest = 0;
|
||||||
|
FrameTemp<FTDestructTest> foo2Temp(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(gFTDestructTest == 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue