From c27b20098440ee69e1635a6600741a8671eb73fe Mon Sep 17 00:00:00 2001 From: Matthew Date: Sun, 20 Apr 2025 12:24:33 +1000 Subject: [PATCH] hash table + basic profiler implemented, now using c23 --- src/allocators.c | 60 +++++++-------- src/allocators.h | 15 ++-- src/ds.c | 111 ++++++++++++++++++++++++--- src/ds.h | 26 +++++-- src/entry_linux.c | 8 +- src/entry_windows.c | 6 +- src/game.c | 4 +- src/packer.c | 2 +- src/platform/platform.h | 6 ++ src/platform/platform_linux.h | 2 + src/platform/platform_linux_public.c | 24 ++++++ src/renderer.h | 1 - src/renderer_vulkan_public.c | 2 +- src/shared_types.h | 6 +- src/tests.c | 29 +++++++ src/tests.h | 1 + src/util.c | 47 ++++++++++-- src/util.h | 95 +++++++++++++++++++++-- 18 files changed, 365 insertions(+), 80 deletions(-) diff --git a/src/allocators.c b/src/allocators.c index 12736a8..94d5c34 100644 --- a/src/allocators.c +++ b/src/allocators.c @@ -4,6 +4,8 @@ FLAlloc FL_ALLOC = {0}; Allocator ALLOC = {0}; read_only FLNode FL_NIL_NODE = {0}; +#define ALLOC_CAP 16 + // ::Allocator::Util::Header:: usize CalcPaddingWithHeader(uintptr ptr, uintptr alignment, usize header_size) @@ -32,7 +34,7 @@ usize CalcPaddingWithHeader(uintptr ptr, uintptr alignment, usize header_size) // ::Allocator::Arena::Start:: -static Arena *CreateArena(rawptr buffer, usize length) +static Arena *ArenaInit(rawptr buffer, usize length) { Arena *arena = (Arena *)buffer; buffer = PtrAdd(buffer, ARENA_HEADER_SIZE); @@ -87,9 +89,9 @@ static void DeallocArena(Arena *arena) MemFree(arena, arena->length); } -static Arena * CreateArenaDebug(rawptr buffer, usize length, u32 init_line_no) +static Arena * ArenaInitDebug(rawptr buffer, usize length, u32 init_line_no) { - Arena *arena = CreateArena(buffer, length); + Arena *arena = ArenaInit(buffer, length); arena->init_line_no = init_line_no; return arena; } @@ -100,45 +102,43 @@ static Arena * CreateArenaDebug(rawptr buffer, usize length, u32 init_line_no) // ::Allocator::GlobalAlloc::Start:: -static void InitAllocator(usize init_size, usize grow_size) +static void InitAllocator(usize init_size) { - usize size = init_size + sizeof(Allocator) + sizeof(FreeListBuffer) + sizeof(rawptr) + sizeof(RBNode); - u8 *mem = (u8 *)MemAllocZeroed(size); - Allocator *fl_alloc = (Allocator *)mem; + ALLOC.tree = FLMemAlloc(sizeof(RBTree)); + RBTreeInit(ALLOC.tree); - u8 *pre_mem = mem; - mem = (u8 *)PtrAdd(mem, sizeof(Alloc)); - usize rem_size = (size) - (pre_mem - mem); + ALLOC.hash_table = FLMemAlloc(sizeof(HashTable)); + HashTableInit(ALLOC.hash_table, 32); - fl_alloc->buf_len = 1; - fl_alloc->grow_size = grow_size; - fl_alloc->buffers = (FreeListBuffer *)mem; + ALLOC.buffers = FLMemAlloc(sizeof(FreeListBuffer) * ALLOC_CAP); + ALLOC.count = 1; + ALLOC.cap = ALLOC_CAP; + ALLOC.grow_size = init_size; - pre_mem = mem; - mem = (u8 *)PtrAdd(mem, sizeof(FreeListBuffer)); - rem_size -= pre_mem - mem; - - fl_alloc->nil = (RBNode *)mem; - - pre_mem = mem; - mem = (u8 *)PtrAdd(mem, sizeof(RBNode)); - rem_size -= pre_mem - mem; - - fl_alloc->buffers[0].buf = mem; - fl_alloc->buffers[0].size = (u32)size; - fl_alloc->buffers[0].free_size = (u32)rem_size; + InitAllocatorBuffer(&ALLOC.buffers[0], init_size); +} +static void InitAllocatorBuffer(FreeListBuffer *buffer, usize init_size) +{ + buffer->buf = MemAllocZeroed(init_size); + buffer->size = init_size; + buffer->free_size = init_size; } static void DeinitAlloc() { - for (u8 i = ALLOC.buf_len-1; i >= 0; i--) + for (u8 i = 0; i < ALLOC.count; i++) { MemFree(ALLOC.buffers[i].buf, ALLOC.buffers[i].size); } } static rawptr Alloc(usize size) +{ + return AllocAlign(size, DEFAULT_ALIGNMENT); +} + +static rawptr AllocAlign(usize size, usize alignment) { return NULL; } @@ -150,9 +150,9 @@ static void Free(rawptr ptr) static void AllocGrow() { - u8 *mem = (u8 *)MemAllocZeroed(ALLOC.grow_size); - - + Assert(ALLOC.count < ALLOC.cap, "Global allocator has reached capacity"); + InitAllocatorBuffer(&ALLOC.buffers[ALLOC.count], ALLOC.grow_size); + ALLOC.count += 1; } // ::Allocator::GlobalAlloc::End:: diff --git a/src/allocators.h b/src/allocators.h index 26fec24..ce5b705 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -22,13 +22,13 @@ typedef struct TempArena u64 pos; } TempArena; -static Arena *CreateArena(rawptr buffer, usize length); +static Arena *ArenaInit(rawptr buffer, usize length); static rawptr ArenaAllocAlign(Arena *arena, usize size, usize align); static rawptr ArenaAlloc(Arena *arena, usize size); static void ArenaFree(Arena *arena); static void ArenaFreeZeroed(Arena *arena); static void DeallocArena(Arena *arena); -static Arena *CreateArenaDebug(rawptr buffer, usize length, u32 init_line_no); +static Arena *ArenaInitDebug(rawptr buffer, usize length, u32 init_line_no); // ::Allocator::GlobalAlloc::Header:: @@ -41,17 +41,20 @@ typedef struct FreeListBuffer typedef struct Allocator { - RBNode *head; - RBNode *nil; + RBTree *tree; FreeListBuffer *buffers; + HashTable *hash_table; usize grow_size; - u8 buf_len; + u64 count; + u64 cap; } Allocator; -static void InitAllocator(usize init_size, usize grow_size); +static void InitAllocator(usize init_size); +static void InitAllocatorBuffer(FreeListBuffer *buffer, usize init_size); static void DeinitAlloc(); static void AllocGrow(); static rawptr Alloc(usize size); +static rawptr AllocAlign(usize size, usize alignment); static void Free(rawptr ptr); // ::Allocator::FreeList::Header:: diff --git a/src/ds.c b/src/ds.c index f29479e..b6ed31d 100644 --- a/src/ds.c +++ b/src/ds.c @@ -1,6 +1,10 @@ // ::DataStructures::Globals::Start:: RBNode RB_NIL = { .color = RB_BLACK }; +RBNode *P_RB_NIL = &RB_NIL; + +HashNode HT_NIL = {0}; +HashNode *P_HT_NIL = &HT_NIL; // ::DataStructures::Globals::End:: @@ -8,17 +12,19 @@ RBNode RB_NIL = { .color = RB_BLACK }; // ::DataStructures::RedBlackTree::Functions::Start:: -static void CreateRBTree(RBTree *tree) +static void RBTreeInit(RBTree *tree) { Assert(tree != NULL, "RBTree is null"); - RB_NIL.right = RB_NIL.left = RB_NIL.parent = &RB_NIL; + RB_NIL.right = RB_NIL.left = RB_NIL.parent = P_RB_NIL; - tree->root = &RB_NIL; - tree->nil = &RB_NIL; + tree->root = P_RB_NIL; + tree->nil = P_RB_NIL; } -static void RBTreeInsert(RBTree *tree, RBNode *node) +static RBNode *RBTreeFindOrInsert(RBTree *tree, RBNode *node) { + RBNode *existing_node = P_RB_NIL; + node->left = node->right = tree->nil; node->color = RB_RED; @@ -35,7 +41,12 @@ static void RBTreeInsert(RBTree *tree, RBNode *node) { Assert(curr_node != tree->nil, "Current Node is NIL"); - if (curr_node->value < node->value) + if (curr_node->value == node->value) + { + existing_node = curr_node; + break; + } + else if (curr_node->value < node->value) { if (curr_node->right == tree->nil) { @@ -64,8 +75,10 @@ static void RBTreeInsert(RBTree *tree, RBNode *node) } } - if (node->parent->color != RB_BLACK) + if (node->parent->color != RB_BLACK && existing_node != P_RB_NIL) RBTreeCorrect(tree, node); + + return existing_node; } static void RBTreeCorrect(RBTree *tree, RBNode *node) @@ -332,15 +345,95 @@ static void RBTreeRightRotate(RBTree *tree, RBNode *node) // ::DataStructures::HashTable::Functions::Start:: -static void InitHashTable(HashTable *table, u32 init_size) +static void HashTableInit(HashTable *table, u32 init_size) { - table->elem_count = init_size; + table->cap = init_size; + table->count = 0; table->lists = FLMemAlloc(sizeof(HashList) * init_size); + table->free_lists.first = P_HT_NIL; + table->free_lists.last = P_HT_NIL; +} + +static void HashTableConcatInPlace(HashList *list, HashList *to_concat) +{ + SLLConcatInPlaceNoCount(list, to_concat); } static void HashTableClear(HashTable *table) { + table->count = 0; + for (u32 i = 0; i < table->count; i++) + { + HashTableConcatInPlace(&table->free_lists, &table->lists[i]); + } +} +static HashNode *HashListPop(HashList *list) +{ + HashNode *result = list->first; + HTQueuePop(list->first, list->last); + return result; +} + +static HashNode *HashTablePush(HashTable *table, u64 hash, KeyValuePair value) +{ + HashNode *node = NULL; + if (table->free_lists.first != P_HT_NIL) + node = HashListPop(&table->free_lists); + else + node = FLMemAlloc(sizeof(HashNode)); + + node->next = P_HT_NIL; + node->v = value; + + u64 index = hash % table->cap; + HTQueuePush(table->lists[index].first, table->lists[index].last, node); + table->count += 1; + + return node; +} + +static HashNode *HashTablePushU32(HashTable *table, u64 key, u32 value) +{ + u64 hash = HashFromString(String8Struct(&key)); + return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u32 = value }); +} + +static HashNode *HashTablePushU64(HashTable *table, u64 key, u64 value) +{ + u64 hash = HashFromString(String8Struct(&key)); + return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u64 = value }); +} + +static HashNode *HashTablePushString8(HashTable *table, u64 key, String8 value) +{ + u64 hash = HashFromString(String8Struct(&key)); + return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_string = value }); +} + +static HashNode *HashTablePushRawptr(HashTable *table, u64 key, rawptr value) +{ + u64 hash = HashFromString(String8Struct(&key)); + return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_rawptr = value }); +} + +static KeyValuePair *HashTableSearchU64(HashTable *table, u64 key) +{ + KeyValuePair *result = NULL; + + u64 hash = HashFromString(String8Struct(&key)); + u64 index = hash % table->cap; + HashList *list = table->lists + index; + for (HashNode *node = list->first; node != P_HT_NIL; node = node->next) + { + if (node->v.key_u64 == key) + { + result = &node->v; + break; + } + } + + return result; } // ::DataStructures::HashTable::Functions::End:: diff --git a/src/ds.h b/src/ds.h index 7cc27f5..4857404 100644 --- a/src/ds.h +++ b/src/ds.h @@ -41,8 +41,8 @@ typedef struct RBTree RBNode *nil; } RBTree; -static void CreateRBTree (RBTree *tree); -static void RBTreeInsert (RBTree *tree, RBNode *node); +static void RBTreeInit (RBTree *tree); +static RBNode *RBTreeFindOrInsert(RBTree *tree, RBNode *node); static b32 RBTreeSearch (RBTree *tree, i32 value, RBNode **node); static void RBTreeDelete (RBTree *tree, i32 value); static void RBTreeLeftRotate (RBTree *tree, RBNode *node); @@ -53,6 +53,10 @@ static void RBTreeTransplant (RBTree *tree, RBNode *node, RBNode *placed_node); // ::DataStructures::HashTable::Functions::Header:: +#define HTQueuePop(f, l) SLLQueuePop(&HT_NIL, f, l) +#define HTQueuePush(f, l, n) SLLQueuePush(&HT_NIL, f, l, n) +#define HTQueuePushFront(f, l, n) SLLQueuePush(&HT_NIL, f, l, n) + typedef struct KeyValuePair { union @@ -61,7 +65,7 @@ typedef struct KeyValuePair }; union { - Str8 value_string; + String8 value_string; rawptr value_rawptr; u32 value_u32; u64 value_u64; @@ -82,15 +86,21 @@ typedef struct HashList typedef struct HashTable { - HashElement *lists; - u32 elem_count; -} HashTable; + HashList *lists; + HashList free_lists; + u64 count; + u32 cap; +} HashTable; -static void InitHashTable(HashTable *table, u32 init_size); +static void HashTableInit(HashTable *table, u32 init_size); static void HashTableClear(HashTable *table); +static void HashTableConcatInPlace(HashList *list, HashList *to_concat); +static u64 HashTableHash(String8 str); +static HashNode *HashListPop(HashList *list); +static KeyValuePair *HashTableSearchU64(HashTable *table, u64 key); static HashNode *HashTablePush(HashTable *table, u64 hash, KeyValuePair value); static HashNode *HashTablePushU32(HashTable *table, u64 key, u32 value); static HashNode *HashTablePushU64(HashTable *table, u64 key, u64 value); -static HashNode *HashTablePushStr8(HashTable *table, u64 key, Str8 value); +static HashNode *HashTablePushString8(HashTable *table, u64 key, String8 value); static HashNode *HashTablePushRawptr(HashTable *table, u64 key, rawptr value); diff --git a/src/entry_linux.c b/src/entry_linux.c index b5b8485..501809a 100644 --- a/src/entry_linux.c +++ b/src/entry_linux.c @@ -16,6 +16,8 @@ # include "tests.c" #endif +static_assert(__COUNTER__ < Len(GLOBAL_PROFILER.anchors)); + void TraverseNode(RBTree *tree, RBNode *node, RBNodeDir *dir) { char *dir_str = dir == NULL ? "Root" : *dir == RB_RIGHT ? "Right" : "Left"; @@ -48,16 +50,16 @@ int main(int argc, char **argv) #endif u8 *mem = (u8 *)MemAllocZeroed(MB(64)); - Arena *arena = CreateArenaDebug(mem, MB(64), __LINE__); + Arena *arena = ArenaInitDebug(mem, MB(64), __LINE__); usize renderer_mem_size = MB(16); usize game_mem_size = MB(16); rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size); - Arena *renderer_arena = CreateArenaDebug(renderer_mem, renderer_mem_size, 2); + Arena *renderer_arena = ArenaInitDebug(renderer_mem, renderer_mem_size, 2); rawptr game_mem = ArenaAlloc(arena, game_mem_size); - Arena *game_arena = CreateArenaDebug(game_mem, game_mem_size, 3); + Arena *game_arena = ArenaInitDebug(game_mem, game_mem_size, 3); Assert(CreatePlatformWindow(WINDOW_NAME), "Failed to initialize the window"); diff --git a/src/entry_windows.c b/src/entry_windows.c index ee7fd0f..94d23b6 100644 --- a/src/entry_windows.c +++ b/src/entry_windows.c @@ -20,16 +20,16 @@ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line #endif u8 *mem = (u8 *)MemAllocZeroed(MB(32)); - Arena *arena = CreateArenaDebug(mem, MB(32), 1); + Arena *arena = ArenaInitDebug(mem, MB(32), 1); isize renderer_mem_size = MB(16); isize game_mem_size = MB(16); rawptr renderer_mem = ArenaAlloc(arena, renderer_mem_size); - Arena *renderer_arena = CreateArenaDebug(renderer_mem, renderer_mem_size, 2); + Arena *renderer_arena = ArenaInitDebug(renderer_mem, renderer_mem_size, 2); rawptr game_mem = ArenaAlloc(arena, game_mem_size); - Arena *game_arena = CreateArenaDebug(game_mem, game_mem_size, 3); + Arena *game_arena = ArenaInitDebug(game_mem, game_mem_size, 3); Assert(CreatePlatformWindow(WINDOW_NAME), "Failed to initialize window"); diff --git a/src/game.c b/src/game.c index 0c5ffa2..b0943b0 100644 --- a/src/game.c +++ b/src/game.c @@ -186,7 +186,7 @@ static inline void PrepareGUICtx(GameContext *ctx) static b32 UIButton(GameContext *ctx, char *label, f32 x0, f32 y0, f32 x1, f32 y1) { GUIButton *btn = NULL; - u64 id = HashFromString(Str8L(label)); + u64 id = HashFromString(String8CStr(label)); if (ctx->btn_len == 0) { ctx->buttons[0].p0.x = x0; @@ -246,7 +246,7 @@ static b32 UIButton(GameContext *ctx, char *label, f32 x0, f32 y0, f32 x1, f32 y static b32 UIWindow(GameContext *ctx, char *title, f32 x0, f32 y0, f32 x1, f32 y1) { GUIWindow *win = NULL; - u32 id = HashFromString(Str8L(title)); + u32 id = HashFromString(String8CStr(title)); if (ctx->window_len == 0) { ctx->windows[0].p0.x = x0; diff --git a/src/packer.c b/src/packer.c index 2b48528..7755f53 100644 --- a/src/packer.c +++ b/src/packer.c @@ -375,7 +375,7 @@ int main(int argc, c8 **argv) SetArrayLookups(); void *mem = MemAllocZeroed(GB(1)); - Arena *arena = CreateArenaDebug(mem, GB(1), __LINE__); + Arena *arena = ArenaInitDebug(mem, GB(1), __LINE__); FILE *file = fopen("assets.sgp", "w+"); Assert(file != NULL, "File is null"); diff --git a/src/platform/platform.h b/src/platform/platform.h index f94a01d..fc53a0d 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -64,3 +64,9 @@ u32 AvailableCPUCount(); b32 ChangeDir(c8 *dir); c8 **GetFileNamesInDir(Arena *arena, u32 *count); b8 DirVisible(c8 *dir_name); + +// ::Platform::Profiling::Functions::Header:: + +static u64 GetOSTimerFreq(); +static u64 ReadOSTimer(); +static inline u64 ReadCPUTimer(); diff --git a/src/platform/platform_linux.h b/src/platform/platform_linux.h index 0be15a9..2930e2b 100644 --- a/src/platform/platform_linux.h +++ b/src/platform/platform_linux.h @@ -23,6 +23,8 @@ #include #include #include +#include +#include // ::Platform::Linux::Defines::Header:: diff --git a/src/platform/platform_linux_public.c b/src/platform/platform_linux_public.c index 3d7a4b0..ffe1fdd 100644 --- a/src/platform/platform_linux_public.c +++ b/src/platform/platform_linux_public.c @@ -305,3 +305,27 @@ b8 DirVisible(c8 *dir_name) } // ::Platform::Functions::Directory::End:: + + + +// ::Platform::Profiling::Functions::Start:: + +static u64 GetOSTimerFreq() +{ + return 1000000; +} + +static u64 ReadOSTimer() +{ + struct timeval value; + gettimeofday(&value, 0); + + return GetOSTimerFreq() * u64(value.tv_sec) + u64(value.tv_usec); +} + +static inline u64 ReadCPUTimer() +{ + return __rdtsc(); +} + +// ::Platform::Profiling::Functions::End:: diff --git a/src/renderer.h b/src/renderer.h index 8a0f251..013f7ba 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -70,7 +70,6 @@ static void BindIndexBuffer(RenderBuffer *buffer); static void GetViewportSize(Vec2 *size); static void SetGlobalUniform(ShaderGlobals *globals); static void SetPushConstants(PushConst *pc); -static DescHandle UploadImageUniform(); // ::Renderer::Config::Header:: diff --git a/src/renderer_vulkan_public.c b/src/renderer_vulkan_public.c index 0ada440..3846011 100644 --- a/src/renderer_vulkan_public.c +++ b/src/renderer_vulkan_public.c @@ -9,7 +9,7 @@ b32 InitRenderer(Arena *arena) Assert(arena != NULL, "Vulkan memory is null"); renderer.perm_arena = arena; void *mem = ArenaAlloc(arena, MB(8)); - renderer.arena = CreateArena(mem, MB(8)); + renderer.arena = ArenaInit(mem, MB(8)); Assert(InitVkGlobalFunctions(), "Unable to load vulkan functions"); { diff --git a/src/shared_types.h b/src/shared_types.h index 285d7a2..111a767 100644 --- a/src/shared_types.h +++ b/src/shared_types.h @@ -177,11 +177,11 @@ typedef uint32_t b32; typedef void * rawptr; -typedef struct Str8 +typedef struct String8 { - u32 len; u8 *value; -} Str8; + u64 len; +} String8; #ifdef __linux__ diff --git a/src/tests.c b/src/tests.c index 9e5cf00..80b514f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1,11 +1,16 @@ +// TODO: Make the tests actually decent void RunTests() { + GlobalFreeListInit(MB(32)); TestFreeListAlloc(); + TestHashTable(); } void TestFreeListAlloc() { + Printfln("Starting free list allocator tests..."); + FLAlloc alloc = {0}; usize alloc_size = KB(256); FreeListInit(&alloc, alloc_size); @@ -46,3 +51,27 @@ void TestFreeListAlloc() Assert(f64_arr[i] == f64(i), "f64 memory incorrect post free"); } } + +void TestHashTable() +{ + Printfln("Starting hash table tests..."); + HashTable table; + HashTableInit(&table, 16); + + for (u64 i = 1; i < 2000; i++) + { + HashTablePushU64(&table, i*3, i); + } + + for (u64 i = 1; i < 2000; i++) + { + KeyValuePair *result = HashTableSearchU64(&table, i*3); + Assert(result != P_HT_NIL, "HashTable result isn't found"); + Assert(result->value_u64 == i, "HashTable result doesn't match"); + } + + HashTableClear(&table); + + KeyValuePair *result = HashTableSearchU64(&table, 1); + Assert(result == NULL, "Result isn't nil after HashTable clear"); +} diff --git a/src/tests.h b/src/tests.h index 99807b7..9789621 100644 --- a/src/tests.h +++ b/src/tests.h @@ -2,4 +2,5 @@ void RunTests(); void TestFreeListAlloc(); +void TestHashTable(); diff --git a/src/util.c b/src/util.c index 571ca41..0fcd460 100644 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,11 @@ +// ::Util::Globals::Start:: + +static Profiler GLOBAL_PROFILER; + +// ::Util::Globals::End:: + + + // ::Util::Strings::Functions::Start:: b32 StrEq(const char *l, const char *r) { @@ -26,12 +34,12 @@ i32 SPrintf(char *buf, rawptr fmt, ...) return sprf_res; } -Str8 MakeStr8(u8 *str, u32 len) +String8 MakeString8(u8 *str, u64 len) { - return (Str8){ .len = len, .value = str }; + return (String8){ .len = len, .value = str }; } -Str8 PreSplitStr8(Str8 string, Str8 delimiter) +String8 PreSplitString8(String8 string, String8 delimiter) { if (string.len == 0 || delimiter.len == 0) return string; @@ -53,12 +61,12 @@ Str8 PreSplitStr8(Str8 string, Str8 delimiter) } } - return (Str8){ .len = new_len, .value = string.value }; + return (String8){ .len = new_len, .value = string.value }; } -Str8 PreSplitNewStr8(Arena *arena, Str8 string, Str8 delimiter) +String8 PreSplitNewString8(Arena *arena, String8 string, String8 delimiter) { - Str8 result = PreSplitStr8(string, delimiter); + String8 result = PreSplitString8(string, delimiter); if (result.len > 0) { @@ -192,9 +200,9 @@ u32 u32Clamp(u32 v, u32 min, u32 max) // ::Util::Hashing::Functions::Start:: -u64 static inline HashFromString(Str8 string) +u64 static inline HashFromString(String8 string) { - return XXH3_64bits_withSeed(string.value, string.len, HASH_SEED); + return XXH3_64bits(string.value, string.len); } // ::Util::Hashing::Functions::End:: @@ -289,3 +297,26 @@ i32 _Printfln(char *fmt, va_list arg) } // ::Util::Print::Functions::End:: + + + +// ::Util::Profiling::Functions::Start:: + +static inline void StartProfileBlock(ProfileBlock *block, c8 *label, u32 anchor_index) +{ + block->anchor_index = anchor_index; + block->label = label; + block->start_tsc = ReadCPUTimer(); +} + +static inline void EndProfileBlock(ProfileBlock *block) +{ + u64 elapsed = ReadCPUTimer() - block->start_tsc; + + ProfileAnchor *anchor = GLOBAL_PROFILER.anchors + block->anchor_index; + anchor->tsc_elapsed += elapsed; + anchor->hit_count += 1; + anchor->label = block->label; +} + +// ::Util::Profiling::Functions::End:: diff --git a/src/util.h b/src/util.h index 641e80f..c7dc30e 100644 --- a/src/util.h +++ b/src/util.h @@ -21,7 +21,6 @@ typedef struct Arena Arena; #define MakeArray(arena, type, count) ArenaAlloc(arena, (isize)(sizeof(type)) * (isize)(count)) #define Len(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) -#define Str8L(x) (Str8){ .len = StrLen(x), .value = (u8 *)x } #define MakeString(x) #x #define i8(x) ((i8)(x)) @@ -49,6 +48,49 @@ typedef struct Arena Arena; #define cast(T, x) ((T)(x)) +// ::Util::LinkedList::Macros:: + +#define CheckNil(nil, p) ((p) == 0 || (p) == nil) +#define SetNil(nil, p) ((p) = nil) + +// ::Util::DoubleHeadedLinkedList::Macros:: + +#define SLLConcatInPlaceNoCount(list, to_concat) do { \ + if ((to_concat)->first) \ + { \ + if ((list)->first) \ + { \ + (list)->last->next = (to_concat)->first; \ + (list)->last = (to_concat)->last; \ + } \ + else \ + { \ + (list)->first = (to_concat)->first; \ + (list)->last = (to_concat)->last; \ + } \ + MemZero(to_concat, sizeof(*to_concat)); \ + } \ +} while (0) +#define _SLLQueuePop(nil, f, l, next) ((f) == (l) ? \ + (SetNil(nil, f), SetNil(nil, l)) : \ + ((f) = (f)->next)) +#define _SLLQueuePushFront(nil, f, l, n, next) (CheckNil(nil, f) ? \ + ((f) = (l) = (n), SetNil(nil, (n)->next)) : \ + ((n)->next = (f), (f) = (n))) +#define _SLLQueuePush(nil, f, l, n, next) (CheckNil(nil, f) ? \ + ((f) = (l) = (n), SetNil(nil, (n)->next)) : \ + ((l)->next = (n), (l) = (n), SetNil(nil, (n)->next))) + +#define SLLQueuePop(nil, f, l) _SLLQueuePop(nil, f, l, next) +#define SLLQueuePush(nil, f, l, n) _SLLQueuePush(nil, f, l, n, next) +#define SLLQueuePushFront(nil, f, l, n) _SLLQueuePushFront(nil, f, l, n, next) + +// ::Util::String8::Macros:: + +#define String8Array(v, c) MakeString8((u8 *)(v), sizeof(*(v))*(c)) +#define String8Struct(v) MakeString8((u8 *)(v), sizeof(*(v))) +#define String8CStr(v) MakeString8((u8 *)v, StrLen(v)) + // ::Util::Defines::Header:: #define HM_MAX_SYMBOLS 256 @@ -57,12 +99,12 @@ typedef struct Arena Arena; // ::Util::Strings::Functions::Header:: +String8 MakeString8(u8 *str, u64 len); u32 StrLen(const char *str); b32 StrEq(const char *l, const char *r); i32 SPrintf(char *buf, rawptr fmt, ...); -Str8 MakeStr8(u8 *str, u32 len); -Str8 PreSplitStr8(Str8 string, Str8 delimiter); -Str8 PreSplitNewStr8(Arena *arena, Str8 string, Str8 delimiter); +String8 PreSplitString8(String8 string, String8 delimiter); +String8 PreSplitNewString8(Arena *arena, String8 string, String8 delimiter); // ::Util::Memory::Functions::Header:: @@ -80,7 +122,7 @@ u32 u32Clamp(u32 v, u32 min, u32 max); // ::Util::Hashing::Functions::Header:: -u64 static inline HashFromString(Str8 string); +u64 static inline HashFromString(String8 string); // ::Util::Print::Functions::Header:: @@ -92,3 +134,46 @@ i32 _EPrint(void *str); i32 _Printf(char *fmt, va_list arg); i32 _Printfln(char *fmt, va_list arg); i32 _EPrintf(char *fmt, va_list arg); + +// ::Util::Profiling::Header:: + +#define NameConcat2(a, b) a##b + +#define NameConcat(a, b) NameConcat2(a, b) + +#define TimeBlockStart(name) ProfileBlock NameConcat(Block, name) = {0}; \ +StartProfileBlock(&NameConcat(Block, name), #name, __COUNTER__ + 1) + +#define TimeBlockEnd(name) EndProfileBlock(&NameConcat(Block, name)) + +#define TimeBlockFuncStart(name) ProfileBlock NameConcat(Block, function) = {0}; \ +StartProfileBlock(& NameConcat(Block, function), name, __COUNTER__ + 1) + +#define TimeFunctionStart TimeBlockFuncStart(__func__) + +#define TimeFunctionEnd TimeBlockEnd(function) + +typedef struct ProfileAnchor +{ + u64 tsc_elapsed; + u64 hit_count; + c8 *label; +} ProfileAnchor; + +typedef struct ProfileBlock +{ + c8 *label; + u64 start_tsc; + u32 anchor_index; +} ProfileBlock; + +typedef struct Profiler +{ + ProfileAnchor anchors[4096]; + u64 start_tsc; + u64 end_tsc; +} Profiler; + +static inline void StartProfileBlock(ProfileBlock *block, c8 *label, u32 anchor_index); +static inline void EndProfileBlock(ProfileBlock *block); +