From 0687ce5af19d1fc60bbbbecd2e0e703ed2663a04 Mon Sep 17 00:00:00 2001 From: Patedam Date: Tue, 20 Jan 2026 22:16:04 -0500 Subject: [PATCH] MemoryArena updates using Gemini. Add some debug tag so we can debug memory allocations --- Juliet/include/Core/Memory/MemoryArena.h | 30 +++++++++--- Juliet/src/Core/Memory/MemoryArena.cpp | 61 +++++++++++++++++++++--- 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/Juliet/include/Core/Memory/MemoryArena.h b/Juliet/include/Core/Memory/MemoryArena.h index f605627..9f3cf56 100644 --- a/Juliet/include/Core/Memory/MemoryArena.h +++ b/Juliet/include/Core/Memory/MemoryArena.h @@ -12,11 +12,27 @@ namespace Juliet uint8* Data; size_t Size; 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* ArenaPush(MemoryArena* arena, size_t size, size_t alignment = 16); - JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, 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, const char* tag = nullptr); + JULIET_API void ArenaReset(MemoryArena* arena); JULIET_API size_t ArenaGetMarker(MemoryArena* arena); JULIET_API void ArenaResetToMarker(MemoryArena* arena, size_t marker); @@ -39,9 +55,10 @@ namespace Juliet void MemoryArenasShutdown(); template - inline T* ArenaPushType(MemoryArena* arena) + inline T* ArenaPushType(MemoryArena* arena, const char* tag = nullptr) { - T* result = static_cast(ArenaPush(arena, sizeof(T), alignof(T))); + T* result = static_cast(ArenaPush(arena, sizeof(T), alignof(T), tag)); + if (result) { MemSet(result, 0, sizeof(T)); @@ -50,9 +67,10 @@ namespace Juliet } template - inline T* ArenaPushArray(MemoryArena* arena, size_t count) + inline T* ArenaPushArray(MemoryArena* arena, size_t count, const char* tag = nullptr) { - T* result = static_cast(ArenaPush(arena, sizeof(T) * count, alignof(T))); + T* result = static_cast(ArenaPush(arena, sizeof(T) * count, alignof(T), tag)); + if (result) { MemSet(result, 0, sizeof(T) * count); diff --git a/Juliet/src/Core/Memory/MemoryArena.cpp b/Juliet/src/Core/Memory/MemoryArena.cpp index 3577aa3..d3410f1 100644 --- a/Juliet/src/Core/Memory/MemoryArena.cpp +++ b/Juliet/src/Core/Memory/MemoryArena.cpp @@ -6,6 +6,11 @@ namespace Juliet { + namespace UnitTest + { + extern void TestMemoryArena(); + } + void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size) { Assert(arena); @@ -13,10 +18,14 @@ namespace Juliet arena->Data = static_cast(backingMemory); arena->Size = size; 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); // Alignment must be power of 2 @@ -35,10 +44,19 @@ namespace Juliet void* result = arena->Data + (offset - reinterpret_cast(arena->Data)); arena->Offset = newOffset; +#if JULIET_DEBUG + if (arena->AllocationCount < MemoryArena::kMaxAllocations) + { + arena->Allocations[arena->AllocationCount] = { offset - reinterpret_cast(arena->Data), size, tag ? tag : "Unknown" }; + arena->AllocationCount++; + } +#endif + 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); // Alignment must be power of 2 @@ -46,7 +64,7 @@ namespace Juliet if (oldPtr == nullptr) { - return ArenaPush(arena, newSize, alignment); + return ArenaPush(arena, newSize, alignment, tag); } if (newSize == 0) @@ -65,13 +83,13 @@ namespace Juliet { // It is the last allocation! We can reuse the space. // We just need to check if we can expand it (if growing) - + // Re-calculate the offset start for this block (to ensure nothing weird with padding) // Ideally oldPtr was aligned. - + // Current Offset corresponds to oldPtrBytes + oldSize. // We want to move Offset to oldPtrBytes + newSize. - + size_t oldPtrOffset = static_cast(oldPtrBytes - arena->Data); size_t newOffset = oldPtrOffset + newSize; @@ -84,12 +102,20 @@ namespace Juliet { // In-place Resize success 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; } } // Fallback: Alloc + Copy - void* newPtr = ArenaPush(arena, newSize, alignment); + void* newPtr = ArenaPush(arena, newSize, alignment, tag); + if (newPtr) { size_t copySize = oldSize < newSize ? oldSize : newSize; @@ -102,6 +128,9 @@ namespace Juliet { Assert(arena); arena->Offset = 0; +#if JULIET_DEBUG + arena->AllocationCount = 0; +#endif } size_t ArenaGetMarker(MemoryArena* arena) @@ -115,6 +144,20 @@ namespace Juliet Assert(arena); Assert(marker <= arena->Offset); 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 --- @@ -167,6 +210,10 @@ namespace Juliet MemoryArenaCreate(&g_ScratchArena, g_ScratchBacking, kScratchSize); MemoryArenaCreate(&g_EngineArena, g_EngineBacking, kEngineSize); MemoryArenaCreate(&g_GameArena, g_GameBacking, kGameSize); + +#if JULIET_DEBUG + UnitTest::TestMemoryArena(); +#endif } void MemoryArenasShutdown()