Replaced old memory arena with a new, better one, which also has a test suite

This commit is contained in:
PS 2021-08-06 18:19:30 -05:00
parent baf4c5d5a6
commit f261cbd55a
33 changed files with 10388 additions and 10380 deletions

View File

@ -6,7 +6,7 @@ SET MyPath=%MyPath:~0,-1%
call %MyPath%\_prebuild_win32.bat app debug msvc
call %MyPath%\setup_cl.bat
SET CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src
SET CommonCompilerFlags=-nologo -DDEBUG=0 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src
SET CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -I%CommonLibs% -Od %CommonCompilerFlags%

View File

@ -44,7 +44,7 @@ OperationModeSystemInit(gs_memory_arena* Storage, gs_thread_context ThreadContex
Result.ModeMemoryPagesFreeList.Data = PushArray(Storage, gs_data, Result.ModeMemoryPagesFreeList.CountMax);
for (u32 Page = 0; Page < Result.ModeMemoryPagesFreeList.CountMax; Page++)
{
Result.ModeMemoryPagesFreeList.Data[Page] = PushSizeToData(Storage, KB(4));
Result.ModeMemoryPagesFreeList.Data[Page] = PushSize(Storage, KB(4));
}
Result.ModeMemoryPagesFreeList.Count = Result.ModeMemoryPagesFreeList.CountMax;
@ -81,7 +81,7 @@ ActivateOperationMode (operation_mode_system* System, operation_render_proc* Ren
//System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(&System->Arena);
Result = &System->ActiveModes[ModeIndex];
Result->Memory = CreateMemoryCursor(OperationModeTakeMemoryPage(System));
Result->Memory = MemoryCursorCreateFromData(OperationModeTakeMemoryPage(System));
Result->Render = RenderProc;
return Result;
@ -132,7 +132,7 @@ CreateOperationState_ (operation_mode* Mode, operation_mode_system* System, s32
// NOTE(Peter): This isn't a problem if this fires, it just means our page size is too small,
// and its time to make the pages dynamically sized
Assert(Mode->Memory.Data.Size >= StateSize);
u8* Result = PushSizeOnCursor(&Mode->Memory, StateSize).Memory;
u8* Result = MemoryCursorPushSize(&Mode->Memory, StateSize).Memory;
Mode->OpStateMemory = Result;
return Result;
}

View File

@ -416,7 +416,7 @@ ui_InterfaceReset(ui_interface* Interface)
Interface->WidgetsCount = 0;
Interface->DrawOrderHead = 0;
Interface->DrawOrderRoot = 0;
ClearArena(Interface->PerFrameMemory);
MemoryArenaClear(Interface->PerFrameMemory);
InterfaceAssert(Interface->PerFrameMemory);
for (u32 i = 0; i < Interface->RetainedStateCount; i++)
@ -1665,7 +1665,7 @@ ui_InterfaceCreate(context Context, interface_config Style, gs_memory_arena* Per
Result.WidgetsCountMax = 4096;
Result.Widgets = PushArray(Permanent, ui_widget, Result.WidgetsCountMax);
Result.PerFrameMemory = PushStruct(Permanent, gs_memory_arena);
*Result.PerFrameMemory = CreateMemoryArena(Context.ThreadContext.Allocator, "Interface Per Frame Memory Arena", KB(32));
*Result.PerFrameMemory = MemoryArenaCreate(KB(32), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "Interface Per Frame Memory Arena");
InterfaceAssert(Result.PerFrameMemory);
Result.Permanent = Permanent;

View File

@ -55,7 +55,7 @@ FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_stat
// function
char LastChar = WorkingDirectory.Str[WorkingDirectory.Length - 1];
Assert(LastChar == '\\' || LastChar == '/');
ClearArena(&State->FileNamesArena);
MemoryArenaClear(&State->FileNamesArena);
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
@ -90,7 +90,7 @@ FileView_Init(panel* Panel, app_state* State, context Context)
// TODO: :FreePanelMemory
file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state);
Panel->StateMemory = StructToData(FileViewState, file_view_state);
FileViewState->FileNamesArena = CreateMemoryArena(Context.ThreadContext.Allocator, "File View - File Names Arena");
FileViewState->FileNamesArena = MemoryArenaCreate(MB(4), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "File View - File Names Arena");
// TODO(pjs): this shouldn't be stored in permanent
FileViewState->DisplayDirectory = PushString(&State->Permanent, 1024);

View File

@ -191,12 +191,12 @@ GetMemAmt (u64 BytesCount)
internal void
RenderProfiler_MemoryView(ui_interface* Interface, ui_widget* Layout, app_state* State, context Context, gs_memory_arena* Memory)
{
gs_allocator_debug Debug = *Context.ThreadContext.Allocator.Debug;
gs_debug_allocations_list* DA = Context.ThreadContext.Allocator.DEBUGAllocList;
gs_string TempString = PushString(State->Transient, 256);
mem_amt MemFootprint = GetMemAmt(Debug.TotalAllocSize);
u64 AllocCount = Debug.AllocationsCount;
mem_amt MemFootprint = GetMemAmt(DA->AllocationsSizeTotal);
u64 AllocCount = DA->AllocationsCount;
PrintF(&TempString, "Total Memory Size: %.2f %s | Allocations: %lld", MemFootprint.Size, MemFootprint.Units, AllocCount);
ui_Label(Interface, TempString);
@ -212,16 +212,20 @@ RenderProfiler_MemoryView(ui_interface* Interface, ui_widget* Layout, app_state*
}
ui_EndRow(Interface);
ui_BeginList(Interface, MakeString("Alloc List"), 10, Debug.AllocationsCount);
ui_BeginList(Interface, MakeString("Alloc List"), 10, DA->AllocationsCount);
ui_BeginRow(Interface, 2, &ColumnWidths[0]);
for (s32 n = 0; n < Debug.AllocationsCount; n++)
{
gs_debug_allocation A = Debug.Allocations[n];
PrintF(&TempString, "%S", A.Location);
for (gs_debug_memory_allocation* A = DA->Root;
A && A->Next != 0;
A = A->Next)
{
gs_const_string Str = ConstString(A->Loc.File);
u64 LastSlash = FindLastFromSet(Str, "\\/");
gs_const_string JustFileName = Substring(Str, LastSlash + 1, Str.Length);
PrintF(&TempString, "%s:%s(%d)", JustFileName.Str, A->Loc.Function, A->Loc.Line);
ui_Label(Interface, TempString);
mem_amt Amt = GetMemAmt(A.Size);
mem_amt Amt = GetMemAmt(A->Size);
PrintF(&TempString, "%.2f %s", Amt.Size, Amt.Units);
ui_Label(Interface, TempString);

View File

@ -200,7 +200,7 @@ SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
u32 NextLEDIndex = 0;
for (u32 Job = 0; Job < JobsNeeded; Job++)
{
gs_data Data = PushSizeToData(State->Transient, sizeof(draw_leds_job_data));
gs_data Data = PushSize(State->Transient, sizeof(draw_leds_job_data));
draw_leds_job_data* JobData = (draw_leds_job_data*)Data.Memory;
JobData->LedBuffer = *LedBuffer;
JobData->StartIndex = NextLEDIndex;

View File

@ -147,7 +147,7 @@ AnimationSystem_BeginRenderBlockToLedBuffer(animation_system* System, animation_
for (u32 i = 0; i < JobsCount; i++)
{
gs_data Data = PushSizeToData(Context.ThreadContext.Transient, sizeof(render_anim_to_led_buffer_job_data));
gs_data Data = PushSize(Context.ThreadContext.Transient, sizeof(render_anim_to_led_buffer_job_data));
render_anim_to_led_buffer_job_data* JobData = (render_anim_to_led_buffer_job_data*)Data.Memory;
JobData->Pattern = Pattern;
JobData->Buffer = *Buffer;

View File

@ -79,7 +79,7 @@ LedSystem_Create(gs_allocator PlatformMemory, u32 BuffersMax)
Result.PlatformMemory = PlatformMemory;
// TODO(Peter): Since we have access to PlatformMemory, just realloc Buffers when we fill it up
Result.BuffersCountMax = BuffersMax;
Result.Buffers = AllocatorAllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax);
Result.Buffers = AllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax, "led system");
return Result;
}
@ -109,9 +109,10 @@ LedSystemTakeFreeBuffer(led_system* System, u32 LedCount)
}
led_buffer* Buffer = &System->Buffers[Result];
Buffer->A = MemoryArenaCreate(KB(16),Bytes(8),System->PlatformMemory,0,0,"Led Buffer Arena");
Buffer->LedCount = LedCount;
Buffer->Colors = AllocatorAllocArray(System->PlatformMemory, pixel, Buffer->LedCount);
Buffer->Positions = AllocatorAllocArray(System->PlatformMemory, v4, Buffer->LedCount);
Buffer->Colors = PushArray(&Buffer->A, pixel, Buffer->LedCount);
Buffer->Positions = PushArray(&Buffer->A, v4, Buffer->LedCount);
System->LedsCountTotal += LedCount;
@ -123,8 +124,7 @@ LedSystemFreeBuffer(led_system* System, u32 BufferIndex)
{
Assert(BufferIndex < System->BuffersCountMax);
led_buffer* Buffer = &System->Buffers[BufferIndex];
AllocatorFreeArray(System->PlatformMemory, Buffer->Colors, pixel, Buffer->LedCount);
AllocatorFreeArray(System->PlatformMemory, Buffer->Positions, v4, Buffer->LedCount);
MemoryArenaFree(&Buffer->A);
System->LedsCountTotal -= Buffer->LedCount;
*Buffer = {};
}
@ -209,7 +209,7 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena
gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length);
NewAssembly = AssemblyArray_Take(Assemblies);
NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator, "Assembly Arena");
NewAssembly->Arena = MemoryArenaCreate(MB(4), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "Assembly Arena");
parser AssemblyParser = ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch);
if (AssemblyParser.Success)
@ -218,7 +218,7 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena
}
else
{
FreeMemoryArena(&NewAssembly->Arena);
MemoryArenaFree(&NewAssembly->Arena);
Assemblies->Count -= 1;
}
@ -244,7 +244,7 @@ UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context)
Assert(AssemblyIndex < State->Assemblies.Count);
assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex);
FreeMemoryArena(&Assembly->Arena);
MemoryArenaFree(&Assembly->Arena);
AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex);
}

View File

