Skip to content

feat: add arena allocation tracking + JSON dump#30

Open
gimploo wants to merge 7 commits into
devfrom
feat/arena-tracking
Open

feat: add arena allocation tracking + JSON dump#30
gimploo wants to merge 7 commits into
devfrom
feat/arena-tracking

Conversation

@gimploo

@gimploo gimploo commented Jul 9, 2026

Copy link
Copy Markdown
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
Comment thread basic/arena.h Outdated
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);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these declarations must be under impelmentation if def

gimploo added 3 commits July 9, 2026 14:53
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
Comment thread basic/arena.h Outdated
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__)

@gimploo gimploo Jul 9, 2026

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move these two above arena_store

Comment thread basic/arena.h Outdated
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;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put this into dbg.h

Comment thread basic/arena.h
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));
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason for this change ?

Comment thread basic/arena.h Outdated
}
}

static void arena__internal_ensure_registered(arena_t *self)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace static with INTERNAL and have an extra _ after internal_ -> it should look like internal

Comment thread basic/arena.h Outdated
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)++;

@gimploo gimploo Jul 9, 2026

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make the function name descriptive enough - also this is internal so use the internal code design

Comment thread basic/arena.h Outdated
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;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Comment thread basic/arena.h
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);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use str_t

Comment thread basic/arena.h
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);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use INTERNAL macro here

Comment thread basic/dbg.h
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;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont use _ at the front have internal in the name instead

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant