From 13ace0e5c0098ddb28ae8db597266d41f8f5cd0b Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Wed, 5 Jun 2024 21:16:02 +0200 Subject: [PATCH] memory/mempool: refactor to avoid storing object size and alignment in struct Works similarly to DYNAMMIC_ARRAY(type) --- src/enemy.c | 2 +- src/lasers/laser.c | 2 +- src/memory/mempool.c | 25 ++++++--------- src/memory/mempool.h | 76 ++++++++++++++++++++++++++++++++------------ src/stagedraw.c | 10 +++++- src/stageobjects.c | 9 ++---- src/stageobjects.h | 2 +- src/stagetext.c | 4 +-- 8 files changed, 81 insertions(+), 49 deletions(-) diff --git a/src/enemy.c b/src/enemy.c index 9c7bc9cc..13763335 100644 --- a/src/enemy.c +++ b/src/enemy.c @@ -165,7 +165,7 @@ static void *_delete_enemy(ListAnchor *enemies, List* enemy, void *arg) { COEVENT_CANCEL_ARRAY(e->events); ent_unregister(&e->ent); - mempool_release(&stage_object_pools.enemies, alist_unlink(enemies, enemy)); + mempool_release(&stage_object_pools.enemies, alist_unlink(enemies, e)); return NULL; } diff --git a/src/lasers/laser.c b/src/lasers/laser.c index b3bccbb6..323f8c92 100644 --- a/src/lasers/laser.c +++ b/src/lasers/laser.c @@ -113,7 +113,7 @@ void laserline_set_posdir(Laser *l, cmplx pos, cmplx dir) { static void *_delete_laser(ListAnchor *lasers, List *laser, void *arg) { Laser *l = (Laser*)laser; ent_unregister(&l->ent); - mempool_release(&stage_object_pools.lasers, alist_unlink(lasers, laser)); + mempool_release(&stage_object_pools.lasers, alist_unlink(lasers, l)); return NULL; } diff --git a/src/memory/mempool.c b/src/memory/mempool.c index 0a0b5cc8..fd59e82d 100644 --- a/src/memory/mempool.c +++ b/src/memory/mempool.c @@ -8,44 +8,37 @@ #include "mempool.h" -void mempool_init( +void mempool_generic_init( MemPool *pool, - const char *tag, - MemArena *arena, - size_t obj_size, - size_t obj_align + MemArena *arena ) { *pool = (MemPool) { .arena = arena, - .obj_size = obj_size, - .obj_align = obj_align, - .tag = tag, }; } -void *mempool_acquire(MemPool *pool) { - MemPoolObjectHeader *obj = pool->free_objects; +void *mempool_generic_acquire(MemPool *pool, size_t size, size_t align) { + MemPoolObjectHeader *obj = pool->free_objects.as_generic; if(obj) { assert(pool->num_used < pool->num_allocated); - pool->free_objects = obj->next; + pool->free_objects.as_generic = obj->next; } else { assert(pool->num_used == pool->num_allocated); - obj = marena_alloc_aligned(pool->arena, pool->obj_size, pool->obj_align); + obj = marena_alloc_aligned(pool->arena, size, align); ++pool->num_allocated; } - memset(obj, 0, pool->obj_size); ++pool->num_used; assert(pool->num_used <= pool->num_allocated); return obj; } -void mempool_release(MemPool *pool, void *object) { +void mempool_generic_release(MemPool *pool, void *object) { MemPoolObjectHeader *obj = object; - obj->next = pool->free_objects; - pool->free_objects = obj; + obj->next = pool->free_objects.as_generic; + pool->free_objects.as_generic = obj; --pool->num_used; assert(pool->num_used >= 0); diff --git a/src/memory/mempool.h b/src/memory/mempool.h index 208e31e1..7823c390 100644 --- a/src/memory/mempool.h +++ b/src/memory/mempool.h @@ -11,32 +11,68 @@ #include "arena.h" -typedef struct MemPool MemPool; - typedef struct MemPoolObjectHeader { alignas(alignof(max_align_t)) struct MemPoolObjectHeader *next; } MemPoolObjectHeader; -struct MemPool { - MemArena *arena; - MemPoolObjectHeader *free_objects; - const char *tag; - size_t obj_size; - size_t obj_align; - int num_allocated; - int num_used; -}; +#define MEMPOOL_BASE(elem_type) struct { \ + MemArena *arena; \ + union { \ + MemPoolObjectHeader *as_generic; \ + elem_type *as_specific; \ + } free_objects; \ + uint num_allocated; \ + uint num_used; \ +} \ -void mempool_init( - MemPool *pool, - const char *tag, - MemArena *arena, - size_t obj_size, - size_t obj_align -) attr_nonnull(1, 2, 3); +typedef MEMPOOL_BASE(max_align_t) MemPool; -void *mempool_acquire(MemPool *pool) +#define MEMPOOL(elem_type) union { \ + MEMPOOL_BASE(elem_type); \ + MemPool as_generic; \ +} + +#define MEMPOOL_ASSERT_VALID(mpool) do { \ + static_assert( \ + __builtin_types_compatible_p(MemPool, __typeof__((mpool)->as_generic)), \ + "x->as_generic must be of MemPool type"); \ + static_assert( \ + __builtin_offsetof(__typeof__(*(mpool)), as_generic) == 0, \ + "x->as_generic must be the first member in struct"); \ +} while(0) + +#define MEMPOOL_CAST_TO_BASE(mpool) ({ \ + MEMPOOL_ASSERT_VALID(mpool); \ + &NOT_NULL(mpool)->as_generic; \ +}) + +#define MEMPOOL_OBJTYPE(mpool) \ + typeof(*(mpool)->free_objects.as_specific) + +void mempool_generic_init(MemPool *pool, MemArena *arena) + attr_nonnull(1, 2); + +void *mempool_generic_acquire(MemPool *pool, size_t size, size_t align) attr_returns_allocated attr_hot attr_nonnull(1); -void mempool_release(MemPool *pool, void *object) +void mempool_generic_release(MemPool *pool, void *object) attr_hot attr_nonnull(1, 2); + +#define mempool_init(mpool, arena) \ + mempool_generic_init(MEMPOOL_CAST_TO_BASE(mpool), (arena)); + +#define mempool_acquire(mpool) ({ \ + auto _mpool = mpool; \ + MEMPOOL_OBJTYPE(_mpool) *_obj = mempool_generic_acquire(\ + MEMPOOL_CAST_TO_BASE(_mpool), \ + sizeof(MEMPOOL_OBJTYPE(_mpool)), \ + alignof(MEMPOOL_OBJTYPE(_mpool))); \ + *_obj = (typeof(*_obj)) {} ; \ + _obj; \ +}) + +#define mempool_release(mpool, obj) ({ \ + static_assert( \ + __builtin_types_compatible_p(typeof(*(obj)), MEMPOOL_OBJTYPE(mpool))); \ + mempool_generic_release(MEMPOOL_CAST_TO_BASE(mpool), (obj)); \ +}) diff --git a/src/stagedraw.c b/src/stagedraw.c index 65f16db4..31e1fa68 100644 --- a/src/stagedraw.c +++ b/src/stagedraw.c @@ -1197,12 +1197,20 @@ static void stage_draw_hud_objpool_stats(float x, float y, float width) { y += lineskip * 1.5; + const char *const names[] = { + #define OBJECT_POOL(t, n) #t, + OBJECT_POOLS + #undef OBJECT_POOL + }; + + static_assert(ARRAY_SIZE(*objpools) == ARRAY_SIZE(names)); + for(int i = 0; i < ARRAY_SIZE(*objpools); ++i) { MemPool *p = &(*objpools)[i]; snprintf(buf, sizeof(buf), "%u | %7u", p->num_used, p->num_allocated); - text_draw(p->tag, &(TextParams) { + text_draw(names[i], &(TextParams) { .pos = { x, y }, .font_ptr = font, .align = ALIGN_LEFT, diff --git a/src/stageobjects.c b/src/stageobjects.c index c7c4dcf4..aa16e8ea 100644 --- a/src/stageobjects.c +++ b/src/stageobjects.c @@ -24,14 +24,9 @@ void stage_objpools_init(void) { } #define OBJECT_POOL(type, field) \ - mempool_init( \ - &stage_object_pools.field, \ - #type, \ - &stgobjs.arena, \ - sizeof(type), \ - alignof(type)); + mempool_init(&stage_object_pools.field, &stgobjs.arena); - OBJECT_POOLS + OBJECT_POOLS #undef OBJECT_POOL } diff --git a/src/stageobjects.h b/src/stageobjects.h index d75238ea..49ec2b03 100644 --- a/src/stageobjects.h +++ b/src/stageobjects.h @@ -28,7 +28,7 @@ typedef struct StageObjectPools { #define OBJECT_POOL(type, field) \ - MemPool field; + MEMPOOL(type) field; OBJECT_POOLS #undef OBJECT_POOL diff --git a/src/stagetext.c b/src/stagetext.c index ec833bee..2a8b1302 100644 --- a/src/stagetext.c +++ b/src/stagetext.c @@ -46,8 +46,8 @@ StageText* stagetext_add_numeric(int n, cmplx pos, Alignment align, Font *font, return t; } -static void* stagetext_delete(List **dest, List *txt, void *arg) { - mempool_release(&stage_object_pools.stagetext, list_unlink(dest, txt)); +static void *stagetext_delete(List **dest, List *txt, void *arg) { + mempool_release(&stage_object_pools.stagetext, list_unlink(dest, (StageText*)txt)); return NULL; }