@ -27,6 +27,13 @@ union pixel
struct led_buffer
{
// NOTE(PS): This is just a tracking structure,
// that enables allocations for a particular buffer
// to occur all in contiguous memory
// and should not be pushed to after the initial
// allocation
gs_memory_arena A;
u32 LedCount;
pixel* Colors;
v4* Positions;

View File

@ -53,7 +53,7 @@ AddressedDataBufferList_Clear(addressed_data_buffer_list* List)
{
List->Root = 0;
List->Head = 0;
ClearArena(List->Arena);
MemoryArenaClear(List->Arena);
}
internal addressed_data_buffer*
@ -99,8 +99,8 @@ internal addressed_data_buffer_list
AddressedDataBufferList_Create(gs_thread_context TC)
{
addressed_data_buffer_list Result = {};
Result.Arena = AllocatorAllocStruct(TC.Allocator, gs_memory_arena);
*Result.Arena = CreateMemoryArena(TC.Allocator, "Addressed Data Buffer List Arena");
Result.Arena = AllocStruct(TC.Allocator, gs_memory_arena, "Addressed Data");
*Result.Arena = MemoryArenaCreate(KB(256), Bytes(8), TC.Allocator, 0, 0, "Addressed Data Buffer List Arena");
return Result;
}

View File

@ -17,7 +17,7 @@ struct log_entry
struct log_buffer
{
gs_allocator Allocator;
gs_memory_arena* Arena;
u64 EntriesCount;
u64 NextEntry;
@ -33,16 +33,21 @@ struct log_buffer_iter
};
internal log_buffer
Log_Init(gs_allocator Allocator, u64 Count)
Log_Init(gs_memory_arena* A, u64 Count)
{
log_buffer Result = {};
Result.Allocator = Allocator;
Result.Arena = A;
Result.EntriesCount = Count;
Result.Entries = AllocatorAllocArray(Allocator, log_entry, Result.EntriesCount);
Result.Entries = PushArray(A, log_entry, Result.EntriesCount);
u64 LogStringLength = 512;
u64 LogStringBufferSize = LogStringLength * Result.EntriesCount;
char* LogStringBuffer = PushArray(A, char, LogStringBufferSize);
char* LogStringBufferAt = LogStringBuffer;
for (u32 i = 0; i < Result.EntriesCount; i++)
{
Result.Entries[i].String = AllocatorAllocString(Allocator, 512);
Result.Entries[i].String = MakeString(LogStringBufferAt, 0, LogStringLength);
LogStringBufferAt += LogStringLength;
}
return Result;

View File

@ -13,10 +13,10 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel
// to catch the error where they are different
Assert(ChannelSettings.PixelsCount == Strip.LedCount);
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel);
uart_channel* Channel = MemoryCursorPushStruct(WriteCursor, uart_channel);
*Channel = ChannelSettings;
for (u32 i = 0; i < Channel->PixelsCount; i++)
@ -24,7 +24,7 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel
u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex];
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3);
u8* OutputPixel = MemoryCursorPushArray(WriteCursor, u8, 3);
// TODO(pjs): Use the Output mask
#if 1
@ -46,17 +46,17 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel
}
}
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
internal void
UART_DrawAll_Create(gs_memory_cursor* WriteCursor)
{
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
UART_FillHeader(Header, 1, UART_DRAW_ALL);
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
@ -152,7 +152,7 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli
gs_const_string ComPort = At->ComPort;
AddressedDataBuffer_SetCOMPort(Buffer, ComPort);
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
gs_memory_cursor WriteCursor = MemoryCursorCreate(Buffer->Memory, Buffer->MemorySize);
for (u32 i = 0; i < At->StripIndicesCount; i++)
{

View File

@ -31,11 +31,11 @@ RELOAD_STATIC_DATA(ReloadStaticData)
INITIALIZE_APPLICATION(InitializeApplication)
{
Context->MemorySize = sizeof(app_state);
Context->MemoryBase = AllocatorAlloc(Context->ThreadContext.Allocator, Context->MemorySize).Memory;
Context->MemoryBase = Alloc(Context->ThreadContext.Allocator, Context->MemorySize, "Memory Base");
app_state* State = (app_state*)Context->MemoryBase;
*State = {};
State->Permanent = CreateMemoryArena(Context->ThreadContext.Allocator, "Permanent");
State->Permanent = MemoryArenaCreate(MB(4), Bytes(8), Context->ThreadContext.Allocator,0, 0, "Permanent");
State->Transient = Context->ThreadContext.Transient;
State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
@ -129,7 +129,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
// and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't
// zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically
// incorrect to clear the arena, and then access the memory later.
ClearArena(State->Transient);
MemoryArenaClear(State->Transient);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
if (State->RunEditor)

View File

@ -117,6 +117,7 @@ struct debug_services
debug_interface Interface;
gs_thread_context Ctx;
gs_memory_arena A;
debug_get_thread_id* GetThreadId;
debug_timing_proc* GetWallClock;
@ -126,13 +127,13 @@ internal void
InitializeDebugFrame (debug_frame* Frame, s32 NameHashMax, s32 ThreadCount, s32 ScopeCallsMax, debug_services* Services)
{
Frame->ScopeNamesMax = NameHashMax;
Frame->ScopeNamesHash = AllocatorAllocArray(Services->Ctx.Allocator, scope_name, NameHashMax);
Frame->ScopeNamesHash = PushArray(&Services->A, scope_name, NameHashMax);
// NOTE(Peter): We use the same size as scope names because we're only storing a single instance
// per scope. If ScopeNamesMax can't hold all the scopes, this will never get filled and
// we should assert and recompile with a resized NameHashMax
Frame->CollatedScopesMax = NameHashMax;
Frame->CollatedScopes = AllocatorAllocArray(Services->Ctx.Allocator, collated_scope_record, NameHashMax);
Frame->CollatedScopes = PushArray(&Services->A, collated_scope_record, NameHashMax);
for (s32 i = 0; i < Frame->ScopeNamesMax; i++)
{
@ -141,13 +142,13 @@ InitializeDebugFrame (debug_frame* Frame, s32 NameHashMax, s32 ThreadCount, s32
}
Frame->ThreadCount = ThreadCount;
Frame->ThreadCalls = AllocatorAllocArray(Services->Ctx.Allocator, debug_scope_record_list, ThreadCount);
Frame->ThreadCalls = PushArray(&Services->A, debug_scope_record_list, ThreadCount);
for (s32 i = 0; i < ThreadCount; i++)
{
Frame->ThreadCalls[i].Max = ScopeCallsMax;
Frame->ThreadCalls[i].Count = 0;
Frame->ThreadCalls[i].Calls = AllocatorAllocArray(Services->Ctx.Allocator, scope_record, ScopeCallsMax);
Frame->ThreadCalls[i].Calls = PushArray(&Services->A, scope_record, ScopeCallsMax);
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
Frame->ThreadCalls[i].ThreadId = 0;
}
@ -213,9 +214,11 @@ InitDebugServices_DebugMode (debug_services* Services,
Services->RecordFrames = true;
Services->CurrentDebugFrame = 0;
Services->A = MemoryArenaCreate(MB(64), Bytes(8), Ctx.Allocator, 0, 0, "Debug Services Allocator");
s32 NameHashMax = 4096;
s32 ScopeCallsMax = 4096;
Services->Frames = AllocatorAllocArray(Ctx.Allocator, debug_frame, DEBUG_FRAME_COUNT);
Services->Frames = PushArray(&Services->A, debug_frame, DEBUG_FRAME_COUNT);
for (s32 i = 0; i < DEBUG_FRAME_COUNT; i++)
{
InitializeDebugFrame(&Services->Frames[i], NameHashMax, ThreadCount, ScopeCallsMax, Services);
@ -408,8 +411,8 @@ PushScopeTimeOnFrame (debug_services* Services, s32 NameHash, u64 StartCycles, u
if (ThreadList->Count >= ThreadList->Max)
{
s32 NewMax = (ThreadList->Max + DEBUG_FRAME_GROW_SIZE);
AllocatorFreeArray(Services->Ctx.Allocator, ThreadList->Calls, scope_record, ThreadList->Max);
ThreadList->Calls = AllocatorAllocArray(Services->Ctx.Allocator, scope_record, NewMax);
FreeArray(Services->Ctx.Allocator, ThreadList->Calls, scope_record, ThreadList->Max);
ThreadList->Calls = AllocArray(Services->Ctx.Allocator, scope_record, NewMax, "Debug Frame");
ThreadList->Max = NewMax;
}

View File

@ -20,7 +20,7 @@ AllocateRenderCommandBuffer(u32 MemorySize,
gs_memory_arena* Arena,
gs_thread_context Ctx)
{
u8* Memory = PushSize(Arena, MemorySize);
u8* Memory = PushSize(Arena, MemorySize).Memory;
return AllocateRenderCommandBuffer(Memory, MemorySize, Ctx);
}

View File

@ -265,8 +265,8 @@ ResizeBufferIfNecessary(render_command_buffer* Buffer, s32 DataSize)
s32 AdditionSize = Max(SpaceNeeded, COMMAND_BUFFER_MIN_GROW_SIZE);
s32 NewSize = Buffer->CommandMemorySize + AdditionSize;
AllocatorFree(Buffer->Ctx.Allocator, Buffer->CommandMemory, Buffer->CommandMemorySize);
Buffer->CommandMemory = AllocatorAlloc(Buffer->Ctx.Allocator, NewSize).Memory;
Free(Buffer->Ctx.Allocator, Buffer->CommandMemory, Buffer->CommandMemorySize);
Buffer->CommandMemory = Alloc(Buffer->Ctx.Allocator, NewSize, "Renderer");
Buffer->CommandMemorySize = NewSize;
}
}

View File

@ -585,14 +585,15 @@ WinMain (
)
{
gs_thread_context ThreadContext = Win32CreateThreadContext();
GlobalLogBuffer = AllocatorAllocStruct(ThreadContext.Allocator, log_buffer);
*GlobalLogBuffer = Log_Init(ThreadContext.Allocator, 32);
gs_allocator_debug AllocDebug = {};
AllocDebug.AllocationsCountMax = 4096;
AllocDebug.Allocations = AllocatorAllocArray(ThreadContext.Allocator, gs_debug_allocation, AllocDebug.AllocationsCountMax);
gs_memory_arena PlatformPermanent = MemoryArenaCreate(MB(4),
Bytes(8), ThreadContext.Allocator,
0,
0,
"Platform Memory");
ThreadContext.Allocator.Debug = &AllocDebug;
GlobalLogBuffer = AllocStruct(ThreadContext.Allocator, log_buffer, "Global Log Buffer");
*GlobalLogBuffer = Log_Init(&PlatformPermanent, 32);
if (!SetWorkingDirectory(HInstance, ThreadContext)) return 1;
@ -619,8 +620,6 @@ WinMain (
CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow);
}
gs_memory_arena PlatformPermanent = CreateMemoryArena(Context.ThreadContext.Allocator, "Platform Memory");
s64 PerformanceCountFrequency = GetPerformanceFrequency();
s64 LastFrameEnd = GetWallClock();
r32 TargetSecondsPerFrame = 1 / 30.0f;
@ -667,7 +666,7 @@ WinMain (
Win32SocketSystem_Init(&PlatformPermanent);
Win32SerialArray_Create(ThreadContext);
Win32SerialArray_Create(&PlatformPermanent);
render_command_buffer RenderBuffer = {};
if (!Context.Headless)

View File

@ -122,7 +122,7 @@ InitializeDLLHotReloading(char* SourceDLLName,
Win32DLLgs_stringLength(LockFileName), LockFileName,
MAX_PATH, Result.LockFilePath);
Win32Free((u8*)ExePath.Path, ExePath.PathLength);
Win32Free((u8*)ExePath.Path, ExePath.PathLength, 0);
return Result;
}

View File

@ -1,36 +1,26 @@
//
// File: win32_foldhaus_memory.h
// Author: Peter Slattery
// Creation Date: 2020-02-04
//
//
// NOTE: Relies on having imported foldhaus_platform.h prior to this file
//
#ifndef WIN32_FOLDHAUS_MEMORY_H
/* date = May 10th 2021 11:48 pm */
ALLOCATOR_ALLOC(Win32Alloc)
#ifndef GS_MEMORY_WIN32_H
#define GS_MEMORY_WIN32_H
PLATFORM_ALLOC(Win32Alloc)
{
u8* Result = (u8*)VirtualAlloc(NULL, Size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
if (ResultSize != 0)
{
*ResultSize = Size;
}
if (ResultSize) *ResultSize = Size;
return Result;
}
ALLOCATOR_FREE(Win32Free)
PLATFORM_FREE(Win32Free)
{
b32 Result = VirtualFree(Ptr, 0, MEM_RELEASE);
if (!Result)
{
s32 Error = GetLastError();
// TODO(Peter): I'm waiting to see an error actually occur here
// to know what it could possibly be.
InvalidCodePath;
}
VirtualFree(Base, 0, MEM_RELEASE);
}
#define WIN32_FOLDHAUS_MEMORY_H
#endif // WIN32_FOLDHAUS_MEMORY_H
internal gs_allocator
CreatePlatformAllocator()
{
return AllocatorCreate(Win32Alloc, Win32Free, 0);
}
#endif //GS_MEMORY_WIN32_H

View File

@ -82,7 +82,7 @@ Win32SerialPorts_List(gs_memory_arena* Arena, gs_memory_arena* Transient)
DWORD SizeNeeded1 = 0;
DWORD CountReturned1 = 0;
PORT_INFO_1* PortsArray = (PORT_INFO_1*)PushSize(Transient, SizeNeeded0);
PORT_INFO_1* PortsArray = (PORT_INFO_1*)PushSize(Transient, SizeNeeded0).Memory;
if (EnumPorts(NULL,
1,
(u8*)PortsArray,
@ -275,19 +275,19 @@ Win32SerialPort_ReadMessageWhenReady(HANDLE PortHandle, gs_data Data)
// Win32SerialArray
void
Win32SerialArray_Create(gs_thread_context Context)
Win32SerialArray_Create(gs_memory_arena* A)
{
DEBUG_TRACK_FUNCTION;
Win32SerialHandlesCountMax = 32;
Win32SerialHandles = AllocatorAllocArray(Context.Allocator, HANDLE, Win32SerialHandlesCountMax);
Win32SerialPortNames = AllocatorAllocArray(Context.Allocator, gs_string, Win32SerialHandlesCountMax);
Win32SerialPortFilled = AllocatorAllocArray(Context.Allocator, s32, Win32SerialHandlesCountMax);
Win32SerialHandles = PushArray(A, HANDLE, Win32SerialHandlesCountMax);
Win32SerialPortNames = PushArray(A, gs_string, Win32SerialHandlesCountMax);
Win32SerialPortFilled = PushArray(A, s32, Win32SerialHandlesCountMax);
u64 PortNameSize = 256;
u64 PortNameBufferSize = PortNameSize * Win32SerialHandlesCountMax;
char* PortNameBuffer = AllocatorAllocArray(Context.Allocator, char, PortNameBufferSize);
char* PortNameBuffer = PushArray(A, char, PortNameBufferSize);
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
char* NameBase = PortNameBuffer + (PortNameSize * i);

View File

@ -197,7 +197,7 @@ Win32ConnectSocket(platform_socket_manager* Manager, platform_socket* Socket)
}
}
Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0);
Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0, 0);
*(SOCKET*)Socket->PlatformHandle = SocketHandle;
Result = true;
break;
@ -223,7 +223,7 @@ Win32CloseSocket(platform_socket_manager* Manager, platform_socket* Socket)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
closesocket(*Win32Sock);
Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET));
Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET), 0);
*Socket = {};
return true;
}
@ -299,7 +299,7 @@ Win32SocketReceive(platform_socket_manager* Manager, platform_socket* Socket, gs
}
return Result;
#else
gs_data Result = PushSizeToData(Storage, 1024);
gs_data Result = PushSize(Storage, 1024);
s32 Flags = 0;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
s32 BytesReceived = recv(*Win32Sock, (char*)Result.Memory, Result.Size, Flags);
@ -465,7 +465,7 @@ Win32Socket_Receive(win32_socket* Socket, gs_memory_arena* Storage)
}
return Result;
#else
gs_data Result = PushSizeToData(Storage, 1024);
gs_data Result = PushSize(Storage, 1024);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
if (BytesReceived == SOCKET_ERROR)

