removing useless "realloc" feature in memory arenas
This commit is contained in:
@@ -12,14 +12,6 @@ namespace Juliet
|
|||||||
constexpr global uint64 g_Arena_Default_Commit_Size = Kilobytes(64);
|
constexpr global uint64 g_Arena_Default_Commit_Size = Kilobytes(64);
|
||||||
constexpr global uint64 k_ArenaHeaderSize = 128;
|
constexpr global uint64 k_ArenaHeaderSize = 128;
|
||||||
|
|
||||||
struct ArenaFreeNode
|
|
||||||
{
|
|
||||||
ArenaFreeNode* Next;
|
|
||||||
ArenaFreeNode* Previous;
|
|
||||||
index_t Position;
|
|
||||||
size_t Size;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
#if JULIET_DEBUG
|
||||||
struct ArenaDebugInfo;
|
struct ArenaDebugInfo;
|
||||||
#endif
|
#endif
|
||||||
@@ -41,10 +33,6 @@ namespace Juliet
|
|||||||
|
|
||||||
Arena* FreeBlockLast;
|
Arena* FreeBlockLast;
|
||||||
|
|
||||||
ArenaFreeNode* FreeNodes;
|
|
||||||
|
|
||||||
bool AllowRealloc : 1;
|
|
||||||
|
|
||||||
JULIET_DEBUG_ONLY(uint16 LostNodeCount;)
|
JULIET_DEBUG_ONLY(uint16 LostNodeCount;)
|
||||||
JULIET_DEBUG_ONLY(bool CanReserveMore : 1;)
|
JULIET_DEBUG_ONLY(bool CanReserveMore : 1;)
|
||||||
|
|
||||||
@@ -66,9 +54,6 @@ namespace Juliet
|
|||||||
uint64 ReserveSize = g_Arena_Default_Reserve_Size;
|
uint64 ReserveSize = g_Arena_Default_Reserve_Size;
|
||||||
uint64 CommitSize = g_Arena_Default_Commit_Size;
|
uint64 CommitSize = g_Arena_Default_Commit_Size;
|
||||||
|
|
||||||
// True: All push will be 32 bytes minimum
|
|
||||||
bool AllowRealloc = false;
|
|
||||||
|
|
||||||
// When false, will assert if a new block is reserved.
|
// When false, will assert if a new block is reserved.
|
||||||
JULIET_DEBUG_ONLY(bool CanReserveMore : 1 = true;)
|
JULIET_DEBUG_ONLY(bool CanReserveMore : 1 = true;)
|
||||||
};
|
};
|
||||||
@@ -80,8 +65,6 @@ namespace Juliet
|
|||||||
// Raw Push, can be used but templated helpers exists below
|
// Raw Push, can be used but templated helpers exists below
|
||||||
[[nodiscard]] JULIET_API void* ArenaPush(NonNullPtr<Arena> arena, size_t size, size_t align,
|
[[nodiscard]] JULIET_API void* ArenaPush(NonNullPtr<Arena> arena, size_t size, size_t align,
|
||||||
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
||||||
[[nodiscard]] JULIET_API void* ArenaReallocate(NonNullPtr<Arena> arena, void* oldPtr, size_t oldSize, size_t newSize,
|
|
||||||
size_t align, bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
|
||||||
JULIET_API void ArenaPopTo(NonNullPtr<Arena> arena, size_t position);
|
JULIET_API void ArenaPopTo(NonNullPtr<Arena> arena, size_t position);
|
||||||
JULIET_API void ArenaPop(NonNullPtr<Arena> arena, size_t amount);
|
JULIET_API void ArenaPop(NonNullPtr<Arena> arena, size_t amount);
|
||||||
JULIET_API void ArenaClear(NonNullPtr<Arena> arena);
|
JULIET_API void ArenaClear(NonNullPtr<Arena> arena);
|
||||||
|
|||||||
@@ -18,12 +18,6 @@ namespace Juliet
|
|||||||
constexpr uint64 k_PageSize = Kilobytes(4);
|
constexpr uint64 k_PageSize = Kilobytes(4);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
static_assert(sizeof(ArenaFreeNode) == 32, "ArenaFreeNode should be 32 bytes and not more");
|
|
||||||
constexpr size_t k_ArenaFreeNodeSize = sizeof(ArenaFreeNode);
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// https://github.com/EpicGamesExt/raddebugger/blob/master/src/base/base_arena.c
|
// https://github.com/EpicGamesExt/raddebugger/blob/master/src/base/base_arena.c
|
||||||
|
|
||||||
Arena* ArenaAllocate(const ArenaParams& params JULIET_DEBUG_ONLY(, const char* name), const std::source_location& loc)
|
Arena* ArenaAllocate(const ArenaParams& params JULIET_DEBUG_ONLY(, const char* name), const std::source_location& loc)
|
||||||
@@ -51,9 +45,6 @@ namespace Juliet
|
|||||||
arena->BasePosition = 0;
|
arena->BasePosition = 0;
|
||||||
arena->Position = k_ArenaHeaderSize;
|
arena->Position = k_ArenaHeaderSize;
|
||||||
|
|
||||||
arena->FreeNodes = nullptr;
|
|
||||||
arena->AllowRealloc = params.AllowRealloc;
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
#if JULIET_DEBUG
|
||||||
arena->CanReserveMore = params.CanReserveMore;
|
arena->CanReserveMore = params.CanReserveMore;
|
||||||
arena->FirstDebugInfo = nullptr;
|
arena->FirstDebugInfo = nullptr;
|
||||||
@@ -86,52 +77,6 @@ namespace Juliet
|
|||||||
size_t positionPrePush = AlignPow2(current->Position, align);
|
size_t positionPrePush = AlignPow2(current->Position, align);
|
||||||
size_t positionPostPush = positionPrePush + size;
|
size_t positionPostPush = positionPrePush + size;
|
||||||
|
|
||||||
if (arena->AllowRealloc)
|
|
||||||
{
|
|
||||||
size = Max(size, k_ArenaFreeNodeSize);
|
|
||||||
|
|
||||||
for (ArenaFreeNode* freeNode = current->FreeNodes; freeNode != nullptr; freeNode = freeNode->Next)
|
|
||||||
{
|
|
||||||
if (size <= freeNode->Size)
|
|
||||||
{
|
|
||||||
index_t position = freeNode->Position;
|
|
||||||
size_t remainingSize = freeNode->Size - size;
|
|
||||||
if (remainingSize < k_ArenaFreeNodeSize)
|
|
||||||
{
|
|
||||||
ArenaFreeNode* previous = freeNode->Previous;
|
|
||||||
ArenaFreeNode* next = freeNode->Next;
|
|
||||||
if (previous)
|
|
||||||
{
|
|
||||||
previous->Next = next;
|
|
||||||
}
|
|
||||||
if (next)
|
|
||||||
{
|
|
||||||
next->Previous = previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
if (remainingSize > 0)
|
|
||||||
{
|
|
||||||
++current->LostNodeCount;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
freeNode->Position += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* result = reinterpret_cast<Byte*>(current) + position;
|
|
||||||
if (shouldBeZeroed)
|
|
||||||
{
|
|
||||||
MemoryZero(result, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If allowed and needed, add a new block and chain it to the arena.
|
// If allowed and needed, add a new block and chain it to the arena.
|
||||||
if (current->Reserved < positionPostPush /* flags : chaining allowed */)
|
if (current->Reserved < positionPostPush /* flags : chaining allowed */)
|
||||||
{
|
{
|
||||||
@@ -225,55 +170,6 @@ namespace Juliet
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ArenaReallocate(NonNullPtr<Arena> arena, void* oldPtr, size_t oldSize, size_t newSize, size_t align,
|
|
||||||
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag))
|
|
||||||
{
|
|
||||||
void* result = ArenaPush(arena, newSize, align, shouldBeZeroed JULIET_DEBUG_ONLY(, tag));
|
|
||||||
|
|
||||||
// Find the correct block to release
|
|
||||||
Arena* block = nullptr;
|
|
||||||
for (block = arena->Current; block != nullptr; block = block->Previous)
|
|
||||||
{
|
|
||||||
if ((reinterpret_cast<Byte*>(block) < static_cast<Byte*>(oldPtr)) &&
|
|
||||||
(static_cast<Byte*>(oldPtr) <= (reinterpret_cast<Byte*>(block) + block->Reserved)))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Assert(block != nullptr);
|
|
||||||
|
|
||||||
// Copy old to new
|
|
||||||
MemCopy(result, oldPtr, std::min(oldSize, newSize));
|
|
||||||
|
|
||||||
// Zero the old memory
|
|
||||||
MemoryZero(oldPtr, oldSize);
|
|
||||||
|
|
||||||
if (oldSize >= sizeof(ArenaFreeNode))
|
|
||||||
{
|
|
||||||
ArenaFreeNode* freeNode = static_cast<ArenaFreeNode*>(oldPtr);
|
|
||||||
ptrdiff_t posPtr = static_cast<Byte*>(oldPtr) - reinterpret_cast<Byte*>(block);
|
|
||||||
index_t position = static_cast<index_t>(posPtr);
|
|
||||||
freeNode->Position = position;
|
|
||||||
freeNode->Size = oldSize;
|
|
||||||
|
|
||||||
// Insert at head of the free list
|
|
||||||
freeNode->Next = block->FreeNodes;
|
|
||||||
freeNode->Previous = nullptr;
|
|
||||||
if (block->FreeNodes)
|
|
||||||
{
|
|
||||||
block->FreeNodes->Previous = freeNode;
|
|
||||||
}
|
|
||||||
block->FreeNodes = freeNode;
|
|
||||||
|
|
||||||
#if JULIET_DEBUG
|
|
||||||
// Remove the debug info for the old allocation (since it's now free)
|
|
||||||
size_t oldOffset = static_cast<size_t>(static_cast<Byte*>(oldPtr) - reinterpret_cast<Byte*>(block));
|
|
||||||
DebugArenaRemoveAllocation(block, oldOffset);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArenaPopTo(NonNullPtr<Arena> arena, size_t position)
|
void ArenaPopTo(NonNullPtr<Arena> arena, size_t position)
|
||||||
{
|
{
|
||||||
size_t clampedPosition = ClampBottom(k_ArenaHeaderSize, position);
|
size_t clampedPosition = ClampBottom(k_ArenaHeaderSize, position);
|
||||||
|
|||||||
@@ -117,60 +117,6 @@ namespace Juliet::UnitTest
|
|||||||
|
|
||||||
ArenaRelease(testArena);
|
ArenaRelease(testArena);
|
||||||
|
|
||||||
{
|
|
||||||
// Test reallocate
|
|
||||||
Arena* arena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_ONLY(, "Test Realloc"));
|
|
||||||
char* charArray = ArenaPushArray<char>(arena, 128);
|
|
||||||
char* secondCharArray = ArenaPushArray<char>(arena, 128);
|
|
||||||
char* thirdCharArray = ArenaPushArray<char>(arena, 128);
|
|
||||||
|
|
||||||
secondCharArray = static_cast<char*>(ArenaReallocate(arena, secondCharArray, 128, 256, alignof(char), true JULIET_DEBUG_ONLY(, "ReallocChar")));
|
|
||||||
|
|
||||||
char* fourthCharArray = ArenaPushArray<char>(arena, 128);
|
|
||||||
|
|
||||||
Assert(charArray);
|
|
||||||
Assert(secondCharArray);
|
|
||||||
Assert(thirdCharArray);
|
|
||||||
Assert(fourthCharArray);
|
|
||||||
|
|
||||||
ArenaRelease(arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Test Reallocate Shrink (Buffer Overflow Bug Check)
|
|
||||||
Arena* arena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_ONLY(, "Test Shrink"));
|
|
||||||
|
|
||||||
size_t largeSize = 100;
|
|
||||||
char* large = ArenaPushArray<char>(arena, largeSize);
|
|
||||||
MemSet(large, 'A', largeSize);
|
|
||||||
|
|
||||||
size_t smallSize = 50;
|
|
||||||
char* smallData = static_cast<char*>(ArenaReallocate(arena, large, largeSize, smallSize, alignof(char), true JULIET_DEBUG_ONLY(, "ResizeSmall")));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < smallSize; ++i)
|
|
||||||
{
|
|
||||||
Assert(smallData[i] == 'A');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate next block (should be immediately after 'small')
|
|
||||||
// Don't zero it, if overflow happened it will contain 'A's
|
|
||||||
char* next = static_cast<char*>(ArenaPush(arena, 50, alignof(char), false JULIET_DEBUG_ONLY(, "OverflowCheck")));
|
|
||||||
|
|
||||||
bool corrupted = false;
|
|
||||||
for(size_t i = 0; i < 50; ++i)
|
|
||||||
{
|
|
||||||
if (next[i] == 'A')
|
|
||||||
{
|
|
||||||
corrupted = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert(!corrupted);
|
|
||||||
|
|
||||||
ArenaRelease(arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("All Paged MemoryArena tests passed.\n");
|
printf("All Paged MemoryArena tests passed.\n");
|
||||||
}
|
}
|
||||||
} // namespace Juliet::UnitTest
|
} // namespace Juliet::UnitTest
|
||||||
|
|||||||
@@ -450,24 +450,6 @@ namespace Juliet::Debug
|
|||||||
info = info->Next;
|
info = info->Next;
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw Free Nodes (Holes) if Realloc is enabled
|
|
||||||
if (arena->AllowRealloc && blk->FreeNodes)
|
|
||||||
{
|
|
||||||
ArenaFreeNode* freeNode = blk->FreeNodes;
|
|
||||||
while (freeNode)
|
|
||||||
{
|
|
||||||
float fxStart = pos.x + static_cast<float>(static_cast<double>(freeNode->Position) * scale);
|
|
||||||
float fWidth = static_cast<float>(static_cast<double>(freeNode->Size) * scale);
|
|
||||||
|
|
||||||
ImVec2 fMin(fxStart, pos.y + 1);
|
|
||||||
ImVec2 fMax(fxStart + fWidth, pos.y + blockHeight - 1);
|
|
||||||
|
|
||||||
dl->AddRectFilled(fMin, fMax, IM_COL32(50, 50, 50, 200));
|
|
||||||
|
|
||||||
freeNode = freeNode->Next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pos.y += blockHeight + blockSpacing;
|
pos.y += blockHeight + blockSpacing;
|
||||||
|
|||||||
@@ -154,7 +154,8 @@ namespace Juliet
|
|||||||
|
|
||||||
void InitializeEngine(JulietInit_Flags flags)
|
void InitializeEngine(JulietInit_Flags flags)
|
||||||
{
|
{
|
||||||
EngineInstance.PlatformArena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_PARAM("Platform Arena"));
|
EngineInstance.PlatformArena =
|
||||||
|
ArenaAllocate({ .ReserveSize = Megabytes(128) } JULIET_DEBUG_PARAM("Platform Arena"));
|
||||||
|
|
||||||
InitializeLogManager();
|
InitializeLogManager();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user