Skip to content

Commit 3bb224b

Browse files
committed
Simplify memory arena page layout
1 parent db4e6f5 commit 3bb224b

3 files changed

Lines changed: 67 additions & 92 deletions

File tree

src/Foundations/SystemMemory.cpp

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,17 @@ struct PageSizeIndexes
4646
thread_local MemoryArenaStorage* stackMemoryArenaStorage = nullptr;
4747
size_t systemPageSizeInBytes = 0;
4848

49+
void PopStackMemory(MemoryArena memoryArena, size_t sizeInBytes);
50+
size_t ResizeToPageSizeMultiple(size_t sizeInBytes, size_t pageSizeInBytes);
51+
4952
PageSizeIndexes ComputePageSizeInfoIndexes(MemoryArenaStorage* storage, void* pointer, size_t sizeInBytes)
5053
{
51-
auto offset = (uint8_t*)pointer - (uint8_t*)storage;
54+
auto dataStart = (uint8_t*)storage + storage->HeaderSizeInBytes;
55+
auto offset = (uint8_t*)pointer - dataStart;
5256

5357
PageSizeIndexes result = {};
5458
result.StartIndex = offset / systemPageSizeInBytes;
55-
result.EndIndex = (size_t)SystemRoundUp((float)(offset + sizeInBytes) / systemPageSizeInBytes);
59+
result.EndIndex = ResizeToPageSizeMultiple(offset + sizeInBytes, systemPageSizeInBytes) / systemPageSizeInBytes;
5660
return result;
5761
}
5862

@@ -61,7 +65,7 @@ PageSizeIndexes ComputePageSizeLocalOffsets(MemoryArenaStorage* storage, size_t
6165
auto absoluteStart = (uint8_t*)pointer;
6266
auto absoluteEnd = (uint8_t*)pointer + sizeInBytes;
6367

64-
auto pageStart = (uint8_t*)storage + index * systemPageSizeInBytes;
68+
auto pageStart = (uint8_t*)storage + storage->HeaderSizeInBytes + index * systemPageSizeInBytes;
6569
auto pageEnd = pageStart + systemPageSizeInBytes;
6670

6771
PageSizeIndexes result = {};
@@ -104,45 +108,32 @@ MemoryArenaStorage* AllocateMemoryArenaStorage(size_t sizeInBytes)
104108
systemPageSizeInBytes = SystemPlatformGetPageSize();
105109
}
106110

107-
auto pageInfosCount = SystemRoundUp((float)sizeInBytes / (float)systemPageSizeInBytes);
108-
auto headerSizeInBytes = sizeof(MemoryArenaStorage) + pageInfosCount * sizeof(MemoryArenaPageInfo) + SystemRoundUp((float)pageInfosCount / 32) * sizeof(MemoryArenaPageCommitInfo);
109-
110-
auto sizeResized = ResizeToPageSizeMultiple(headerSizeInBytes + sizeInBytes, systemPageSizeInBytes);
111-
auto storage = (MemoryArenaStorage*)SystemPlatformReserveMemory(sizeResized);
111+
auto dataSizeInBytes = ResizeToPageSizeMultiple(sizeInBytes, systemPageSizeInBytes);
112+
auto pageInfosCount = dataSizeInBytes / systemPageSizeInBytes;
113+
auto pageCommitInfosCount = (pageInfosCount + 31) / 32;
114+
auto headerMetadataSizeInBytes = sizeof(MemoryArenaStorage) + pageInfosCount * sizeof(MemoryArenaPageInfo) + pageCommitInfosCount * sizeof(MemoryArenaPageCommitInfo);
115+
auto headerSizeInBytes = ResizeToPageSizeMultiple(headerMetadataSizeInBytes, systemPageSizeInBytes);
116+
auto reservedSizeInBytes = headerSizeInBytes + dataSizeInBytes;
112117

113-
auto headerResized = ResizeToPageSizeMultiple(headerSizeInBytes, systemPageSizeInBytes);
114-
SystemPlatformCommitMemory(storage, headerResized);
118+
auto storage = (MemoryArenaStorage*)SystemPlatformReserveMemory(reservedSizeInBytes);
119+
SystemPlatformCommitMemory(storage, headerSizeInBytes);
115120