View File

@ -40,15 +40,15 @@ Win32CreateThreadContext(gs_memory_arena* Transient = 0)
{
gs_thread_context Result = {0};
Result.ThreadInfo.ThreadID = Win32GetThreadId();
Result.Allocator = CreateAllocator(Win32Alloc, Win32Free);
Result.Allocator = CreatePlatformAllocator();
if (Transient != 0)
{
Result.Transient = Transient;
}
else
{
Result.Transient = (gs_memory_arena*)AllocatorAlloc(Result.Allocator, sizeof(gs_memory_arena)).Memory;
*Result.Transient = CreateMemoryArena(Result.Allocator, "Tctx Transient");
Result.Transient = AllocStruct(Result.Allocator, gs_memory_arena, "Work Queue");
*Result.Transient = MemoryArenaCreate(MB(4), Bytes(8), Result.Allocator, 0, 0, "Tctx Transient");
}
Result.FileHandler = CreateFileHandler(Win32GetFileInfo,
Win32ReadEntireFile,
@ -145,7 +145,7 @@ WorkerThreadProc (LPVOID InputThreadInfo)
Entry.IsValid = false;
while (true)
{
ClearArena(ThreadInfo->ThreadContext.Transient);
MemoryArenaClear(ThreadInfo->ThreadContext.Transient);
Entry = CompleteAndTakeNextJob(ThreadInfo->Queue, Entry, ThreadInfo->ThreadContext);
if (Entry.IsValid)
{
@ -182,7 +182,7 @@ CREATE_THREAD(Win32CreateThread)
Thread->UserData = UserData;
// TODO(pjs): ugh, allocation out in the middle of nowhere
HANDLE* ThreadHandle = AllocatorAllocStruct(Ctx.Allocator, HANDLE);
HANDLE* ThreadHandle = AllocStruct(Ctx.Allocator, HANDLE, "Create Thread");
*ThreadHandle = CreateThread(0, 0, Win32ThreadProcWrapper, (void*)Thread, 0, 0);
// TODO(pjs): Error checking on the created thread
@ -197,7 +197,7 @@ KILL_THREAD(Win32KillThread)
TerminateThread(ThreadHandle, 0);
// TODO(pjs): see allocation out in the middle of nowhere in Win32CreateThread
Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE));
Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE), 0);
// TODO(pjs): Error checking
return true;

View File

@ -369,7 +369,7 @@ BlumenLumen_CustomInit(app_state* State, context Context)
// the sculpture's CustomUpdate function;
gs_data Result = {};
Result = PushSizeToData(&State->Permanent, sizeof(blumen_lumen_state));
Result = PushSize(&State->Permanent, sizeof(blumen_lumen_state));
blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory;
BLState->Running = true;

View File

@ -2,9 +2,12 @@
internal void
MessageQueue_Init(blumen_network_msg_queue* Queue, gs_memory_arena* Arena)
{
gs_data MessageQueueData = PushSize(Arena, DEFAULT_QUEUE_ENTRY_SIZE * BLUMEN_MESSAGE_QUEUE_COUNT);
gs_memory_cursor C = MemoryCursorCreateFromData(MessageQueueData);
for (u32 i = 0; i < BLUMEN_MESSAGE_QUEUE_COUNT; i++)
{
Queue->Buffers[i] = PushSizeToData(Arena, DEFAULT_QUEUE_ENTRY_SIZE);
Queue->Buffers[i] = MemoryCursorPushSize(&C, DEFAULT_QUEUE_ENTRY_SIZE);
}
}

View File

@ -293,7 +293,7 @@ InputQueue_Create(gs_memory_arena* Arena, u32 CountMax)
if (CountMax > 0)
{
s32 Size = sizeof(input_entry) * 32;
u8* Memory = PushSize(Arena, Size);
u8* Memory = PushSize(Arena, Size).Memory;
Result = InputQueue_Create(Memory, Size);
}
return Result;

528
src/gs_libs/gs_memory.h Normal file
View File

