MemoryArena updates using Gemini. Add some debug tag so we can debug memory allocations

This commit is contained in:
2026-01-20 22:16:04 -05:00
parent d2b91c46d4
commit 0687ce5af1
2 changed files with 78 additions and 13 deletions

View File

@@ -12,11 +12,27 @@ namespace Juliet
uint8* Data; uint8* Data;
size_t Size; size_t Size;
size_t Offset; size_t Offset;
#if JULIET_DEBUG
struct AllocationInfo
{
size_t Offset;
size_t Size;
const char* Tag;
};
// Use a simple array for now to avoid std::vector dependency in the header or complex management
// Ideally this should be a linked list or similar
static constexpr size_t kMaxAllocations = 4096;
AllocationInfo Allocations[kMaxAllocations];
size_t AllocationCount = 0;
#endif
}; };
JULIET_API void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size); JULIET_API void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size);
JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment = 16); JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment = 16, const char* tag = nullptr);
JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment = 16);
JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment = 16, const char* tag = nullptr);
JULIET_API void ArenaReset(MemoryArena* arena); JULIET_API void ArenaReset(MemoryArena* arena);
JULIET_API size_t ArenaGetMarker(MemoryArena* arena); JULIET_API size_t ArenaGetMarker(MemoryArena* arena);
JULIET_API void ArenaResetToMarker(MemoryArena* arena, size_t marker); JULIET_API void ArenaResetToMarker(MemoryArena* arena, size_t marker);
@@ -39,9 +55,10 @@ namespace Juliet
void MemoryArenasShutdown(); void MemoryArenasShutdown();
template <typename T> template <typename T>
inline T* ArenaPushType(MemoryArena* arena) inline T* ArenaPushType(MemoryArena* arena, const char* tag = nullptr)
{ {
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T), alignof(T))); T* result = static_cast<T*>(ArenaPush(arena, sizeof(T), alignof(T), tag));
if (result) if (result)
{ {
MemSet(result, 0, sizeof(T)); MemSet(result, 0, sizeof(T));
@@ -50,9 +67,10 @@ namespace Juliet
} }
template <typename T> template <typename T>
inline T* ArenaPushArray(MemoryArena* arena, size_t count) inline T* ArenaPushArray(MemoryArena* arena, size_t count, const char* tag = nullptr)
{ {
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T) * count, alignof(T))); T* result = static_cast<T*>(ArenaPush(arena, sizeof(T) * count, alignof(T), tag));
if (result) if (result)
{ {
MemSet(result, 0, sizeof(T) * count); MemSet(result, 0, sizeof(T) * count);

View File

@@ -6,6 +6,11 @@
namespace Juliet namespace Juliet
{ {
namespace UnitTest
{
extern void TestMemoryArena();
}
void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size) void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size)
{ {
Assert(arena); Assert(arena);
@@ -13,10 +18,14 @@ namespace Juliet
arena->Data = static_cast<uint8*>(backingMemory); arena->Data = static_cast<uint8*>(backingMemory);
arena->Size = size; arena->Size = size;
arena->Offset = 0; arena->Offset = 0;
#if JULIET_DEBUG
arena->AllocationCount = 0;
#endif
} }
void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment) void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment, const char* tag)
{ {
(void)tag; // TODO: Use tag for allocation tracking in Debug builds
Assert(arena); Assert(arena);
// Alignment must be power of 2 // Alignment must be power of 2
@@ -35,10 +44,19 @@ namespace Juliet
void* result = arena->Data + (offset - reinterpret_cast<size_t>(arena->Data)); void* result = arena->Data + (offset - reinterpret_cast<size_t>(arena->Data));
arena->Offset = newOffset; arena->Offset = newOffset;
#if JULIET_DEBUG
if (arena->AllocationCount < MemoryArena::kMaxAllocations)
{
arena->Allocations[arena->AllocationCount] = { offset - reinterpret_cast<size_t>(arena->Data), size, tag ? tag : "Unknown" };
arena->AllocationCount++;
}
#endif
return result; return result;
} }
void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment) void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, const char* tag)
{ {
Assert(arena); Assert(arena);
// Alignment must be power of 2 // Alignment must be power of 2
@@ -46,7 +64,7 @@ namespace Juliet
if (oldPtr == nullptr) if (oldPtr == nullptr)
{ {
return ArenaPush(arena, newSize, alignment); return ArenaPush(arena, newSize, alignment, tag);
} }
if (newSize == 0) if (newSize == 0)
@@ -84,12 +102,20 @@ namespace Juliet
{ {
// In-place Resize success // In-place Resize success
arena->Offset = newOffset; arena->Offset = newOffset;
#if JULIET_DEBUG
// Update the last allocation size
if (arena->AllocationCount > 0)
{
arena->Allocations[arena->AllocationCount - 1].Size = newSize;
}
#endif
return oldPtr; return oldPtr;
} }
} }
// Fallback: Alloc + Copy // Fallback: Alloc + Copy
void* newPtr = ArenaPush(arena, newSize, alignment); void* newPtr = ArenaPush(arena, newSize, alignment, tag);
if (newPtr) if (newPtr)
{ {
size_t copySize = oldSize < newSize ? oldSize : newSize; size_t copySize = oldSize < newSize ? oldSize : newSize;
@@ -102,6 +128,9 @@ namespace Juliet
{ {
Assert(arena); Assert(arena);
arena->Offset = 0; arena->Offset = 0;
#if JULIET_DEBUG
arena->AllocationCount = 0;
#endif
} }
size_t ArenaGetMarker(MemoryArena* arena) size_t ArenaGetMarker(MemoryArena* arena)
@@ -115,6 +144,20 @@ namespace Juliet
Assert(arena); Assert(arena);
Assert(marker <= arena->Offset); Assert(marker <= arena->Offset);
arena->Offset = marker; arena->Offset = marker;
#if JULIET_DEBUG
while (arena->AllocationCount > 0)
{
if (arena->Allocations[arena->AllocationCount - 1].Offset >= marker)
{
arena->AllocationCount--;
}
else
{
break;
}
}
#endif
} }
// --- Global Arenas & Management --- // --- Global Arenas & Management ---
@@ -167,6 +210,10 @@ namespace Juliet
MemoryArenaCreate(&g_ScratchArena, g_ScratchBacking, kScratchSize); MemoryArenaCreate(&g_ScratchArena, g_ScratchBacking, kScratchSize);
MemoryArenaCreate(&g_EngineArena, g_EngineBacking, kEngineSize); MemoryArenaCreate(&g_EngineArena, g_EngineBacking, kEngineSize);
MemoryArenaCreate(&g_GameArena, g_GameBacking, kGameSize); MemoryArenaCreate(&g_GameArena, g_GameBacking, kGameSize);
#if JULIET_DEBUG
UnitTest::TestMemoryArena();
#endif
} }
void MemoryArenasShutdown() void MemoryArenasShutdown()