feat: add arena allocation tracking + JSON dump#30
Open
gimploo wants to merge 7 commits into
Open
Conversation
gimploo
commented
Jul 9, 2026
Owner
- Add alloc_log linked list to arena_t for recording every arena_reserve/arena_store call
- Macro-wrap arena_init/arena_reserve to auto-capture FILE, LINE, func
- Arenas self-register into global registry on first allocation
- arena_dump_json() writes all arena allocation data as JSON
- arena_clear and arena_destroy free alloc log records
- Add alloc_log linked list to arena_t for recording every arena_reserve/arena_store call - Macro-wrap arena_init/arena_reserve to auto-capture __FILE__, __LINE__, __func__ - Arenas self-register into global registry on first allocation - arena_dump_json() writes all arena allocation data as JSON - arena_clear and arena_destroy free alloc log records
gimploo
commented
Jul 9, 2026
| arena_t arena_init(arena_t *const, const u64 capacity); | ||
| void * arena_reserve(arena_t *const self, const u64 memory_size); | ||
| bool arena_is_init(const arena_t *const self); | ||
| arena_t arena__internal_init(arena_t *const, const u64 capacity, const char *file, int line); |
Owner
Author
There was a problem hiding this comment.
these declarations must be under impelmentation if def
Generates flamegraph-compatible JSON for speedscope.app: - Drag arena_map.json into speedscope.app for interactive flamegraph - Wide bars = heavy memory consumers, click to drill down - Arena → file → function → (line + bytes) hierarchy - Unused arena space shown as '(unused)' frame
gimploo
commented
Jul 9, 2026
Comment on lines
+67
to
+71
| #define arena_init(arena, capacity) \ | ||
| arena__internal_init((arena), (capacity), __FILE__, __LINE__) | ||
|
|
||
| #define arena_reserve(self, memory_size) \ | ||
| arena__internal_reserve_tracked((self), (memory_size), __FILE__, __LINE__, __func__) |
Owner
Author
There was a problem hiding this comment.
move these two above arena_store
gimploo
commented
Jul 9, 2026
| void * arena__internal_reserve_tracked(arena_t *const self, const u64 memory_size, const char *file, int line, const char *func); | ||
|
|
||
| arena_t arena_init(arena_t *const arena, const u64 capacity) | ||
| static arena_t *arena_registry = NULL; |
gimploo
commented
Jul 9, 2026
Comment on lines
+271
to
+282
| free_chunks_t *new_chunk; | ||
| if (self->meta.lifetime_owner) { | ||
| new_chunk = (free_chunks_t *)arena__internal_reserve_memory_16byte_aligned( | ||
| self->meta.lifetime_owner, sizeof(free_chunks_t)); | ||
| if (new_chunk) { | ||
| new_chunk->memory = ptr; | ||
| new_chunk->size = size; | ||
| new_chunk->next = NULL; | ||
| } | ||
| } else { | ||
| new_chunk = calloc(1, sizeof(free_chunks_t)); | ||
| } |
gimploo
commented
Jul 9, 2026
| } | ||
| } | ||
|
|
||
| static void arena__internal_ensure_registered(arena_t *self) |
Owner
Author
There was a problem hiding this comment.
replace static with INTERNAL and have an extra _ after internal_ -> it should look like internal
gimploo
commented
Jul 9, 2026
Comment on lines
+334
to
+341
| static u32 arena__frame_idx(const char *name, char fnames[][256], u32 *count) | ||
| { | ||
| ASSERT(mem_size > 0); | ||
| ASSERT(mem); | ||
| void *raw_mem = arena_reserve(self, mem_size); | ||
| memcpy(raw_mem, mem, mem_size); | ||
| return raw_mem; | ||
| for (u32 i = 0; i < *count; i++) { | ||
| if (strcmp(fnames[i], name) == 0) return i; | ||
| } | ||
| strncpy(fnames[*count], name, 255); | ||
| fnames[*count][255] = '\0'; | ||
| return (*count)++; |
Owner
Author
There was a problem hiding this comment.
make the function name descriptive enough - also this is internal so use the internal code design
…l fns with __, replace static with INTERNAL
gimploo
commented
Jul 9, 2026
Comment on lines
+43
to
+49
| struct { | ||
| arena_alloc_record_t *head; | ||
| u32 count; | ||
| } alloc_log; | ||
| const char *init_file; | ||
| int init_line; | ||
| arena_t *next_in_registry; |
Owner
Author
There was a problem hiding this comment.
dont put this in here, have another struct called arena_logger or something and have it called in dbg.h during init. also create a init and destroy function for it.
…dbg.h - Remove alloc_log, init_file, init_line, next_in_registry from arena_t - Add arena_logger_t struct, registry, init/destroy/log_alloc/clear_log to dbg.h - arena_logger_init is lazy — fires on first arena_reserve call - arena_dump_json now iterates arena_logger_registry instead of arena_registry - All 16 arena tests pass
gimploo
commented
Jul 9, 2026
| void arena_giveback(arena_t *const self, void *const ptr, const u64 size); | ||
| void arena_clear(arena_t *const self); | ||
| void arena_destroy(arena_t *const self); | ||
| void arena_dump_json(const char *filepath); |
gimploo
commented
Jul 9, 2026
Comment on lines
+56
to
+60
| arena_t arena__internal__init(arena_t *const, const u64 capacity); | ||
| void * arena__internal__reserve_memory_16byte_aligned(arena_t * const self, const u64 memory_size); | ||
| void * arena__internal__reserve_tracked(arena_t *const self, const u64 memory_size, const char *file, int line, const char *func); | ||
|
|
||
| arena_t arena_init(arena_t *const arena, const u64 capacity) | ||
| { | ||
| arena_t o = { | ||
| .capacity = capacity, | ||
| .size = 0, | ||
| .memory = arena ? arena__internal_reserve_memory_16byte_aligned(arena, capacity) : calloc(capacity, sizeof(u8)), | ||
| .freelist = {0}, | ||
| .meta = { | ||
| .lifetime_owner = arena, | ||
| } | ||
| }; | ||
| atomic_flag_clear(&o.meta.lock); | ||
| return o; | ||
| } | ||
| static u32 arena__internal__frame_lookup(const char *name, char fnames[][256], u32 *count); |
gimploo
commented
Jul 9, 2026
Comment on lines
+71
to
+78
| struct _arena_alloc_record { | ||
| const char *file; | ||
| int line; | ||
| const char *func; | ||
| uint64_t size; | ||
| struct _arena_alloc_record *next; | ||
| }; | ||
| typedef struct _arena_alloc_record arena_alloc_record_t; |
Owner
Author
There was a problem hiding this comment.
dont use _ at the front have internal in the name instead
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.