@ -0,0 +1,528 @@
/* date = May 10th 2021 10:19 pm */
#ifndef GS_MEMORY_H
#define GS_MEMORY_H
#if !defined(Assert)
# define Assert(c)
#endif
#if !defined(InvalidCodePath)
# define InvalidCodePath
#endif
#if !defined(GS_MEMORY_PROFILE_FUNC)
# define GS_MEMORY_PROFILE_FUNC
#endif
#define MemoryClearArray(b,t,s) MemoryClear((u8*)(b), sizeof(t) * (s))
internal void
MemoryClear(u8* Base, u64 Size)
{
for (u64 i = 0; i < Size; i++) Base[i] = 0;
}
#ifndef DEBUG_LOC
typedef struct gs_debug_loc
{
char* File;
char* Function;
u32 Line;
} gs_debug_loc;
# define DEBUG_LOC gs_debug_loc{ (char*)__FILE__, (char*)__FUNCTION__, __LINE__ }
#endif
//
// Debug Info
//
typedef struct gs_debug_memory_allocation
{
gs_debug_loc Loc;
u64 ArenaHash;
u64 Size;
struct gs_debug_memory_allocation* Next;
} gs_debug_memory_allocation;
typedef struct gs_debug_arena_info
{
char* ArenaName;
u64 AllocationsCount;
u64 TotalSize;
} gs_debug_arena_info;
typedef struct gs_debug_allocations_list
{
gs_debug_memory_allocation* Root;
gs_debug_memory_allocation* Head;
u64 AllocationsSizeTotal;
u64 AllocationsCount;
u64 ArenaHashesCount;
u64* ArenaHashes;
gs_debug_arena_info* ArenaInfos;
} gs_debug_allocations_list;
//
// Allocator
//
#define PLATFORM_ALLOC(name) void* name(u64 Size, u64* ResultSize, u8* UserData)
typedef PLATFORM_ALLOC(platform_alloc);
#define PLATFORM_FREE(name) void name(void* Base, u64 Size, u8* UserData)
typedef PLATFORM_FREE(platform_free);
typedef struct gs_allocator
{
platform_alloc* PAlloc;
platform_free* PFree;
u8* UserData;
gs_debug_allocations_list* DEBUGAllocList;
} gs_allocator;
PLATFORM_ALLOC(AllocNoOp)
{
GS_MEMORY_PROFILE_FUNC;
if (ResultSize) *ResultSize = 0;
return 0;
}
PLATFORM_FREE(FreeNoOp)
{
GS_MEMORY_PROFILE_FUNC;
return;
}
internal u64
GSMemoryHash(char* Str, u64 Len)
{
u64 Hash = 5381;
for (u32 i = 0; i < Len; i++)
{
Hash = ((Hash << 5) + Hash) + Str[i];
}
return Hash;
}
#define Alloc(a,s,an) Alloc_((a),(s),DEBUG_LOC, (char*)(an)).Memory
#define AllocStruct(a,t,an) (t*)Alloc_((a),sizeof(t),DEBUG_LOC, (char*)(an)).Memory
#define AllocArray(a,t,c,an) (t*)Alloc_((a),sizeof(t)*(c),DEBUG_LOC, (char*)(an)).Memory
#define AllocData(a,s,an) Alloc_((a),(s),DEBUG_LOC, (char*)(an))
internal gs_data
Alloc_(gs_allocator A, u64 Size, gs_debug_loc Loc, char* ArenaName)
{
GS_MEMORY_PROFILE_FUNC;
gs_data Result = {};
Result.Memory = (u8*)A.PAlloc(Size, &Result.Size, A.UserData);
// Debug
{
u64 ArenaHash = GSMemoryHash(ArenaName, CStringLength(ArenaName));
gs_debug_memory_allocation* Allocation = (gs_debug_memory_allocation*)A.PAlloc(sizeof(gs_debug_memory_allocation*), 0, A.UserData);
Allocation->Loc = Loc;
Allocation->Size = Size;
Allocation->ArenaHash = ArenaHash;
SLLPushOrInit(A.DEBUGAllocList->Root, A.DEBUGAllocList->Head, Allocation);
A.DEBUGAllocList->AllocationsSizeTotal += Size;
A.DEBUGAllocList->AllocationsCount += 1;
u64 ArenaStartIndex = ArenaHash % A.DEBUGAllocList->ArenaHashesCount;
u64 ArenaIndex = ArenaStartIndex;
while (A.DEBUGAllocList->ArenaHashes[ArenaIndex] != 0 &&
A.DEBUGAllocList->ArenaHashes[ArenaIndex] != ArenaHash)
{
ArenaIndex = (ArenaIndex + 1) % A.DEBUGAllocList->ArenaHashesCount;
// NOTE(PS): this means you've created enough arena's to fill up every
// slot in the arena hash table. Go increase the size of of DEBUG_ALLOCATOR_ARENA_MAX
Assert(ArenaIndex != ArenaStartIndex);
}
if (A.DEBUGAllocList->ArenaHashes[ArenaIndex] == 0)
{
A.DEBUGAllocList->ArenaHashes[ArenaIndex] = ArenaHash;
gs_debug_arena_info AI = {};
AI.ArenaName = ArenaName;
A.DEBUGAllocList->ArenaInfos[ArenaIndex] = AI;
}
A.DEBUGAllocList->ArenaInfos[ArenaIndex].AllocationsCount += 1;
A.DEBUGAllocList->ArenaInfos[ArenaIndex].TotalSize += Size;
}
return Result;
}
#define AllocString(a,s,l) AllocString_((a), (s), DEBUG_LOC, (l))
internal gs_string
AllocString_(gs_allocator A, u64 Size, gs_debug_loc Loc, char* LocString)
{
gs_string Result = {};
Result.Str = (char*)Alloc_(A, sizeof(char)*Size, Loc, LocString).Memory;
Result.Length = 0;
Result.Size = Size;
return Result;
}
#define Free(a,b,s) Free_((a),(b),(s),DEBUG_LOC)
#define FreeStruct(a,b,t) Free_((a),(u8*)(b),sizeof(t),DEBUG_LOC)
#define FreeArray(a,b,t,c) Free_((a),(u8*)(b),sizeof(t)*(c),DEBUG_LOC)
internal void
Free_(gs_allocator A, u8* Base, u64 Size, gs_debug_loc Loc)
{
GS_MEMORY_PROFILE_FUNC;
A.PFree(Base, Size, A.UserData);
}
// NOTE(PS): cast function and struct pointers to proper data types
// for convenience
#define AllocatorCreate(a,f,u) AllocatorCreate_((platform_alloc*)(a),(platform_free*)(f),(u8*)(u))
internal gs_allocator
AllocatorCreate_(platform_alloc* PAlloc, platform_free* PFree, u8* UserData)
{
gs_allocator Result = {};
Result.PAlloc = PAlloc;
Result.PFree = PFree;
Result.UserData = UserData;
if (!PAlloc) Result.PAlloc = AllocNoOp;
if (!PFree) Result.PFree = FreeNoOp;
// @DEBUG
#define DEBUG_ALLOCATOR_ARENA_MAX 256
Result.DEBUGAllocList = (gs_debug_allocations_list*)PAlloc(sizeof(gs_debug_allocations_list*), 0, UserData);
Result.DEBUGAllocList->ArenaHashesCount = DEBUG_ALLOCATOR_ARENA_MAX;
Result.DEBUGAllocList->ArenaHashes = (u64*)PAlloc(sizeof(u64*) * DEBUG_ALLOCATOR_ARENA_MAX, 0, UserData);
Result.DEBUGAllocList->ArenaInfos = (gs_debug_arena_info*)PAlloc(sizeof(gs_debug_arena_info) * DEBUG_ALLOCATOR_ARENA_MAX, 0, UserData);
return Result;
}
//
// Memory Cursor
//
typedef struct gs_memory_cursor
{
gs_data Data;
u64 Position;
} gs_memory_cursor;
internal gs_memory_cursor
MemoryCursorCreate(u8* Base, u64 Size)
{
GS_MEMORY_PROFILE_FUNC;
gs_memory_cursor Result = {};
Result.Data.Memory = Base;
Result.Data.Size = Size;
Result.Position = 0;
return Result;
}
internal gs_memory_cursor
MemoryCursorCreateFromData(gs_data Data)
{
GS_MEMORY_PROFILE_FUNC;
return MemoryCursorCreate(Data.Memory, Data.Size);
}
internal u64
MemoryCursorRoomLeft(gs_memory_cursor Cursor)
{
GS_MEMORY_PROFILE_FUNC;
u64 Result = 0;
if (Cursor.Data.Size >= Cursor.Position)
{
Result = Cursor.Data.Size - Cursor.Position;
}
return Result;
}
internal bool
MemoryCursorHasRoom(gs_memory_cursor Cursor)
{
GS_MEMORY_PROFILE_FUNC;
u64 RoomLeft = MemoryCursorRoomLeft(Cursor);
bool Result = RoomLeft > 0;
return Result;
}
internal bool
MemoryCursorCanPush(gs_memory_cursor Cursor, u64 Size)
{
GS_MEMORY_PROFILE_FUNC;
u64 RoomLeft = MemoryCursorRoomLeft(Cursor);
bool Result = RoomLeft >= Size;
return Result;
}
#define MemoryCursorPushSize(c,s) MemoryCursorPushSize_((c),(s))
#define MemoryCursorPushStruct(c,s) (s*)MemoryCursorPushSize_((c),sizeof(s)).Memory
#define MemoryCursorPushArray(c,s,l) (s*)MemoryCursorPushSize_((c),sizeof(s)*(l)).Memory
internal gs_data
MemoryCursorPushSize_(gs_memory_cursor* C, u64 Size)
{
GS_MEMORY_PROFILE_FUNC;
gs_data Result = {0};
if (MemoryCursorCanPush(*C, Size))
{
Result.Memory = C->Data.Memory + C->Position;
Result.Size = Size,
C->Position += Size;
}
return Result;
}
internal gs_data
MemoryCursorAlign(gs_memory_cursor* C, u64 Alignment)
{
GS_MEMORY_PROFILE_FUNC;
u64 Position = RoundUpTo64(C->Position, Alignment);
if (Position > C->Data.Size)
{
Position = C->Data.Size;
}
u64 AlignmentDist = Position - C->Position;
gs_data Result = MemoryCursorPushSize_(C, AlignmentDist);
return Result;
}
#define MemoryCursorWriteValue(c,t,v) *PushStructOnCursor((c),(t)) = (v)
internal void
MemoryCursorWriteBuffer(gs_memory_cursor* C, gs_data Buffer)
{
GS_MEMORY_PROFILE_FUNC;
gs_data Dest = MemoryCursorPushSize(C, Buffer.Size);
if (Dest.Size == Buffer.Size)
{
CopyMemoryTo(Buffer.Memory, Dest.Memory, Buffer.Size);
}
}
internal void
MemoryCursorPopSize(gs_memory_cursor* C, u64 Size)
{
GS_MEMORY_PROFILE_FUNC;
u64 SizeToPop = Size;
if (SizeToPop > C->Position)
{
SizeToPop = C->Position;
}
C->Position -= SizeToPop;
}
internal void
MemoryCursorReset(gs_memory_cursor* C)
{
GS_MEMORY_PROFILE_FUNC;
C->Position = 0;
}
//
// Memory Arena
//
typedef struct gs_memory_cursor_sll
{
gs_memory_cursor Cursor;
struct gs_memory_cursor_sll* Next;
} gs_memory_cursor_sll;
typedef struct gs_memory_arena
{
u64 ChunkSize;
u64 Alignment;
char* ArenaName;
gs_memory_cursor_sll* CursorsRoot;
gs_memory_cursor_sll* CursorsHead;
struct gs_memory_arena* Parent;
gs_allocator Allocator;
u8* UserData;
// TODO: some sort of GrowArena function
} gs_memory_arena;
internal gs_memory_arena
MemoryArenaCreate(u64 ChunkSize, u64 Alignment, gs_allocator Allocator, gs_memory_arena* Parent, u8* UserData, char* Name)
{
GS_MEMORY_PROFILE_FUNC;
gs_memory_arena Result = {};
Result.ChunkSize = ChunkSize;
Result.Alignment = Alignment;
Result.Allocator = Allocator;
Result.Parent = Parent;
Result.UserData = UserData;
Result.ArenaName = Name;
return Result;
}
internal gs_data PushSize_(gs_memory_arena* Arena, u64 Size, gs_debug_loc Loc);
internal gs_memory_cursor*
MemoryArenaPushCursor(gs_memory_arena* Arena, u64 MinSize, gs_debug_loc Loc)
{
GS_MEMORY_PROFILE_FUNC;
gs_memory_cursor* Result = 0;
u64 CursorSize = MinSize;
if (CursorSize < Arena->ChunkSize)
{
CursorSize = Arena->ChunkSize;
}
u64 AllocSize = CursorSize + sizeof(gs_memory_cursor_sll);
gs_data CursorMemory = {0};
if (Arena->Parent)
{
CursorMemory = PushSize_(Arena->Parent, AllocSize, Loc);
} else if (Arena->UserData) {
// TODO(PS): implement custom MemoryArenaAllocCursor functionality
InvalidCodePath;
} else {
Assert(Arena->Allocator.PAlloc);
CursorMemory = Alloc_(Arena->Allocator, AllocSize, Loc, Arena->ArenaName);
}
gs_memory_cursor_sll* CursorEntry = (gs_memory_cursor_sll*)CursorMemory.Memory;
if (!Arena->CursorsRoot)
{
Arena->CursorsRoot = CursorEntry;
}
if (Arena->CursorsHead)
{
Arena->CursorsHead->Next = CursorEntry;
}
Arena->CursorsHead = CursorEntry;
u8* CursorBase = (u8*)(CursorEntry + 1);
CursorEntry->Cursor = MemoryCursorCreate(CursorBase, CursorSize);
Result = &CursorEntry->Cursor;
return Result;
}
#define PushSize(a,s) PushSize_((a), (s), DEBUG_LOC)
#define PushStruct(a,t) (t*)PushSize_((a), sizeof(t), DEBUG_LOC).Memory
#define PushArray(a,t,c) (t*)PushSize_((a), sizeof(t) * (c), DEBUG_LOC).Memory
#define PushString(a,c) gs_string{ PushArray((a),char,(c)), 0, (c) }
internal gs_data
PushSize_(gs_memory_arena* Arena, u64 Size, gs_debug_loc Loc)
{
GS_MEMORY_PROFILE_FUNC;
gs_data Result = {0};
if (Size > 0)
{
gs_memory_cursor* Cursor = 0;
for (gs_memory_cursor_sll* C = Arena->CursorsRoot;
C != 0;
C = C->Next)
{
if (MemoryCursorCanPush(C->Cursor, Size))
{
Cursor = &C->Cursor;
break;
}
}
// NOTE(PS): We didn't find a cursor with enough room
// for the allocation being requested
if (!Cursor)
{
Cursor = MemoryArenaPushCursor(Arena, Size, Loc);
}
Assert(Cursor);
Assert(MemoryCursorCanPush(*Cursor, Size));
Result = MemoryCursorPushSize(Cursor, Size);
gs_data Alignment = MemoryCursorAlign(Cursor, Arena->Alignment);
Result.Size += Alignment.Size;
}
return Result;
}
internal void
MemoryArenaClear(gs_memory_arena* Arena)
{
GS_MEMORY_PROFILE_FUNC;
for (gs_memory_cursor_sll* C = Arena->CursorsRoot;
C != 0;
C = C->Next)
{
MemoryCursorReset(&C->Cursor);
}
}
internal void
MemoryArenaFree(gs_memory_arena* Arena)
{
GS_MEMORY_PROFILE_FUNC;
// NOTE(PS): If this isn't a base arena, we can't
// really free it.
// TODO(PS): Once we have the User Specified codepaths
// in, we can probably provide a way for the user to
// let us free a custom allocator
Assert(Arena->Allocator.PFree);
gs_allocator A = Arena->Allocator;
gs_memory_cursor_sll* At = Arena->CursorsRoot;
while (At)
{
gs_memory_cursor_sll* NextAt = At->Next;
u64 Size = At->Cursor.Data.Size + sizeof(gs_memory_cursor_sll);
Free(A, (u8*)At, Size);
At = NextAt;
}
Arena->CursorsRoot = 0;
Arena->CursorsHead = 0;
}
#ifdef GS_PLATFORM_IMPLEMENTATION
internal gs_allocator CreatePlatformAllocator();
# if PLATFORM_WINDOWS
# include "./gs_memory_win32.h"
# elif PLATFORM_OSX
# include "./gs_memory_osx.h"
# elif PLATFORM_LINUX
# include "./gs_memory_linux.h"
# endif
#endif
#endif //GS_MEMORY_H

