finished free list allocator (linked list) and added small test
This commit is contained in:
parent
f57018317a
commit
7602982c93
2
build.sh
2
build.sh
@ -57,7 +57,7 @@ clang_out="-o"
|
||||
gcc_common="${include_flags} ${render_flag} -DCOMPILER_GCC -std=c99 -fuse-ld=mold -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -DVMA_STATIC_VULKAN_FUNCTIONS=0"
|
||||
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common}"
|
||||
gcc_release="$compiler -O2 ${gcc_common} ${render_flag}"
|
||||
gcc_test="$compiler -O2 -DBUILD_TEST=1 ${gcc_common} ${render_flag}"
|
||||
gcc_test="$compiler -O0 -DBUILD_TEST=1 ${gcc_common} ${render_flag}"
|
||||
gcc_link="-lpthread -lm -lrt -ldl ${render_link} -lstdc++"
|
||||
gcc_out="-o"
|
||||
|
||||
|
||||
259
src/allocators.c
259
src/allocators.c
@ -1,7 +1,7 @@
|
||||
// ::Allocator::Globals::
|
||||
|
||||
Allocator g_alloc;
|
||||
read_only FLNode FL_NIL_NODE = {};
|
||||
read_only FLNode FL_NIL_NODE = {0};
|
||||
|
||||
// ::Allocator::Util::Header::
|
||||
|
||||
@ -95,6 +95,8 @@ static Arena * CreateArenaDebug(rawptr buffer, usize length, u32 init_line_no)
|
||||
|
||||
// ::Allocator::Arena::End::
|
||||
|
||||
|
||||
|
||||
// ::Allocator::GlobalAlloc::Start::
|
||||
|
||||
static void InitAllocator(usize init_size, usize grow_size)
|
||||
@ -152,34 +154,71 @@ static void AllocGrow()
|
||||
|
||||
}
|
||||
|
||||
// ::Allocator::FreeList::End::
|
||||
// ::Allocator::GlobalAlloc::End::
|
||||
|
||||
static void FLAllocInit(FLAlloc *alloc, usize size)
|
||||
|
||||
|
||||
// ::Allocator::FreeList::Start::
|
||||
|
||||
static void FreeListInit(FLAlloc *alloc, usize size)
|
||||
{
|
||||
alloc->data = MemAllocZeroed(size);
|
||||
alloc->size = size;
|
||||
alloc->lists = MemAllocZeroed(sizeof(FreeList *) * 16);
|
||||
alloc->list_count = 1;
|
||||
alloc->list_capacity = 16;
|
||||
alloc->ticket = 0;
|
||||
alloc->next_ticket = 0;
|
||||
alloc->nil = &FL_NIL_NODE;
|
||||
FLAllocFreeAll(alloc);
|
||||
alloc->grow_size = size;
|
||||
|
||||
_FreeListInit(&alloc->lists[0], size);
|
||||
|
||||
FreeListFreeAll(alloc);
|
||||
}
|
||||
|
||||
static void FLAllocFreeAll(FLAlloc *alloc)
|
||||
static void _FreeListInit(FreeList **alloc, usize size)
|
||||
{
|
||||
FLNode *node = (FLNode *)alloc->data;
|
||||
node->size = alloc->size;
|
||||
node->next = alloc->nil;
|
||||
|
||||
alloc->used = 0;
|
||||
alloc->head = node;
|
||||
*alloc = (FreeList *)MemAllocZeroed(size);
|
||||
(*alloc)->data = (rawptr)(((uintptr)*alloc) + ((uintptr)sizeof(FreeList)));
|
||||
(*alloc)->size = size;
|
||||
(*alloc)->used = sizeof(FreeList);
|
||||
}
|
||||
|
||||
static FLNode *FreeListSearch(FLAlloc *alloc, usize size, u32 alignment, u32 *out_padding, FLNode **prev_node)
|
||||
static void FreeListFreeAll(FLAlloc *alloc)
|
||||
{
|
||||
u32 ticket = __atomic_fetch_add(&alloc->ticket, 1, __ATOMIC_SEQ_CST);
|
||||
while (ticket != alloc->next_ticket);
|
||||
|
||||
if (alloc->list_count > 1)
|
||||
{
|
||||
for (u32 i = 1; i < alloc->list_count; i++)
|
||||
{
|
||||
MemFree(alloc->lists[i], alloc->lists[i]->size);
|
||||
alloc->lists[i] = NULL;
|
||||
}
|
||||
|
||||
alloc->list_count = 1;
|
||||
}
|
||||
|
||||
FLNode *node = (FLNode *)alloc->lists[0]->data;
|
||||
node->size = alloc->lists[0]->size;
|
||||
node->next = &FL_NIL_NODE;
|
||||
|
||||
alloc->lists[0]->head = node;
|
||||
alloc->lists[0]->used = sizeof(FreeList);
|
||||
|
||||
__atomic_thread_fence(__ATOMIC_RELEASE);
|
||||
|
||||
__atomic_fetch_add(&alloc->next_ticket, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
static FLNode *FreeListSearch(FreeList *alloc, usize size, usize alignment, usize *out_padding, FLNode **prev_node)
|
||||
{
|
||||
FLNode *node = alloc->head;
|
||||
FLNode *prev = alloc->nil;
|
||||
FLNode *prev = &FL_NIL_NODE;
|
||||
|
||||
usize padding = 0;
|
||||
|
||||
while (node != alloc->nil)
|
||||
while (node != &FL_NIL_NODE)
|
||||
{
|
||||
padding = CalcPaddingWithHeader((uintptr)node, (uintptr)alignment, sizeof(FLNode));
|
||||
usize required_size = size + padding;
|
||||
@ -199,12 +238,194 @@ static FLNode *FreeListSearch(FLAlloc *alloc, usize size, u32 alignment, u32 *ou
|
||||
return node;
|
||||
}
|
||||
|
||||
static rawptr FreeListAlloc(FLAlloc *alloc, usize size, u32 alignment)
|
||||
/*
|
||||
* NOT SAFE TO CALL OUTSIDE OF FreeListAlloc
|
||||
*/
|
||||
static void FreeListGrow(FLAlloc *alloc, usize alloc_size)
|
||||
{
|
||||
alloc->list_count += 1;
|
||||
u32 i = alloc->list_count;
|
||||
if (i >= alloc->list_capacity)
|
||||
{
|
||||
alloc->list_capacity += 16;
|
||||
rawptr new_mem = MemAlloc(sizeof(FreeList *) * alloc->list_capacity);
|
||||
MemCpy(new_mem, alloc->lists, i);
|
||||
MemFree(alloc->lists, sizeof(FreeList *) * i);
|
||||
alloc->lists = new_mem;
|
||||
}
|
||||
|
||||
usize grow_size = alloc->grow_size;
|
||||
if (alloc_size > grow_size)
|
||||
grow_size += alloc_size;
|
||||
|
||||
_FreeListInit(&alloc->lists[i], grow_size);
|
||||
|
||||
FLNode *node = (FLNode *)alloc->lists[i]->data;
|
||||
node->size = alloc->lists[i]->size;
|
||||
node->next = alloc->nil;
|
||||
|
||||
alloc->lists[i]->head = node;
|
||||
}
|
||||
|
||||
static rawptr _FreeListAllocAlign(FreeList *alloc, usize size, u32 alignment)
|
||||
{
|
||||
usize padding = 0;
|
||||
FLNode *prev_node = alloc->nil;
|
||||
FLNode *prev_node = &FL_NIL_NODE;
|
||||
|
||||
FLAllocHeader *header;
|
||||
|
||||
if (size < sizeof(FLNode))
|
||||
size = sizeof(FLNode);
|
||||
|
||||
return NULL;
|
||||
if (alignment < 8)
|
||||
alignment = 8;
|
||||
|
||||
FLNode *node = FreeListSearch(alloc, size, alignment, &padding, &prev_node);
|
||||
|
||||
if (node == &FL_NIL_NODE)
|
||||
Assert(0, "FreeListAllocAlign failed to allocate, oom");
|
||||
|
||||
usize alignment_padding = padding - sizeof(FLAllocHeader);
|
||||
usize required_space = size + padding;
|
||||
usize remaining = node->size - required_space;
|
||||
|
||||
if (remaining > 0)
|
||||
{
|
||||
FLNode *new_node = (FLNode *)(((c8 *)node) + required_space);
|
||||
new_node->size = remaining;
|
||||
FreeListInsert(&alloc->head, node, new_node);
|
||||
}
|
||||
|
||||
FreeListRemove(&alloc->head, prev_node, node);
|
||||
|
||||
header = (FLAllocHeader *)(((c8 *)node) + alignment_padding);
|
||||
header->size = required_space;
|
||||
header->padding = alignment_padding;
|
||||
|
||||
alloc->used += required_space;
|
||||
|
||||
return (rawptr)(((c8 *)header) + sizeof(FLAllocHeader));
|
||||
}
|
||||
|
||||
static rawptr FreeListAlloc(FLAlloc *alloc, usize size)
|
||||
{
|
||||
return FreeListAllocAlign(alloc, size, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, u32 alignment)
|
||||
{
|
||||
u32 ticket = __atomic_fetch_add(&alloc->ticket, 1, __ATOMIC_SEQ_CST);
|
||||
while (ticket != alloc->next_ticket);
|
||||
|
||||
FreeList *fl = NULL;
|
||||
for (u32 i = 0; i < alloc->list_count; i++)
|
||||
{
|
||||
usize remaining = alloc->lists[i]->size - alloc->lists[i]->used;
|
||||
if (size < remaining)
|
||||
{
|
||||
fl = alloc->lists[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fl == NULL)
|
||||
{
|
||||
FreeListGrow(alloc, size);
|
||||
fl = alloc->lists[alloc->list_count-1];
|
||||
}
|
||||
|
||||
rawptr ptr = _FreeListAllocAlign(fl, size, alignment);
|
||||
|
||||
__atomic_thread_fence(__ATOMIC_RELEASE);
|
||||
|
||||
__atomic_add_fetch(&alloc->next_ticket, 1, __ATOMIC_SEQ_CST);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void _FreeListFree(FreeList *alloc, rawptr ptr)
|
||||
{
|
||||
FLAllocHeader *header = cast(FLAllocHeader *, u8ptr(ptr) - sizeof(FLAllocHeader));
|
||||
FLNode *free_node = cast(FLNode *,header);
|
||||
free_node->size = header->size + header->padding;
|
||||
free_node->next = &FL_NIL_NODE;
|
||||
|
||||
FLNode *prev_node = &FL_NIL_NODE;
|
||||
FLNode *node = alloc->head;
|
||||
while (node != &FL_NIL_NODE)
|
||||
{
|
||||
if (ptr < node)
|
||||
{
|
||||
FreeListInsert(&alloc->head, prev_node, free_node);
|
||||
break;
|
||||
}
|
||||
|
||||
prev_node = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
alloc->used -= free_node->size;
|
||||
|
||||
FreeListCoalescence(alloc, prev_node, free_node);
|
||||
}
|
||||
|
||||
static void FreeListFree(FLAlloc *alloc, rawptr ptr)
|
||||
{
|
||||
if (ptr == NULL) return;
|
||||
|
||||
u32 ticket = __atomic_fetch_add(&alloc->ticket, 1, __ATOMIC_SEQ_CST);
|
||||
while (ticket != alloc->next_ticket);
|
||||
|
||||
for (u32 i = 0; i < alloc->list_count; i++)
|
||||
{
|
||||
uintptr ptr_addr = uintptr(ptr);
|
||||
uintptr start = uintptr(alloc->lists[i]->data);
|
||||
uintptr end = uintptr(alloc->lists[i]->data) + uintptr(alloc->lists[i]->size);
|
||||
if (ptr_addr >= start && ptr_addr < end)
|
||||
{
|
||||
_FreeListFree(alloc->lists[i], ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FreeListCoalescence(FreeList *alloc, FLNode *prev_node, FLNode *free_node)
|
||||
{
|
||||
if (free_node->next != &FL_NIL_NODE && (rawptr)(((c8 *)free_node) + free_node->size) == free_node->next)
|
||||
{
|
||||
free_node->size += free_node->next->size;
|
||||
FreeListRemove(&alloc->head, free_node, free_node->next);
|
||||
}
|
||||
|
||||
if (prev_node->next != &FL_NIL_NODE && (rawptr)(((c8 *)prev_node) + prev_node->size) == free_node)
|
||||
{
|
||||
prev_node->size += free_node->next->size;
|
||||
FreeListRemove(&alloc->head, prev_node, free_node);
|
||||
}
|
||||
}
|
||||
|
||||
static void FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node)
|
||||
{
|
||||
if (prev_node == &FL_NIL_NODE)
|
||||
*head = del_node->next;
|
||||
else
|
||||
prev_node->next = del_node->next;
|
||||
}
|
||||
|
||||
static void FreeListInsert(FLNode **head, FLNode *prev_node, FLNode *new_node)
|
||||
{
|
||||
if (prev_node == &FL_NIL_NODE)
|
||||
{
|
||||
if (*head != &FL_NIL_NODE)
|
||||
new_node->next = *head;
|
||||
else
|
||||
*head = new_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_node->next = prev_node->next;
|
||||
prev_node->next = new_node;
|
||||
}
|
||||
}
|
||||
|
||||
// ::Allocator::FreeList::End::
|
||||
|
||||
@ -58,7 +58,7 @@ static void Free(rawptr ptr);
|
||||
|
||||
typedef struct FLAllocHeader
|
||||
{
|
||||
usize block_size;
|
||||
usize size;
|
||||
usize padding;
|
||||
} FLAllocHeader;
|
||||
|
||||
@ -70,16 +70,35 @@ typedef struct FLNode
|
||||
usize size;
|
||||
} FLNode;
|
||||
|
||||
typedef struct FLAlloc
|
||||
typedef struct FreeList
|
||||
{
|
||||
rawptr data;
|
||||
FLNode *head;
|
||||
FLNode *nil;
|
||||
usize size;
|
||||
usize used;
|
||||
} FreeList;
|
||||
|
||||
typedef struct FLAlloc
|
||||
{
|
||||
FreeList **lists;
|
||||
u32 list_count;
|
||||
u32 list_capacity;
|
||||
u32 volatile ticket;
|
||||
u32 volatile next_ticket;
|
||||
FLNode *nil;
|
||||
usize grow_size;
|
||||
} FLAlloc;
|
||||
|
||||
static void FLAllocInit(FLAlloc *alloc, usize size);
|
||||
static void FLAllocFreeAll(FLAlloc *alloc);
|
||||
static FLNode *FreeListSearch(FLAlloc *alloc, usize size, u32 alignment, u32 *out_padding, FLNode **prev_node);
|
||||
static rawptr FreeListAlloc(FLAlloc *alloc, usize size, u32 alignment);
|
||||
static void _FreeListInit(FreeList **alloc, usize size);
|
||||
static void FreeListInit(FLAlloc *alloc, usize size);
|
||||
static rawptr _FreeListAllocAlign(FreeList *alloc, usize size, u32 alignment);
|
||||
static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, u32 alignment);
|
||||
static rawptr FreeListAlloc(FLAlloc *alloc, usize size);
|
||||
static void _FreeListFree(FreeList *alloc, rawptr ptr);
|
||||
static void FreeListFree(FLAlloc *alloc, rawptr ptr);
|
||||
static void FreeListFreeAll(FLAlloc *alloc);
|
||||
static void FreeListGrow(FLAlloc *alloc, usize alloc_size);
|
||||
static FLNode *FreeListSearch(FreeList *alloc, usize size, usize alignment, usize *out_padding, FLNode **prev_node);
|
||||
static void FreeListCoalescence(FreeList *alloc, FLNode *prev_node, FLNode *free_node);
|
||||
static void FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node);
|
||||
static void FreeListInsert(FLNode **head, FLNode *prev_node, FLNode *new_node);
|
||||
|
||||
@ -108,7 +108,7 @@ int main(int argc, char **argv)
|
||||
|
||||
WaitForWindowEvent(inputs);
|
||||
|
||||
GameContext ctx = {};
|
||||
GameContext ctx = {0};
|
||||
|
||||
InitializeGame(renderer_arena, &ctx, game_arena);
|
||||
|
||||
|
||||
@ -31,8 +31,8 @@ const FileMapping g_Texture_File_Map[] = {
|
||||
{ .file_name = "purplemon.png", .ix = PATTERMON_PURPLOID },
|
||||
};
|
||||
|
||||
c8 *g_Shader_File_Names[SHADER_ASSET_MAX] = {};
|
||||
c8 *g_Texture_File_Names[TEXTURE_ASSET_MAX] = {};
|
||||
c8 *g_Shader_File_Names[SHADER_ASSET_MAX] = {0};
|
||||
c8 *g_Texture_File_Names[TEXTURE_ASSET_MAX] = {0};
|
||||
|
||||
// ::Packer::Globals::End::
|
||||
|
||||
@ -380,7 +380,7 @@ int main(int argc, c8 **argv)
|
||||
FILE *file = fopen("assets.sgp", "w+");
|
||||
Assert(file != NULL, "File is null");
|
||||
|
||||
FileHeader header = {};
|
||||
FileHeader header = {0};
|
||||
InitHeader(&header);
|
||||
|
||||
PackFiles(arena, &header);
|
||||
|
||||
@ -17,7 +17,7 @@ static Renderer renderer = {
|
||||
}
|
||||
};
|
||||
|
||||
static u32 vk_thread_indices[10] = {};
|
||||
static u32 vk_thread_indices[10] = {0};
|
||||
|
||||
#if __linux__
|
||||
pthread_cond_t cond;
|
||||
|
||||
@ -209,8 +209,8 @@ static b32 UploadToBuffer(RenderBuffer **buffers, rawptr *ptrs, u32 count, u8 th
|
||||
VkDevice device = renderer.vk.device;
|
||||
VkQueue queue = renderer.vk.queues.transfer_queue;
|
||||
VmaAllocator alloc = renderer.vk.alloc;
|
||||
rawptr mapped_buffers[16] = {};
|
||||
RenderBuffer staging_buffers[16] = {};
|
||||
rawptr mapped_buffers[16] = {0};
|
||||
RenderBuffer staging_buffers[16] = {0};
|
||||
|
||||
u32 copy_count = 0;
|
||||
|
||||
|
||||
45
src/tests.c
45
src/tests.c
@ -1,5 +1,48 @@
|
||||
|
||||
void RunTests()
|
||||
{
|
||||
|
||||
TestFreeListAlloc();
|
||||
}
|
||||
|
||||
void TestFreeListAlloc()
|
||||
{
|
||||
FLAlloc alloc = {0};
|
||||
usize alloc_size = KB(256);
|
||||
FreeListInit(&alloc, alloc_size);
|
||||
u8 *value = (u8 *)(uintptr(alloc.lists[0]->data) + uintptr(alloc_size-sizeof(FreeList)-2));
|
||||
*value = 255;
|
||||
Assert(*value == 255, "data set is invalid");
|
||||
|
||||
u32 u32_count = 2000;
|
||||
u32 f64_count = 3000;
|
||||
|
||||
u32 *u32_arr = FreeListAlloc(&alloc, sizeof(u32) * u32_count);
|
||||
f64 *f64_arr = FreeListAlloc(&alloc, sizeof(f64) * f64_count);
|
||||
|
||||
for (u32 i = 0; i < u32_count; i++)
|
||||
{
|
||||
u32_arr[i] = 3 * i;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < f64_count; i++)
|
||||
{
|
||||
f64_arr[i] = f64(i);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < u32_count; i++)
|
||||
{
|
||||
Assert(u32_arr[i] == 3 * i, "u32 memory incorrect");
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < f64_count; i++)
|
||||
{
|
||||
Assert(f64_arr[i] == f64(i), "f64 memory incorrect");
|
||||
}
|
||||
|
||||
FreeListFree(&alloc, u32_arr);
|
||||
|
||||
for (u32 i = 0; i < f64_count; i++)
|
||||
{
|
||||
Assert(f64_arr[i] == f64(i), "f64 memory incorrect post free");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void RunTests();
|
||||
void TestFreeListAlloc();
|
||||
|
||||
|
||||
25
src/util.h
25
src/util.h
@ -24,6 +24,31 @@ typedef struct Arena Arena;
|
||||
#define Str8L(x) (Str8){ .len = StrLen(x), .value = (u8 *)x }
|
||||
#define MakeString(x) #x
|
||||
|
||||
#define i8(x) ((i8)(x))
|
||||
#define i16(x) ((i16)(x))
|
||||
#define i32(x) ((i32)(x))
|
||||
#define i64(x) ((i64)(x))
|
||||
|
||||
#define u8(x) ((u8)(x))
|
||||
#define u16(x) ((u16)(x))
|
||||
#define u32(x) ((u32)(x))
|
||||
#define u64(x) ((u64)(x))
|
||||
|
||||
#define c8(x) ((c8)(x))
|
||||
#define c8ptr(x) ((c8 *)(x))
|
||||
#define u8ptr(x) ((u8 *)(x))
|
||||
#define i8ptr(x) ((i8 *)(x))
|
||||
|
||||
#define intptr(x) ((intptr)(x))
|
||||
#define uintptr(x) ((uintptr)(x))
|
||||
|
||||
#define f32(x) ((f32)(x))
|
||||
#define f64(x) ((f64)(x))
|
||||
|
||||
#define rawptr(x) ((rawptr)(x))
|
||||
|
||||
#define cast(T, x) ((T)(x))
|
||||
|
||||
// ::Util::Defines::Header::
|
||||
|
||||
#define HM_MAX_SYMBOLS 256
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user