116121
storage->CurrentPointer = (uint8_t*)storage + headerSizeInBytes;
117122
storage->SizeInBytes = sizeInBytes;
118123
storage->HeaderSizeInBytes = headerSizeInBytes;
119124
storage->IsCommitOperationInProgres = false;
120-
storage->CommittedPagesCount = 0;
125+
storage->CommittedPagesCount = headerSizeInBytes / systemPageSizeInBytes;
121126
storage->PagesInfos = (MemoryArenaPageInfo*)((uint8_t*)storage + sizeof(MemoryArenaStorage));
122127
storage->PagesCommitInfos = (MemoryArenaPageCommitInfo*)((uint8_t*)storage + sizeof(MemoryArenaStorage) + pageInfosCount * sizeof(MemoryArenaPageInfo));
123128
storage->StackExtraStorage = {};
124129
storage->StackLevel = 0;
125130
storage->StackMinAllocatedLevel = 255;
126131

127-
auto headerPageCount = (size_t)SystemRoundUp((float)headerResized / systemPageSizeInBytes);
128-
129-
for (size_t i = 0; i < (size_t)pageInfosCount; i++)
132+
for (size_t i = 0; i < pageInfosCount; i++)
130133
{
131-
if (headerPageCount > i)
132-
{
133-
auto offsets = ComputePageSizeLocalOffsets(storage, i, storage, headerSizeInBytes);
134-
135-
SetPageCommitted(storage, (uint32_t)i);
136-
storage->CommittedPagesCount++;
137-
storage->PagesInfos[i].MinCommittedOffset = offsets.StartIndex;
138-
storage->PagesInfos[i].MaxCommittedOffset = offsets.EndIndex;
139-
}
140-
else
141-
{
142-
ClearPageCommitted(storage, (uint32_t)i);
143-
storage->PagesInfos[i].MinCommittedOffset = systemPageSizeInBytes - 1;
144-
storage->PagesInfos[i].MaxCommittedOffset = 0;
145-
}
134+
ClearPageCommitted(storage, (uint32_t)i);
135+
storage->PagesInfos[i].MinCommittedOffset = systemPageSizeInBytes - 1;
136+
storage->PagesInfos[i].MaxCommittedOffset = 0;
146137
}
147138

148139
return storage;
@@ -167,6 +158,17 @@ MemoryArena GetStackWorkingMemoryArena(MemoryArena memoryArena)
167158
return workingMemoryArena;
168159
}
169160

161+
bool IsStackMemoryArena(MemoryArena memoryArena)
162+
{
163+
if (stackMemoryArenaStorage == nullptr)
164+
{
165+
return false;
166+
}
167+
168+
return memoryArena.Storage == stackMemoryArenaStorage ||
169+
(stackMemoryArenaStorage->StackExtraStorage.Storage != nullptr && memoryArena.Storage == stackMemoryArenaStorage->StackExtraStorage.Storage);
170+
}
171+
170172
size_t GetMemoryArenaAllocatedBytes(MemoryArena memoryArena)
171173
{
172174
return memoryArena.Storage->CurrentPointer - (uint8_t*)memoryArena.Storage - memoryArena.Storage->HeaderSizeInBytes;
@@ -198,12 +200,27 @@ MemoryArena SystemAllocateMemoryArena(size_t sizeInBytes)
198200

199201
void SystemFreeMemoryArena(MemoryArena memoryArena)
200202
{
201-
SystemPlatformFreeMemory(memoryArena.Storage, memoryArena.Storage->HeaderSizeInBytes + memoryArena.Storage->SizeInBytes);
203+
auto dataSizeInBytes = ResizeToPageSizeMultiple(memoryArena.Storage->SizeInBytes, systemPageSizeInBytes);
204+
SystemPlatformFreeMemory(memoryArena.Storage, memoryArena.Storage->HeaderSizeInBytes + dataSizeInBytes);
202205
}
203206

204207
void SystemClearMemoryArena(MemoryArena memoryArena)
205208
{
206-
SystemPopMemory(memoryArena, GetMemoryArenaAllocatedBytes(memoryArena));
209+
auto storage = memoryArena.Storage;
210+
auto allocatedSize = GetMemoryArenaAllocatedBytes(memoryArena);
211+
212+
if (allocatedSize == 0)
213+
{
214+
return;
215+
}
216+
217+
auto pointer = storage->CurrentPointer;
218+
storage->CurrentPointer -= allocatedSize;
219+
220+
if (memoryArena.Storage != stackMemoryArenaStorage)
221+
{
222+
SystemDecommitMemory(memoryArena, pointer - allocatedSize, allocatedSize);
223+
}
207224
}
208225

209226
MemoryArenaAllocationInfos SystemGetMemoryArenaAllocationInfos(MemoryArena memoryArena)
@@ -253,7 +270,7 @@ StackMemoryArena::~StackMemoryArena()
253270

254271
if (extraBytesToPop && storage->StackMinAllocatedLevel >= Arena.Level)
255272
{
256-
SystemPopMemory(storage->StackExtraStorage, extraBytesToPop);
273+
PopStackMemory(storage->StackExtraStorage, extraBytesToPop);
257274
storage->StackMinAllocatedLevel = 255;
258275
}
259276
}
@@ -264,7 +281,7 @@ StackMemoryArena::~StackMemoryArena()
264281