View File

@ -2426,383 +2426,18 @@ DataIsNonEmpty(gs_data Data)
return ((Data.Size > 0) && (Data.Memory != 0));
}
internal void* AllocatorAlloc_NoOp(u64 Size, u64* SizeResult) {
*SizeResult = 0;
return 0;
}
internal void AllocatorFree_NoOp(void* Base, u64 Size) { return; }
internal gs_allocator
CreateAllocator_(allocator_allocate* Alloc, allocator_free* Free)
{
if (Alloc == 0)
{
Alloc = AllocatorAlloc_NoOp;
}
if (Free == 0)
{
Free = AllocatorFree_NoOp;
}
gs_allocator Result = {0};
Result.Alloc = Alloc;
Result.Free = Free;
return Result;
}
#define CreateAllocator(a, f) CreateAllocator_((allocator_allocate*)(a), (allocator_free*)(f))
internal void
AllocatorDebug_PushAlloc(gs_allocator_debug* Debug, u64 Size, char* Location)
{
// NOTE(pjs): I don't want this debug procedure to be the reason the
// application crashes.
if (Debug->AllocationsCount < Debug->AllocationsCountMax)
{
gs_debug_allocation Allocation = {};
gs_const_string L = ConstString(Location);
s64 LastSlash = FindLastFromSet(L, "\\/");
if (LastSlash < 0) LastSlash = 0;
Allocation.Location = GetStringAfter(L, LastSlash);
Allocation.Size = Size;
Debug->Allocations[Debug->AllocationsCount++] = Allocation;
}
Debug->TotalAllocSize += Size;
}
internal gs_data
AllocatorAlloc_(gs_allocator Allocator, u64 Size, char* Location)
{
u64 SizeResult = 0;
void* Memory = Allocator.Alloc(Size, &SizeResult);
if (Allocator.Debug)
{
AllocatorDebug_PushAlloc(Allocator.Debug, Size, Location);
}
return CreateData((u8*)Memory, SizeResult);
}
internal void
AllocatorFree_(gs_allocator Allocator, void* Base, u64 Size, char* Location)
{
if (Base != 0 && Size != 0)
{
Allocator.Free(Base, Size);
if (Allocator.Debug)
{
// NOTE(pjs): There's no reason we should be going negative
// ie. Freeing more memory than we allocated
Assert(Allocator.Debug->TotalAllocSize >= Size);
Allocator.Debug->TotalAllocSize -= Size;
}
}
}
#define AllocatorAlloc(alloc,size) AllocatorAlloc_((alloc), (size), FileNameAndLineNumberString)
#define AllocatorAllocStruct(alloc, type) (type*)(AllocatorAlloc((alloc), sizeof(type)).Memory)
#define AllocatorAllocArray(alloc, type, count) (type*)(AllocatorAlloc((alloc), sizeof(type) * (count)).Memory)
#define AllocatorAllocString(alloc, size) gs_string{ AllocatorAllocArray((alloc), char, (size)), 0, (size) }
#define AllocatorFree(alloc,base,size) AllocatorFree_((alloc), (base), (size), FileNameAndLineNumberString)
#define AllocatorFreeArray(alloc,base,type,count) AllocatorFree_((alloc), (base), sizeof(type) * count, FileNameAndLineNumberString)
internal gs_memory_cursor
CreateMemoryCursor(u8* Base, u64 Size)
{
gs_memory_cursor Result = {0};
Result.Data.Memory = Base;
Result.Data.Size = Size;
return Result;
};
internal gs_memory_cursor
CreateMemoryCursor(gs_data Data)
{
return CreateMemoryCursor(Data.Memory, Data.Size);
}
internal gs_memory_cursor
CreateMemoryCursor(gs_allocator Allocator, u64 Size)
{
gs_data Data = AllocatorAlloc(Allocator, Size);
return CreateMemoryCursor(Data);
}
internal bool
CursorHasRoom(gs_memory_cursor Cursor, u64 Size)
{
bool Result = ((Cursor.Position + Size) <= Cursor.Data.Size);
return Result;
}
internal gs_data
PushSizeOnCursor_(gs_memory_cursor* Cursor, u64 Size, char* Location)
{
gs_data Result = {0};
if (CursorHasRoom(*Cursor, Size))
{
Result.Memory = Cursor->Data.Memory + Cursor->Position;
Result.Size = Size;
Cursor->Position += Size;
}
return Result;
}
#define PushSizeOnCursor(cursor,size) PushSizeOnCursor_((cursor), (size), FileNameAndLineNumberString)
#define PushStructOnCursor(cursor,type) (type*)PushSizeOnCursor_((cursor), sizeof(type), FileNameAndLineNumberString).Memory
#define PushArrayOnCursor(cursor,type,count) (type*)PushSizeOnCursor_((cursor), sizeof(type) * (count), FileNameAndLineNumberString).Memory
#define MemoryCursor_WriteValue(cursor, type, value) *PushStructOnCursor(cursor, type) = value
#define MemoryCursor_WriteBuffer(cursor, buf, len) CopyMemoryTo((u8*)(buf), PushArrayOnCursor((cursor), u8, (len)), (len))
internal void
PopSizeOnCursor(gs_memory_cursor* Cursor, u64 Size)
{
if (Cursor->Position > Size)
{
Cursor->Position -= Size;
}
else
{
Cursor->Position = 0;
}
}
internal gs_data
AlignCursor(gs_memory_cursor* Cursor, u64 Alignment)
{
u64 Position = RoundUpTo64(Cursor->Position, Alignment);
Position = Min(Position, Cursor->Data.Size);
u64 NewSize = Position - Cursor->Position;
return PushSizeOnCursor(Cursor, NewSize);
}
internal void
ClearCursor(gs_memory_cursor* Cursor)
{
Cursor->Position = 0;
}
internal void
FreeCursorListEntry(gs_allocator Allocator, gs_memory_cursor_list* CursorEntry)
{
AllocatorFree(Allocator, CursorEntry, CursorEntry->Cursor.Data.Size + sizeof(gs_memory_cursor));
}
internal gs_memory_arena
CreateMemoryArena_(arena_type ArenaType, gs_allocator Allocator, u64 ChunkSize, u64 Alignment, gs_memory_arena* ParentArena, char* Name)
{
// we only want a parent arena if the type is Arena_SubArena
Assert(((ArenaType == Arena_BaseArena) && (ParentArena == 0)) ||
((ArenaType == Arena_SubArena) && (ParentArena != 0)));
gs_memory_arena Arena = {};
Arena.ArenaName = Name;
Arena.Type = ArenaType;
Arena.Allocator = Allocator;
Arena.Parent = ParentArena;
#if MEMORY_CURSOR_STATIC_ARRAY
Arena.CursorsCountMax = 4096;
Arena.Cursors = AllocatorAllocArray(Allocator, gs_memory_cursor_list, Arena.CursorsCountMax);
#endif
Arena.MemoryChunkSize = ChunkSize;
Arena.MemoryAlignment = Alignment;
return Arena;
}
internal gs_memory_arena
CreateMemoryArena(gs_allocator Allocator, char* Name, u64 ChunkSize = KB(4), u64 Alignment = Bytes(8))
{
return CreateMemoryArena_(Arena_BaseArena, Allocator, ChunkSize, Alignment, 0, Name);
}
internal gs_memory_arena
CreateMemorySubArena(gs_memory_arena* Parent, char* Name, u64 ChunkSize = KB(32), u64 Alignment = Bytes(8))
{
return CreateMemoryArena_(Arena_SubArena, Parent->Allocator, ChunkSize, Alignment, Parent, Name);
}
internal gs_data PushSize_(gs_memory_arena* Arena, u64 Size, char* Location);
internal void
FreeCursorList(gs_memory_cursor_list* List, gs_allocator Allocator)
{
#if !MEMORY_CURSOR_STATIC_ARRAY
gs_memory_cursor_list* CursorAt = List;
while (CursorAt != 0)
{
gs_memory_cursor_list* Prev = CursorAt->Prev;
FreeCursorListEntry(Allocator, CursorAt);
CursorAt = Prev;
}
#endif
}
internal gs_memory_cursor_list*
MemoryArenaNewCursor(gs_memory_arena* Arena, u64 MinSize, char* Location)
{
#if MEMORY_CURSOR_STATIC_ARRAY
u64 AllocSize = Max(MinSize, Arena->MemoryChunkSize);
#else
// Allocate enough spcae for the minimum size needed + sizeo for the cursor list
u64 AllocSize = Max(MinSize, Arena->MemoryChunkSize) + sizeof(gs_memory_cursor_list);
#endif
gs_data Data = {0};
switch (Arena->Type)
{
case Arena_SubArena:
{
Data = PushSize_(Arena->Parent, AllocSize, Location);
}break;
case Arena_BaseArena:
{
Data = AllocatorAlloc_(Arena->Allocator, AllocSize, Location);
}break;
InvalidDefaultCase;
}
#if MEMORY_CURSOR_STATIC_ARRAY
Assert(Arena->CursorsCount < Arena->CursorsCountMax);
gs_memory_cursor_list* Result = Arena->Cursors + Arena->CursorsCount++;
Result->Cursor = CreateMemoryCursor(Data.Memory, Data.Size);
#else
// Fit the memory cursor into the region allocated
Assert(MinSize + sizeof(gs_memory_cursor_list) <= Data.Size);
gs_memory_cursor_list* Result = (gs_memory_cursor_list*)Data.Memory;
u8* CursorMemoryStart = (u8*)(Result + 1);
u64 CursorMemorySize = Data.Size - sizeof(gs_memory_cursor_list);
Result->Cursor = CreateMemoryCursor(CursorMemoryStart, CursorMemorySize);
Result->Prev = Arena->CursorList;
Result->Next = 0;
if (Arena->CursorList != 0)
{
if (Arena->CursorList->Next != 0)
{
Result->Next = Arena->CursorList->Next;
}
Arena->CursorList->Next = Result;
}
Arena->CursorList = Result;
#endif
return Result;
}
internal gs_data
PushSize_(gs_memory_arena* Arena, u64 Size, char* Location)
{
gs_data Result = {0};
if (Size > 0)
{
#if MEMORY_CURSOR_STATIC_ARRAY
gs_memory_cursor_list* CursorEntry = 0;
for (u64 i = 0;
i < Arena->CursorsCount;
i++)
{
gs_memory_cursor_list* At = Arena->Cursors + i;
if (CursorHasRoom(At->Cursor, Size))
{
CursorEntry = At;
break;
}
}
if (!CursorEntry)
{
CursorEntry = MemoryArenaNewCursor(Arena, Size, Location);
}
if (!CursorEntry || !CursorHasRoom(CursorEntry->Cursor, Size))
{
__debugbreak();
CursorEntry = 0;
for (u64 i = 0;
i < Arena->CursorsCount;
i++)
{
gs_memory_cursor_list* At = Arena->Cursors + i;
if (CursorHasRoom(At->Cursor, Size))
{
CursorEntry = At;
break;
}
}
if (!CursorEntry)
{
CursorEntry = MemoryArenaNewCursor(Arena, Size, Location);
}
}
//Assert(CursorEntry);
//Assert(CursorHasRoom(CursorEntry->Cursor, Size));
#else
gs_memory_cursor_list* CursorEntry = Arena->CursorList;
if (CursorEntry == 0)
{
CursorEntry = MemoryArenaNewCursor(Arena, Size, Location);
}
if (!CursorHasRoom(CursorEntry->Cursor, Size))
{
while ((CursorEntry != 0) && !CursorHasRoom(CursorEntry->Cursor, Size))
{
CursorEntry = CursorEntry->Next;
}
if (CursorEntry == 0)
{
CursorEntry = MemoryArenaNewCursor(Arena, Size, Location);
}
}
#endif
Assert(CursorEntry != 0);
Assert(CursorHasRoom(CursorEntry->Cursor, Size));
Result = PushSizeOnCursor_(&CursorEntry->Cursor, Size, Location);
Assert(Result.Memory != 0);
gs_data Alignment = AlignCursor(&CursorEntry->Cursor, Arena->MemoryAlignment);
Result.Size += Alignment.Size;
}
// TODO(Peter): @Cleanup @Efficiency
// There is a case I want to handle at some point:
// You have a Cursor that is empty, but the size you want to allocate is bigger
// than the cursor. So you create a new cursor, of the exact size you need,
// immediately fill it up, and push it onto the head of the cursor list. Now,
// the list looks like this:
// [root] [cursor] ... [empty cursor] [full cursor] [new, empty cursor]
// and you'll never use the memory in 'empty cursor'
// What I'd like to do is, when you fill up a cursor, it gets pushed back until
// the next cursor is more full
// NOTE: Thought on this tho - you don't want this behavior in a scratch arena
// where usage across frames could change drastically. This matters way more in
// a permanent storage (i think)
return Result;
}
internal void
FreeMemoryArena(gs_memory_arena* Arena)
{
#if MEMORY_CURSOR_STATIC_ARRAY
for (u32 i = 0; i < Arena->CursorsCount; i++)
{
gs_memory_cursor_list E = Arena->Cursors[i];
AllocatorFree(Arena->Allocator, E.Cursor.Data.Memory, E.Cursor.Data.Size);
}
AllocatorFreeArray(Arena->Allocator, Arena->Cursors, gs_memory_cursor_list, Arena->CursorsCountMax);
#else
FreeCursorList(Arena->CursorList, Arena->Allocator);
#endif
}
#define PushSizeToData(arena, size) PushSize_((arena), (size), FileNameAndLineNumberString)
#define PushSize(arena, size) PushSize_((arena), (size), FileNameAndLineNumberString).Memory
#define PushStruct(arena, type) (type*)(PushSize_((arena), sizeof(type), FileNameAndLineNumberString).Memory)
#define PushArray(arena, type, count) (type*)(PushSize_((arena), sizeof(type) * (count), FileNameAndLineNumberString).Memory)
#define PushString(arena, length) MakeString(PushArray((arena), char, (length)), 0, (length));
#define PushStringF(a,l,f,...) PushStringF_((a),(l),(f), DEBUG_LOC, __VA_ARGS__)
internal gs_string
PushStringF(gs_memory_arena* Arena, u32 MaxLength, char* Format, ...)
PushStringF_(gs_memory_arena* Arena, u32 MaxLength, char* Format, gs_debug_loc Loc, ...)
{
gs_string Result = PushString(Arena, MaxLength);
gs_string Result = gs_string {
(char*)PushSize_(Arena, sizeof(char) * MaxLength, Loc).Memory, // Str
0, // Length
MaxLength, // Size
};
va_list Args;
va_start(Args, Format);
va_start(Args, Loc);
PrintFArgsList(&Result, Format, Args);
va_end(Args);
@ -2822,33 +2457,6 @@ PushStringCopy(gs_memory_arena* Arena, gs_const_string String)
return Result;
}
internal void
ClearArena(gs_memory_arena* Arena)
{
#if MEMORY_CURSOR_STATIC_ARRAY
for (u32 i = 0; i < Arena->CursorsCount; i++)
{
Arena->Cursors[i].Cursor.Position = 0;
}
#else
gs_memory_cursor_list* First = 0;
for (gs_memory_cursor_list* CursorEntry = Arena->CursorList;
CursorEntry != 0;
CursorEntry = CursorEntry->Prev)
{
First = CursorEntry;
CursorEntry->Cursor.Position = 0;
}
Arena->CursorList = First;
#endif
}
internal void
FreeArena(gs_memory_arena* Arena)
{
FreeMemoryArena(Arena);
}
///////////////////////////
//
// Debug Print
@ -2877,141 +2485,8 @@ DebugPrintF(debug_output Output, char* Format, ...)
Output.Print(Output, Message.ConstString);
}
///////////////////////////
//
// Dynamic Array
internal gs_dynarray
CreateDynarrayWithStorage(gs_memory_arena Storage, u32 ElementSize, u32 ElementsPerBuffer)
{
gs_dynarray Result = {};
Result.Arena = Storage;
Result.ElementSize = ElementSize;
Result.ElementsPerBuffer = ElementsPerBuffer;
Result.ElementCount = 0;
return Result;
}
internal gs_dynarray
CreateDynarray_(gs_allocator Allocator, u32 ElementSize, u32 ElementsPerBuffer)
{
gs_memory_arena Storage = CreateMemoryArena(Allocator, "Dynarray Arena", ElementSize * ElementsPerBuffer);
return CreateDynarrayWithStorage(Storage, ElementSize, ElementsPerBuffer);
};
internal gs_dynarray
CreateDynarray_(gs_memory_arena* Arena, u32 ElementSize, u32 ElementsPerBuffer)
{
gs_memory_arena Storage = CreateMemorySubArena(Arena, "Dynarray Sub Arena", ElementSize * ElementsPerBuffer);
return CreateDynarrayWithStorage(Storage, ElementSize, ElementsPerBuffer);
};
internal u64
CalculateBufferSize(gs_dynarray Array)
{
u64 Result = Array.ElementsPerBuffer * Array.ElementSize;
return Result;
}
internal void
GrowDynarray(gs_dynarray* Array)
{
gs_dynarray_buffer* OldBufferList = Array->Buffers;
u64 NewBuffersCount = Array->BuffersCount + 1;
gs_dynarray_buffer* NewBufferList = AllocatorAllocArray(Array->Arena.Allocator, gs_dynarray_buffer, NewBuffersCount);
if (OldBufferList)
{
CopyArray(OldBufferList, NewBufferList, gs_dynarray_buffer, Array->BuffersCount);
AllocatorFree(Array->Arena.Allocator, OldBufferList, sizeof(gs_dynarray_buffer) * Array->BuffersCount);
}
u64 BufferSize = CalculateBufferSize(*Array);
NewBufferList[Array->BuffersCount].Memory = PushSize(&Array->Arena, BufferSize);
Array->Buffers = NewBufferList;
Array->BuffersCount = NewBuffersCount;
}
internal u64
DynarraySize(gs_dynarray Array)
{
u64 Result = Array.BuffersCount * Array.ElementsPerBuffer;
return Result;
}
internal gs_dynarray_handle
IndexToHandle(gs_dynarray* Array, u64 Index)
{
gs_dynarray_handle Result = {0};
Result.BufferIndex = Index / Array->ElementsPerBuffer;
Result.IndexInBuffer = Index % Array->ElementsPerBuffer;
return Result;
}
internal u64
HandleToIndex(gs_dynarray Array, gs_dynarray_handle Handle)
{
u64 Result = Handle.IndexInBuffer + (Handle.BufferIndex * Array.ElementsPerBuffer);
return Result;
}
internal gs_dynarray_handle
TakeFreeElement(gs_dynarray* Array)
{
gs_dynarray_handle Result = {0};
if (Array->ElementCount >= DynarraySize(*Array))
{
GrowDynarray(Array);
}
Assert(Array->ElementCount < DynarraySize(*Array));
u64 ElementIndex = Array->ElementCount++;
Result = IndexToHandle(Array, ElementIndex);
return Result;
}
internal bool
HandleIsValid(gs_dynarray Array, gs_dynarray_handle Handle)
{
bool Result = Handle.IndexInBuffer < Array.ElementsPerBuffer;
Result &= Handle.BufferIndex < Array.BuffersCount;
return Result;
}
internal bool
IndexIsValid(gs_dynarray Array, u64 Index)
{
bool Result = Index < DynarraySize(Array);
return Result;
}
internal gs_data
GetElementInList_(gs_dynarray* Array, gs_dynarray_handle Handle, u64 SizeRequested)
{
Assert(SizeRequested == Array->ElementSize);
Assert(HandleIsValid(*Array, Handle));
gs_dynarray_buffer Buffer = Array->Buffers[Handle.BufferIndex];
gs_data Result = {0};
Result.Memory = Buffer.Memory + (Handle.IndexInBuffer * Array->ElementSize);
Result.Size = SizeRequested;
return Result;
}
internal gs_data
GetElementInList_(gs_dynarray* Array, u64 Index, u64 SizeRequested)
{
gs_dynarray_handle Handle = IndexToHandle(Array, Index);
return GetElementInList_(Array, Handle, SizeRequested);
}
internal void
FreeDynarray(gs_dynarray* Array)
{
gs_allocator Allocator = Array->Arena.Allocator;
u64 BufferSize = CalculateBufferSize(*Array);
for (u64 i = 0; i < Array->BuffersCount; i++)
{
AllocatorFree(Allocator, Array->Buffers[i].Memory, BufferSize);
}
AllocatorFree(Allocator, Array->Buffers, sizeof(gs_dynarray_buffer) * Array->BuffersCount);
}
#define HandlesAreEqual(ha, hb) ((ha.IndexInBuffer == hb.IndexInBuffer) && (ha.BufferIndex == hb.BufferIndex))
#define CreateDynarray(allocator,type,elePerBuf) CreateDynarray_((allocator), sizeof(type), (elePerBuf))
#define GetElement_(array,type,size,indexOrHandle) (type*)GetElementInList_(array, indexOrHandle, size).Memory
#define GetElement(array,type,indexOrHandle) GetElement_(array, type, sizeof(type), indexOrHandle)
///////////////////////////
//
// String Builder
@ -3412,7 +2887,7 @@ ReadEntireFile(gs_file_handler FileHandler, gs_const_string Path)
gs_file_info FileInfo = FileHandler.GetFileInfo(FileHandler, Path);
if (FileInfo.FileSize > 0)
{
gs_data FileMemory = PushSizeToData(FileHandler.Transient, FileInfo.FileSize);
gs_data FileMemory = PushSize(FileHandler.Transient, FileInfo.FileSize);
Result = ReadEntireFile(FileHandler, Path, FileMemory);
}
return Result;

