MemoryArena updates using Gemini. Add some debug tag so we can debug memory allocations
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -65,13 +83,13 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
// It is the last allocation! We can reuse the space.
|
// It is the last allocation! We can reuse the space.
|
||||||
// We just need to check if we can expand it (if growing)
|
// 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)
|
// Re-calculate the offset start for this block (to ensure nothing weird with padding)
|
||||||
// Ideally oldPtr was aligned.
|
// Ideally oldPtr was aligned.
|
||||||
|
|
||||||
// Current Offset corresponds to oldPtrBytes + oldSize.
|
// Current Offset corresponds to oldPtrBytes + oldSize.
|
||||||
// We want to move Offset to oldPtrBytes + newSize.
|
// We want to move Offset to oldPtrBytes + newSize.
|
||||||
|
|
||||||
size_t oldPtrOffset = static_cast<size_t>(oldPtrBytes - arena->Data);
|
size_t oldPtrOffset = static_cast<size_t>(oldPtrBytes - arena->Data);
|
||||||
size_t newOffset = oldPtrOffset + newSize;
|
size_t newOffset = oldPtrOffset + newSize;
|
||||||
|
|
||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user