summaryrefslogtreecommitdiff
path: root/tools/slang-unit-test/unit-test-memory-arena.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-09-24 11:33:44 -0700
committerGitHub <noreply@github.com>2021-09-24 11:33:44 -0700
commitbec8e6aec85b6e3f875c58bdd59eb15613978358 (patch)
tree0791fb2ce1be786c17e5a6ee489ed3065fc07332 /tools/slang-unit-test/unit-test-memory-arena.cpp
parentf2a3c933bc11a498c622fa18694c84beca8ca031 (diff)
Move existing unit tests to a standalone dll. (#1945)
Diffstat (limited to 'tools/slang-unit-test/unit-test-memory-arena.cpp')
-rw-r--r--tools/slang-unit-test/unit-test-memory-arena.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/tools/slang-unit-test/unit-test-memory-arena.cpp b/tools/slang-unit-test/unit-test-memory-arena.cpp
new file mode 100644
index 000000000..b2671160a
--- /dev/null
+++ b/tools/slang-unit-test/unit-test-memory-arena.cpp
@@ -0,0 +1,271 @@
+// unit-test-free-list.cpp
+
+#include "../../source/core/slang-memory-arena.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tools/unit-test/slang-unit-test.h"
+
+#include "../../source/core/slang-random-generator.h"
+#include "../../source/core/slang-list.h"
+
+using namespace Slang;
+
+
+namespace // anonymous
+{
+
+struct Block
+{
+ void* m_data;
+ size_t m_size;
+ uint8_t m_value;
+};
+
+enum class TestMode
+{
+ eUnaligned,
+ eImplicitAligned, ///< Alignment is kept implicitly with Unaligned allocs of the right size
+ eDefaultAligned,
+ eExplicitAligned,
+ eCount,
+};
+
+} // anonymous
+
+static size_t getAlignment(TestMode mode)
+{
+ switch (mode)
+ {
+ default:
+ case TestMode::eUnaligned:
+ return 1;
+ case TestMode::eExplicitAligned:
+ return 16;
+ case TestMode::eImplicitAligned:
+ return 32;
+ case TestMode::eDefaultAligned:
+ return MemoryArena::kMinAlignment;
+ }
+}
+
+static bool hasValueShort(const uint8_t* data, size_t size, uint8_t value)
+{
+ for (size_t i = 0; i < size; ++i)
+ {
+ if (data[i] != value)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool hasValue(const uint8_t* data, size_t size, uint8_t value)
+{
+ const size_t alignMask = sizeof(size_t) - 1;
+
+ if (size <= sizeof(size_t) * 2)
+ {
+ return hasValueShort(data, size, value);
+ }
+
+ if (size_t(data) & alignMask)
+ {
+ size_t firstSize = sizeof(size_t) - (size_t(data) & alignMask);
+ if (!hasValueShort(data, firstSize, value))
+ {
+ return false;
+ }
+ size -= firstSize;
+ data += firstSize;
+
+ assert((size_t(data) & alignMask) == 0);
+ }
+
+ // Now do the middle
+ size_t numWords = size / sizeof(size_t);
+
+ // Expand the byte up to a word size
+ size_t wordValue = (size_t(value) << 8) | value;
+ wordValue = (wordValue << 16) | wordValue;
+ wordValue = (sizeof(size_t) > 4) ? size_t((uint64_t(wordValue) << 32) | wordValue) : wordValue;
+
+ const size_t* wordData = (const size_t*)data;
+ for (size_t i = 0; i < numWords; ++i)
+ {
+ if (wordData[i] != wordValue)
+ {
+ return false;
+ }
+ }
+
+ // Do the end piece
+ return hasValueShort(data + sizeof(size_t) * numWords, size & alignMask, value);
+}
+
+SLANG_UNIT_TEST(memoryArena)
+{
+ DefaultRandomGenerator randGen(0x5346536a);
+
+ {
+ const size_t blockSize = 1024;
+ MemoryArena arena;
+ arena.init(blockSize);
+
+ List<void*> blocks;
+
+ blocks.add(arena.allocate(100));
+ blocks.add(arena.allocate(blockSize * 2));
+ blocks.add(arena.allocate(100));
+ blocks.add(arena.allocate(blockSize * 2));
+ blocks.add(arena.allocate(100));
+
+ arena.deallocateAll();
+ blocks.add(arena.allocate(100));
+ blocks.add(arena.allocate(blockSize * 2));
+
+ arena.reset();
+
+ {
+ uint32_t data[] = { 1, 2, 3 };
+
+ const uint32_t* copy = arena.allocateAndCopyArray(data, SLANG_COUNT_OF(data));
+
+ SLANG_CHECK(::memcmp(copy, data, sizeof(data)) == 0);
+ }
+ }
+
+ {
+ int count = 0;
+ const size_t blockSize = 1024;
+
+ for (TestMode mode = TestMode(0); int(mode) < int(TestMode::eCount); mode = TestMode(int(mode) + 1))
+ {
+ const size_t alignment = getAlignment(mode);
+
+ MemoryArena arena;
+ arena.init(blockSize, alignment);
+
+ List<Block> blocks;
+
+ for (int i = 0; i < 10000; i++)
+ {
+ count++;
+
+ const int var = randGen.nextInt32() & 0x3ff;
+ if (var < 3 && blocks.getCount() > 0)
+ {
+ if (var == 1)
+ {
+ // Deallocate everything
+ arena.deallocateAll();
+ blocks.clear();
+ }
+ else if (var == 2)
+ {
+ arena.reset();
+ blocks.clear();
+ }
+ else if (var == 3)
+ {
+ arena.rewindToCursor(nullptr);
+ blocks.clear();
+ }
+ else if (var == 4)
+ {
+ // Rewind to a random position
+ int rewindIndex = randGen.nextInt32UpTo(int32_t(blocks.getCount()));
+ // rewind to this block
+ arena.rewindToCursor(blocks[rewindIndex].m_data);
+ // All the blocks (includign this one) and now deallocated
+ blocks.setCount(rewindIndex);
+
+ }
+ else
+ {
+ size_t usedMemory = arena.calcTotalMemoryUsed();
+ size_t allocatedMemory = arena.calcTotalMemoryAllocated();
+
+ SLANG_CHECK(allocatedMemory >= usedMemory);
+ }
+ }
+ else
+ {
+ size_t sizeInBytes = (randGen.nextInt32() & 255) + 1;
+
+ // Lets go for an oversized block
+ if ((randGen.nextInt32() & 0xff) < 2)
+ {
+ sizeInBytes += blockSize;
+ }
+ else if ((randGen.nextInt32() & 0xff) < 2)
+ {
+ // Let's try for a block that's awkwardly sized
+ sizeInBytes = blockSize / 3 + 10;
+ }
+
+ const uint8_t value = uint8_t(randGen.nextInt32());
+
+ void* mem = nullptr;
+ switch (mode)
+ {
+ default:
+ case TestMode::eUnaligned:
+ {
+ mem = arena.allocateUnaligned(sizeInBytes);
+ break;
+ }
+ case TestMode::eImplicitAligned:
+ {
+ // Fix the size to get implicit alignment
+ sizeInBytes = (sizeInBytes & ~(alignment - 1)) + alignment;
+ mem = arena.allocateUnaligned(sizeInBytes);
+ break;
+ }
+ case TestMode::eExplicitAligned:
+ {
+ mem = arena.allocateAligned(sizeInBytes, alignment);
+ break;
+ }
+ case TestMode::eDefaultAligned:
+ {
+ mem = arena.allocate(sizeInBytes);
+ break;
+ }
+ }
+
+ // Check it is aligned
+ SLANG_CHECK((size_t(mem) & (alignment - 1)) == 0);
+
+ ::memset(mem, value, sizeInBytes);
+
+ Block block;
+
+ block.m_data = mem;
+ block.m_size = sizeInBytes;
+ block.m_value = value;
+
+ blocks.add(block);
+ }
+
+ // Check the blocks
+ for (Index j = 0; j < blocks.getCount(); ++j)
+ {
+ const Block& block = blocks[j];
+
+ SLANG_CHECK(arena.isValid(block.m_data, block.m_size));
+
+ SLANG_CHECK(hasValue((uint8_t*)block.m_data, block.m_size, block.m_value));
+ }
+ }
+ }
+ }
+ {
+ // Do lots of allocations and test out rewind
+
+
+
+ }
+}