View File

@ -309,8 +309,8 @@ CopyMemory_(u8* From, u8* To, u64 Size)
#define SLLPop_(list_tail) list_tail=list_tail=list_tail->next
#define SLLPop(list_tail) (SLLPop_((list_tail)))
#define SLLNext(ele_at) ele_at = ele_at->Next;
#define SLLPrev(ele_at) ele_at = ele_at->Prev;
#define SLLNext(ele_at) ele_at = ele_at->Next
#define SLLPrev(ele_at) ele_at = ele_at->Prev
#define SLLInit(head,tail,first_ele) head=first_ele, tail=first_ele;
@ -651,95 +651,10 @@ enum
gs_Scan_Forward = 1,
};
#define ALLOCATOR_ALLOC(name) void* name(u64 Size, u64* ResultSize)
typedef ALLOCATOR_ALLOC(allocator_allocate);
#define ALLOCATOR_FREE(name) void name(void* Ptr, u64 Size)
typedef ALLOCATOR_FREE(allocator_free);
internal u64 RoundUpTo64(u64 Value, u64 Alignment);
struct gs_debug_allocation
{
gs_const_string Location;
u64 Size;
};
struct gs_allocator_debug
{
u64 TotalAllocSize;
u64 AllocationsCount;
u64 AllocationsCountMax;
gs_debug_allocation* Allocations;
};
struct gs_allocator
{
allocator_allocate* Alloc;
allocator_free* Free;
gs_allocator_debug* Debug;
};
struct gs_memory_cursor
{
gs_data Data;
u64 Position;
};
/* TODO(pjs): Setting MEMORY_CURSOR_STATIC_ARRAY will still compile,
However, it introduces a bug that I haven't fully diagnosed.
The problem seems to occur when trying to push to a cleared memory arena
Where the FirstCursor doesn't have enough room for the allocation, but
also FirstCursor->Next points to a valid cursor. The new cursor is put
in the middle however we seem to continually keep allocating new
cursors forever and losing old ones.
The problem in Lumenarium is found in the OutputData structure
Leaving this in a simplified state for now
*/
#define MEMORY_CURSOR_STATIC_ARRAY 1
struct gs_memory_cursor_list
{
gs_memory_cursor Cursor;
#if !MEMORY_CURSOR_STATIC_ARRAY
gs_memory_cursor_list* Next;
gs_memory_cursor_list* Prev;
#endif
};
enum arena_type
{
Arena_BaseArena,
Arena_SubArena,
};
struct gs_memory_arena
{
arena_type Type;
gs_allocator Allocator;
gs_memory_arena* Parent;
#if MEMORY_CURSOR_STATIC_ARRAY
gs_memory_cursor_list* Cursors;
u64 CursorsCount;
u64 CursorsCountMax;
#else
gs_memory_cursor_list* CursorList;
#endif
u64 MemoryChunkSize;
u64 MemoryAlignment;
char* ArenaName;
};
struct gs_memory_arena_array
{
gs_memory_arena* Arenas;
u32 Count;
u32 Size;
};
#include "gs_memory.h"
///////////////////////////////
//