265282
if (bytesToPop > 0)
266283
{
267-
SystemPopMemory(Arena, bytesToPop);
284+
PopStackMemory(Arena, bytesToPop);
268285
}
269286
}
270287

@@ -330,11 +347,12 @@ void SystemCommitMemory(MemoryArena memoryArena, void* pointer, size_t sizeInByt
330347
{
331348
if (!IsPageCommitted(storage, (uint32_t)i))
332349
{
333-
SystemPlatformCommitMemory((uint8_t*)storage + i * systemPageSizeInBytes, systemPageSizeInBytes);
350+
auto pagePointer = (uint8_t*)storage + storage->HeaderSizeInBytes + i * systemPageSizeInBytes;
351+
SystemPlatformCommitMemory(pagePointer, systemPageSizeInBytes);
334352

335353
if (clearMemory)
336354
{
337-
SystemPlatformClearMemory((uint8_t*)storage + i * systemPageSizeInBytes, systemPageSizeInBytes);
355+
SystemPlatformClearMemory(pagePointer, systemPageSizeInBytes);
338356
}
339357

340358
SetPageCommitted(storage, (uint32_t)i);
@@ -404,7 +422,7 @@ void SystemDecommitMemory(MemoryArena memoryArena, void* pointer, size_t sizeInB
404422

405423
if (IsPageCommitted(storage, (uint32_t)i))
406424
{
407-
auto pagePointer = (uint8_t*)storage + i * systemPageSizeInBytes;
425+
auto pagePointer = (uint8_t*)storage + storage->HeaderSizeInBytes + i * systemPageSizeInBytes;
408426

409427
if ((int32_t)(pageInfos->MaxCommittedOffset - pageInfos->MinCommittedOffset) <= 0)
410428
{
@@ -455,14 +473,16 @@ void* SystemPushMemory(MemoryArena memoryArena, size_t sizeInBytes, AllocationSt
455473
return pointer;
456474
}
457475

458-
void SystemPopMemory(MemoryArena memoryArena, size_t sizeInBytes)
476+
void PopStackMemory(MemoryArena memoryArena, size_t sizeInBytes)
459477
{
478+
SystemAssert(IsStackMemoryArena(memoryArena));
479+
460480
auto storage = memoryArena.Storage;
461481
auto allocatedSize = GetMemoryArenaAllocatedBytes(memoryArena);
462482

463483
if (sizeInBytes > allocatedSize)
464484
{
465-
SystemLogErrorMessage(ElemLogMessageCategory_Memory, "Cannot pop memory arena with: %u (Allocated size is: %u)", (uint32_t)sizeInBytes, (uint32_t)allocatedSize);
485+
SystemLogErrorMessage(ElemLogMessageCategory_Memory, "Cannot pop stack memory arena with: %u (Allocated size is: %u)", (uint32_t)sizeInBytes, (uint32_t)allocatedSize);
466486
return;
467487
}
468488

src/Foundations/SystemMemory.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ void SystemFreeMemoryArena(MemoryArena memoryArena);
107107

108108
/**
109109
* Clears the contents of a MemoryArena.
110+
* This operation is not thread-safe and requires exclusive access to the arena.
110111
* @param memoryArena Pointer to the MemoryArena to be cleared.
111112
*/
112113
void SystemClearMemoryArena(MemoryArena memoryArena);
@@ -133,13 +134,6 @@ StackMemoryArena SystemGetStackMemoryArena();
133134
*/
134135
void* SystemPushMemory(MemoryArena memoryArena, size_t sizeInBytes, AllocationState state = AllocationState_Committed);
135136

136-
/**
137-
* Frees a block of memory in a MemoryArena.
138-
* @param memoryArena MemoryArena containing the block.
139-
* @param sizeInBytes Size of the memory block to free.
140-
*/
141-
void SystemPopMemory(MemoryArena memoryArena, size_t sizeInBytes);
142-
143137
/**
144138
* Commits a block of memory in a MemoryArena.
145139
*

tests/FoundationsTests/MemoryTests.cpp

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@ void MemoryConcurrentAddFunction(void* parameter)
1919
}
2020
}
2121

22-
void MemoryConcurrentPopFunction(void* parameter)
23-
{
24-
auto threadParameter = (MemoryThreadParameter*)parameter;
25-
26-
for (int32_t i = 0; i < threadParameter->ItemCount; i++)
27-
{
28-
SystemPopMemory(threadParameter->MemoryArena, 64);
29-
}
30-
}
31-
3222
UTEST(Memory, Allocate)
3323
{
3424
// Arrange
@@ -53,23 +43,24 @@ UTEST(Memory, AllocateMultiple)
5343
// Act
5444
SystemPushArrayZero<uint8_t>(memoryArena, dataSizeInBytes);
5545
SystemPushArrayZero<uint8_t>(memoryArena, 1024);
56-
SystemPopMemory(memoryArena, 20000);
5746

5847
// Assert
5948
auto allocationInfos = SystemGetMemoryArenaAllocationInfos(memoryArena);
60-
ASSERT_EQ(dataSizeInBytes + 1024 - 20000, allocationInfos.AllocatedBytes);
49+
ASSERT_EQ(dataSizeInBytes + 1024, allocationInfos.AllocatedBytes);
6150
ASSERT_GT(allocationInfos.CommittedBytes, allocationInfos.AllocatedBytes);
6251
}
6352

64-
UTEST(Memory, AllocatePop)
53+
UTEST(Memory, ClearMemoryArena)
6554
{
6655
// Arrange
6756
auto memoryArena = SystemAllocateMemoryArena();
68-
auto dataSizeInBytes = 64llu;
69-
57+
auto dataSizeInBytes = 70024llu;
58+
59+
SystemPushArrayZero<uint8_t>(memoryArena, dataSizeInBytes);
60+
SystemPushArrayZero<uint8_t>(memoryArena, 1024);
61+
7062
// Act
71-
SystemPushArrayZero<uint8_t>(memoryArena, dataSizeInBytes);
72-
SystemPopMemory(memoryArena, dataSizeInBytes);
63+
SystemClearMemoryArena(memoryArena);
7364

7465
// Assert
7566
auto allocationInfos = SystemGetMemoryArenaAllocationInfos(memoryArena);
@@ -237,36 +228,6 @@ UTEST(Memory, ConcurrentPush)
237228
ASSERT_EQ(maxSize, allocationInfos.AllocatedBytes);
238229
}
239230

240-
UTEST(Memory, ConcurrentPop)
241-
{
242-
// Arrange
243-
const int32_t itemCount = 80000;
244-
const int32_t threadCount = 32;
245-
auto maxSize = (size_t)itemCount * 64;
246-
auto memoryArena = SystemAllocateMemoryArena(maxSize);
247-
SystemPushMemory(memoryArena, maxSize);
248-
249-
// Act
250-
SystemThread threads[threadCount];
251-
MemoryThreadParameter threadParameters[threadCount];
252-
253-
for (int32_t i = 0; i < threadCount; i++)
254-
{
255-
threadParameters[i] = { memoryArena, i, itemCount / threadCount };
256-
threads[i] = SystemCreateThread(MemoryConcurrentPopFunction, &threadParameters[i]);
257-
}
258-
259-
for (int32_t i = 0; i < threadCount; i++)
260-
{
261-
SystemWaitThread(threads[i]);
262-
SystemFreeThread(threads[i]);
263-
}
264-
265-
// Assert
266-
auto allocationInfos = SystemGetMemoryArenaAllocationInfos(memoryArena);
267-
ASSERT_EQ(0llu, allocationInfos.AllocatedBytes);
268-
}
269-
270231
UTEST(Memory, AllocateReserved)
271232
{
272233
// Arrange

0 commit comments

Comments
 (0)