yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie HermaszewskaCorrect include dir for libslang (#5539)7b570feed

master
7.5 KiB266 linesraw
1// unit-test-free-list.cpp
2
3#include "../../source/core/slang-list.h"
4#include "../../source/core/slang-memory-arena.h"
5#include "../../source/core/slang-random-generator.h"
6#include "unit-test/slang-unit-test.h"
7
8#include <stdio.h>
9#include <stdlib.h>
10
11using namespace Slang;
12
13
14namespace // anonymous
15{
16
17struct Block
18{
19    void* m_data;
20    size_t m_size;
21    uint8_t m_value;
22};
23
24enum class TestMode
25{
26    eUnaligned,
27    eImplicitAligned, ///< Alignment is kept implicitly with Unaligned allocs of the right size
28    eDefaultAligned,
29    eExplicitAligned,
30    eCount,
31};
32
33} // namespace
34
35static size_t getAlignment(TestMode mode)
36{
37    switch (mode)
38    {
39    default:
40    case TestMode::eUnaligned:
41        return 1;
42    case TestMode::eExplicitAligned:
43        return 16;
44    case TestMode::eImplicitAligned:
45        return 32;
46    case TestMode::eDefaultAligned:
47        return MemoryArena::kMinAlignment;
48    }
49}
50
51static bool hasValueShort(const uint8_t* data, size_t size, uint8_t value)
52{
53    for (size_t i = 0; i < size; ++i)
54    {
55        if (data[i] != value)
56        {
57            return false;
58        }
59    }
60    return true;
61}
62
63static bool hasValue(const uint8_t* data, size_t size, uint8_t value)
64{
65    const size_t alignMask = sizeof(size_t) - 1;
66
67    if (size <= sizeof(size_t) * 2)
68    {
69        return hasValueShort(data, size, value);
70    }
71
72    if (size_t(data) & alignMask)
73    {
74        size_t firstSize = sizeof(size_t) - (size_t(data) & alignMask);
75        if (!hasValueShort(data, firstSize, value))
76        {
77            return false;
78        }
79        size -= firstSize;
80        data += firstSize;
81
82        assert((size_t(data) & alignMask) == 0);
83    }
84
85    // Now do the middle
86    size_t numWords = size / sizeof(size_t);
87
88    // Expand the byte up to a word size
89    size_t wordValue = (size_t(value) << 8) | value;
90    wordValue = (wordValue << 16) | wordValue;
91    wordValue = (sizeof(size_t) > 4) ? size_t((uint64_t(wordValue) << 32) | wordValue) : wordValue;
92
93    const size_t* wordData = (const size_t*)data;
94    for (size_t i = 0; i < numWords; ++i)
95    {
96        if (wordData[i] != wordValue)
97        {
98            return false;
99        }
100    }
101
102    // Do the end piece
103    return hasValueShort(data + sizeof(size_t) * numWords, size & alignMask, value);
104}
105
106SLANG_UNIT_TEST(memoryArena)
107{
108    DefaultRandomGenerator randGen(0x5346536a);
109
110    {
111        const size_t blockSize = 1024;
112        MemoryArena arena;
113        arena.init(blockSize);
114
115        List<void*> blocks;
116
117        blocks.add(arena.allocate(100));
118        blocks.add(arena.allocate(blockSize * 2));
119        blocks.add(arena.allocate(100));
120        blocks.add(arena.allocate(blockSize * 2));
121        blocks.add(arena.allocate(100));
122
123        arena.deallocateAll();
124        blocks.add(arena.allocate(100));
125        blocks.add(arena.allocate(blockSize * 2));
126
127        arena.reset();
128
129        {
130            uint32_t data[] = {1, 2, 3};
131
132            const uint32_t* copy = arena.allocateAndCopyArray(data, SLANG_COUNT_OF(data));
133
134            SLANG_CHECK(::memcmp(copy, data, sizeof(data)) == 0);
135        }
136    }
137
138    {
139        int count = 0;
140        const size_t blockSize = 1024;
141
142        for (TestMode mode = TestMode(0); int(mode) < int(TestMode::eCount);
143             mode = TestMode(int(mode) + 1))
144        {
145            const size_t alignment = getAlignment(mode);
146
147            MemoryArena arena;
148            arena.init(blockSize, alignment);
149
150            List<Block> blocks;
151
152            for (int i = 0; i < 10000; i++)
153            {
154                count++;
155
156                const int var = randGen.nextInt32() & 0x3ff;
157                if (var < 3 && blocks.getCount() > 0)
158                {
159                    if (var == 1)
160                    {
161                        // Deallocate everything
162                        arena.deallocateAll();
163                        blocks.clear();
164                    }
165                    else if (var == 2)
166                    {
167                        arena.reset();
168                        blocks.clear();
169                    }
170                    else if (var == 3)
171                    {
172                        arena.rewindToCursor(nullptr);
173                        blocks.clear();
174                    }
175                    else if (var == 4)
176                    {
177                        // Rewind to a random position
178                        int rewindIndex = randGen.nextInt32UpTo(int32_t(blocks.getCount()));
179                        // rewind to this block
180                        arena.rewindToCursor(blocks[rewindIndex].m_data);
181                        // All the blocks (includign this one) and now deallocated
182                        blocks.setCount(rewindIndex);
183                    }
184                    else
185                    {
186                        size_t usedMemory = arena.calcTotalMemoryUsed();
187                        size_t allocatedMemory = arena.calcTotalMemoryAllocated();
188
189                        SLANG_CHECK(allocatedMemory >= usedMemory);
190                    }
191                }
192                else
193                {
194                    size_t sizeInBytes = (randGen.nextInt32() & 255) + 1;
195
196                    // Lets go for an oversized block
197                    if ((randGen.nextInt32() & 0xff) < 2)
198                    {
199                        sizeInBytes += blockSize;
200                    }
201                    else if ((randGen.nextInt32() & 0xff) < 2)
202                    {
203                        // Let's try for a block that's awkwardly sized
204                        sizeInBytes = blockSize / 3 + 10;
205                    }
206
207                    const uint8_t value = uint8_t(randGen.nextInt32());
208
209                    void* mem = nullptr;
210                    switch (mode)
211                    {
212                    default:
213                    case TestMode::eUnaligned:
214                        {
215                            mem = arena.allocateUnaligned(sizeInBytes);
216                            break;
217                        }
218                    case TestMode::eImplicitAligned:
219                        {
220                            // Fix the size to get implicit alignment
221                            sizeInBytes = (sizeInBytes & ~(alignment - 1)) + alignment;
222                            mem = arena.allocateUnaligned(sizeInBytes);
223                            break;
224                        }
225                    case TestMode::eExplicitAligned:
226                        {
227                            mem = arena.allocateAligned(sizeInBytes, alignment);
228                            break;
229                        }
230                    case TestMode::eDefaultAligned:
231                        {
232                            mem = arena.allocate(sizeInBytes);
233                            break;
234                        }
235                    }
236
237                    // Check it is aligned
238                    SLANG_CHECK((size_t(mem) & (alignment - 1)) == 0);
239
240                    ::memset(mem, value, sizeInBytes);
241
242                    Block block;
243
244                    block.m_data = mem;
245                    block.m_size = sizeInBytes;
246                    block.m_value = value;
247
248                    blocks.add(block);
249                }
250
251                // Check the blocks
252                for (Index j = 0; j < blocks.getCount(); ++j)
253                {
254                    const Block& block = blocks[j];
255
256                    SLANG_CHECK(arena.isValid(block.m_data, block.m_size));
257
258                    SLANG_CHECK(hasValue((uint8_t*)block.m_data, block.m_size, block.m_value));
259                }
260            }
261        }
262    }
263    {
264        // Do lots of allocations and test out rewind
265    }
266}