memory/mempool: refactor to avoid storing object size and alignment in struct

Works similarly to DYNAMMIC_ARRAY(type)
This commit is contained in:
Andrei Alexeyev 2024-06-05 21:16:02 +02:00
parent 05168ac2d7
commit 13ace0e5c0
No known key found for this signature in database
GPG key ID: 72D26128040B9690
8 changed files with 81 additions and 49 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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)); \
})

View file

@ -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,

View file

@ -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
}

View file

@ -28,7 +28,7 @@
typedef struct StageObjectPools {
#define OBJECT_POOL(type, field) \
MemPool field;
MEMPOOL(type) field;
OBJECT_POOLS
#undef OBJECT_POOL

View file

@ -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;
}