View File

@ -64,11 +64,6 @@ internal void Win32UpdateWindowDimension(window* Window);
internal void Win32ResizeDIBSection(win32_offscreen_buffer *Buffer, int Width, int Height);
internal void Win32DisplayBufferInWindow(win32_offscreen_buffer* Buffer, window Window);
// Memory
internal ALLOCATOR_ALLOC(Win32Alloc);
internal ALLOCATOR_FREE(Win32Free);
///
// Utils
///

View File

@ -177,8 +177,8 @@ FlowerStripToChannel(u8 Flower, u8 Channel)
int main(int ArgCount, char** Args)
{
gs_thread_context Ctx = Win32CreateThreadContext();
GlobalLogBuffer = AllocatorAllocStruct(Ctx.Allocator, log_buffer);
*GlobalLogBuffer = Log_Init(Ctx.Allocator, 32);
GlobalLogBuffer = PushStruct(Ctx.Transient, log_buffer);
*GlobalLogBuffer = Log_Init(Ctx.Transient, 32);
gs_string OutputBuffer0 = PushString(Ctx.Transient, MB(4));
gs_string OutputBuffer1 = PushString(Ctx.Transient, MB(4));

View File

@ -45,7 +45,7 @@ FindNextHeader(gs_data Data, u8* StartAt)
void
CreateMessage(gs_data* Data, u8 Count)
{
gs_memory_cursor WriteCursor = CreateMemoryCursor(*Data);
gs_memory_cursor WriteCursor = MemoryCursorCreateFromData(*Data);
u32 Channels[] = {
0, 1, 2, 3, 4, 5, 6, 7,
@ -58,7 +58,7 @@ CreateMessage(gs_data* Data, u8 Count)
for (u32 j = 0; j < sizeof(Channels) / sizeof(u32); j++)
{
u32 ChannelIndex = Channels[j];
uart_header* Header = PushStructOnCursor(&WriteCursor, uart_header);
uart_header* Header = MemoryCursorPushStruct(&WriteCursor, uart_header);
UART_FillHeader(Header, ChannelIndex, UART_SET_CHANNEL_WS2812);
if (FirstHeaderAddr == 0)
@ -66,27 +66,27 @@ CreateMessage(gs_data* Data, u8 Count)
FirstHeaderAddr = (u8*)Header;
}
uart_channel* Channel = PushStructOnCursor(&WriteCursor, uart_channel);
uart_channel* Channel = MemoryCursorPushStruct(&WriteCursor, uart_channel);
Channel->ElementsCount = 3;
Channel->ColorPackingOrder = 36; // 10010000
Channel->PixelsCount = 300;
for (u32 i = 0; i < Channel->PixelsCount; i++)
{
u8* Pixel = PushArrayOnCursor(&WriteCursor, u8, 3);
u8* Pixel = MemoryCursorPushArray(&WriteCursor, u8, 3);
Pixel[0] = Count;
Pixel[1] = 0;
Pixel[2] = 255 - Count;
}
uart_footer* Footer = PushStructOnCursor(&WriteCursor, uart_footer);
uart_footer* Footer = MemoryCursorPushStruct(&WriteCursor, uart_footer);
Footer->CRC = UART_CalculateCRC((u8*)Header, (u8*)(Footer));
}
uart_header* DrawAllHeader = PushStructOnCursor(&WriteCursor, uart_header);
uart_header* DrawAllHeader = MemoryCursorPushStruct(&WriteCursor, uart_header);
UART_FillHeader(DrawAllHeader, 255, UART_DRAW_ALL);
uart_footer* DrawAllFooter =
PushStructOnCursor(&WriteCursor, uart_footer);
MemoryCursorPushStruct(&WriteCursor, uart_footer);
DrawAllFooter->CRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
Data->Size = ((u8*)DrawAllFooter - (u8*)FirstHeaderAddr) + sizeof(uart_footer);
@ -95,8 +95,8 @@ CreateMessage(gs_data* Data, u8 Count)
int main(int ArgCount, char** Args)
{
gs_thread_context Ctx = Win32CreateThreadContext();
GlobalLogBuffer = AllocatorAllocStruct(Ctx.Allocator, log_buffer);
*GlobalLogBuffer = Log_Init(Ctx.Allocator, 32);
GlobalLogBuffer = PushStruct(Ctx.Transient, log_buffer);
*GlobalLogBuffer = Log_Init(Ctx.Transient, 32);
HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9", Ctx.Transient);
Win32SerialPort_SetState(SerialHandle, 2000000, 8, 0, 1);
@ -108,7 +108,7 @@ int main(int ArgCount, char** Args)
{
Win32SerialPort_SetRead(SerialHandle);
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
gs_data Data = PushSize(Ctx.Transient, KB(32));
Win32SerialPort_SetRead(SerialHandle);
u32 ReadSize = Win32SerialPort_ReadMessageWhenReady(SerialHandle, Data);
@ -173,7 +173,7 @@ int main(int ArgCount, char** Args)
}
else if (true)
{
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
gs_data Data = PushSize(Ctx.Transient, KB(32));
u8 Count = 0;
while(true)
@ -185,7 +185,7 @@ int main(int ArgCount, char** Args)
}
else if (false)
{
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
gs_data Data = PushSize(Ctx.Transient, KB(32));
gs_file File = Win32ReadEntireFile(Ctx.FileHandler, OutFileName, Data);
gs_data Messages = {0};

View File

@ -1,7 +1,5 @@
#include "../app/platform_win32/win32_foldhaus_memory.h"
internal u32
TESTNextRandom(u32* LastRandomValue)
NextRandom(u32* LastRandomValue)
{
u32 Result = *LastRandomValue;
Result ^= Result << 13;
@ -11,64 +9,63 @@ TESTNextRandom(u32* LastRandomValue)
return Result;
}
internal void
void
MemoryArenaTests()
{
Test("Allocator")
{
gs_allocator Allocator = CreateAllocator(Win32Alloc, Win32Free);
gs_allocator A = CreatePlatformAllocator();
u8* Data = AllocatorAllocArray(Allocator, u8, 4096);
u8* Data = AllocArray(A, u8, 4096, "root");
for (int i = 0; i < 4096; i++) Data[i] = (i % MaxU8);
bool Success = true;
for (int i = 0; i < 4096; i++) Success &= (Data[i] == (i % MaxU8));
for (int i = 0; i < 4096; i++) Success &= Data[i] == (i % MaxU8);
TestResult(Success);
AllocatorFreeArray(Allocator, Data, u8, 4096);
// idk how to test free
FreeArray(A, Data, u8, 4096);
TestResult(true); // TODO(PS): How do we test free?
}
Test("Memory Cursor")
{
gs_allocator A = CreateAllocator(Win32Alloc, Win32Free);
gs_allocator A = CreatePlatformAllocator();
u64 Size = 4096;
gs_data D = AllocatorAlloc(A, Size);
gs_memory_cursor C = CreateMemoryCursor(D);
gs_data D = AllocData(A, Size, "root");
gs_memory_cursor C = MemoryCursorCreate(D.Memory, D.Size);
u64 RoomLeft = CursorRoomLeft(C);
u64 RoomLeft = MemoryCursorRoomLeft(C);
TestResult(RoomLeft == Size);
TestResult(MemoryCursorHasRoom(C));
TestResult(CursorHasRoom(C, 2048));
TestResult(CursorHasRoom(C, Size));
TestResult(!CursorHasRoom(C, Size + 1));
TestResult(MemoryCursorCanPush(C, 2048));
TestResult(MemoryCursorCanPush(C, Size));
TestResult(!MemoryCursorCanPush(C, Size + 1));
for (u64 i = 0; i < 2048; i++)
{
u8* Byte = PushSizeOnCursor(&C, 1).Memory;
u8* Byte = MemoryCursorPushSize(&C, 1).Memory;
*Byte = (u8)(i % 256);
}
RoomLeft = CursorRoomLeft(C);
RoomLeft = MemoryCursorRoomLeft(C);
TestResult(RoomLeft == (Size - 2048));
PopSizeOnCursor(&C, 2048);
MemoryCursorPopSize(&C, 2048);
TestResult(C.Position == 0);
bool Success = true;
for (u64 i = 0; i < 2048; i++)
{
u8* Byte = PushSizeOnCursor(&C, 1).Memory;
u8* Byte = MemoryCursorPushSize(&C, 1).Memory;
Success &= *Byte == (u8)(i % 256);
}
TestResult(Success);
AllocatorFree(A, D.Memory, D.Size);
}
Test("Memory Arena")
{
gs_allocator Al = CreateAllocator(Win32Alloc, Win32Free);
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4);
gs_allocator Al = CreatePlatformAllocator();
gs_memory_arena A = MemoryArenaCreate(128, 4, Al, 0, 0, "Test");
// NOTE(PS): We loop through this block 3 times
// 1. Make sure the arena works out of the box
@ -76,42 +73,40 @@ MemoryArenaTests()
// 3. Make sure the arena works the same way after freeing
for (int i = 0; i < 3; i++)
{
gs_data D0 = PushSize_(&A, 32, FileNameAndLineNumberString);
gs_data D0 = PushSize_(&A, 32, DEBUG_LOC);
TestResult(D0.Size == 32);
// NOTE(PS): This should still result in 32 bytes
// because its going to align the Cursor after
// it allocates to a multiple of 4 bytes
gs_data D1 = PushSize_(&A, 30, FileNameAndLineNumberString);
gs_data D1 = PushSize_(&A, 30, DEBUG_LOC);
TestResult(D1.Size == 32);
// NOTE(PS): Allocating bigger than the size remaining
// in the current cursor
gs_data D2 = PushSize_(&A, 128, FileNameAndLineNumberString);
gs_data D2 = PushSize_(&A, 128, DEBUG_LOC);
TestResult(D2.Size == 128);
TestResult(A.CursorsCount != 1);
TestResult(A.CursorsRoot != A.CursorsHead);
// NOTE(PS): Because there is still room in cursor
// 0, the head of this gs_data should be one byte
// past the end of D1
gs_data D3 = PushSize_(&A, 32, FileNameAndLineNumberString);
gs_data D3 = PushSize_(&A, 32, DEBUG_LOC);
TestResult(D3.Memory == D1.Memory + D1.Size);
if (i == 0)
{
ClearArena(&A);
MemoryArenaClear(&A);
} else if (i == 1) {
FreeMemoryArena(&A);
MemoryArenaFree(&A);
}
}
}
FreeMemoryArena(&A);
}
Test("Memory Arena: Push")
Test("Memory Arena - Push")
{
gs_allocator Al = CreateAllocator(Win32Alloc, Win32Free);
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4);
gs_allocator Al = CreatePlatformAllocator();
gs_memory_arena A = MemoryArenaCreate(128, 8, Al, 0, 0, "Test");
// NOTE(PS): This makes sure that the Arena is moving its next allocation
// pointer forward the appropriate amount after each allocation. If it isnt'
@ -133,16 +128,21 @@ MemoryArenaTests()
}
TestResult(Success);
FreeArena(&A);
}
int FreeCount = 0;
int ClearCount = 0;
Test("Memory Arena: Stress Test")
gs_debug_allocations_list* DEBUGAllocations = 0;
Test("Memory Arena - Stress Test")
{
gs_allocator Al = CreateAllocator(Win32Alloc, Win32Free);
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4);
// NOTE(PS): We're going to create thousands of allocations
// on the allocator of varying sizes. We're also going to clear
// and free the arena at random times to make sure it all works.
gs_allocator Al = CreatePlatformAllocator();
gs_memory_arena A = MemoryArenaCreate(4096, 4, Al, 0, 0, "Test");
// NOTE(PS): This is an array of allocation sizes
// As we repeat the loop we will get values out of this array
@ -157,19 +157,19 @@ MemoryArenaTests()
u32 RandomSeed = 1923;
for (u64 i = 0; i < (4096 * 14); i++)
{
TESTNextRandom(&RandomSeed);
NextRandom(&RandomSeed);
u32 SizeIndex = RandomSeed % RandomSizesCount;
u64 RandomSize = RandomSizes[SizeIndex];
if (RandomSize == 0)
{
ClearArena(&A);
MemoryArenaClear(&A);
ClearCount++;
} else if (RandomSize == 2) {
FreeArena(&A);
MemoryArenaFree(&A);
FreeCount++;
} else {
gs_data D = PushSize_(&A, RandomSize, FileNameAndLineNumberString);
gs_data D = PushSize_(&A, RandomSize, DEBUG_LOC);
// NOTE(PS): This check has to be >= because the arena
// might have adjusted to maintain alignment on this
// allocation.
@ -179,6 +179,24 @@ MemoryArenaTests()
TestResult(Success);
DEBUGAllocations = Al.DEBUGAllocList;
}
printf("\tMemory Arena Cleared: %d times\n", ClearCount);
printf("\tMemory Arena Freed: %d times\n", FreeCount);
#if 0
printf("\n\nAllocations:\n");
for (gs_debug_memory_allocation* ARecord = DEBUGAllocations->Root;
ARecord != 0;
ARecord = ARecord->Next)
{
printf("\t");
printf("%lld\t%s:%d - %s\n",
ARecord->Size,
ARecord->Loc.File,
ARecord->Loc.Line,
ARecord->Loc.Function);
}
#endif
}

View File

@ -14,11 +14,10 @@
#include "../gs_libs/gs_path.h"
#include "../gs_libs/gs_csv.h"
#include "../app/platform_win32/win32_foldhaus_memory.h"
#include "./memory_arena_tests.cpp"
gs_memory_arena Scratch = {};
void* Alloc(u64 Size, u64* ResultSize) { *ResultSize = Size; return malloc(Size); }
void Free(void* Ptr, u64 Size) { return free(Ptr); }
bool StringTest (gs_const_string StrA, gs_const_string StrB)
{
@ -38,9 +37,76 @@ Flower A 55 32 128 foo, bar, blah, baz, whatever
Flower B 123 344 32 foo, bar, blah, baz, whatever
Flower C 55 32 128 foo, bar, blah, baz, whatever)FOO";
struct test_sll
{
u32 Val;
test_sll* Next;
};
int main (int ArgCount, char** Args)
{
Scratch = CreateMemoryArena(CreateAllocator(Alloc, Free), "Scratch");
gs_allocator Al = CreatePlatformAllocator();
Scratch = MemoryArenaCreate(KB(4), Bytes(8), Al, 0, 0, "Scratch");
Test("SLL 1")
{
test_sll* Root = 0;
test_sll* Head = 0;
test_sll* First = PushStruct(&Scratch, test_sll);
First->Val = 0;
SLLInit(Root, Head, First);
TestResult((Root == First) && (Head == First));
for (u32 i = 1; i < 4; i++)
{
test_sll* New = PushStruct(&Scratch, test_sll);
New->Val = i;
SLLPush(Head, New);
TestResult((Root == First) && (Head == New));
}
bool Success = true;
u32 i = 0;
for (test_sll* At = Root;
At && At->Next != 0;
SLLNext(At))
{
Success &= (At->Val == i);
i += 1;
}
TestResult(Success);
}
Test("SLL Push Or Init")
{
test_sll* Root = 0;
test_sll* Head = 0;
test_sll* First = PushStruct(&Scratch, test_sll);
First->Val = 0;
SLLPushOrInit(Root, Head, First);
TestResult((Root == First) && (Head == First));
for (u32 i = 1; i < 4; i++)
{
test_sll* New = PushStruct(&Scratch, test_sll);
New->Val = i;
SLLPushOrInit(Root, Head, New);
TestResult((Root == First) && (Head == New));
}
bool Success = true;
u32 i = 0;
for (test_sll* At = Root;
At && At->Next != 0;
SLLNext(At))
{
Success &= (At->Val == i);
i += 1;
}
TestResult(Success);
}
Test("gs_string")
{