Rework the arena once again...

This commit is contained in:
kamkow1
2025-06-01 13:24:14 +02:00
parent dd74b7f78a
commit ed39351983
2 changed files with 84 additions and 61 deletions

View File

@ -9,18 +9,14 @@ typedef struct {
int main(void) int main(void)
{ {
/* Arena arena = gebs_arena_get(512); */ Arena arena = gebs_arena_get();
Arena arena = gebs_arena_get(128);
defer { arena_destroy(&arena); } defer { arena_destroy(&arena); }
Ints ints = {0}; Ints ints = {0};
for (size_t i = 0; i < 100; i++) { for (size_t i = 0; i < 10000; i++) {
list_append_alloc(&arena, &ints, i); list_append_alloc(&arena, &ints, i);
}
gebs_arena_reset(&arena); gebs_arena_reset(&arena);
}
for (size_t i = 0; i < ints.count; i++) {
printf("%zu\n", i);
}
printf("%s\n", fmt("Hello formatting %d", 124)); printf("%s\n", fmt("Hello formatting %d", 124));

131
gebs.h
View File

@ -169,36 +169,45 @@ void gebs_default_allocator_free(void *self, void *memory);
void *gebs_default_allocator_realloc(void *self, void *memory, void *gebs_default_allocator_realloc(void *self, void *memory,
size_t prev_size, size_t new_size); size_t prev_size, size_t new_size);
typedef struct Gebs_Arena_Chunk {
struct Gebs_Arena_Chunk *next;
size_t size;
size_t capacity;
uintptr_t memory[];
} Gebs_Arena_Chunk;
typedef struct Gebs_Arena { typedef struct Gebs_Arena {
void *(*malloc)(void *self, size_t size); void *(*malloc)(void *self, size_t size);
void (*free)(void *self, void *memory); void (*free)(void *self, void *memory);
void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size); void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size);
void *buffer; Gebs_Arena_Chunk *begin;
void *end; Gebs_Arena_Chunk *end;
size_t capacity;
void (*out_of_memory_handler)(struct Gebs_Arena *self, size_t requested);
} Gebs_Arena; } Gebs_Arena;
void gebs_arena_reset(Gebs_Arena *a);
void gebs_arena_destroy(Gebs_Arena *a);
void *gebs_arena_malloc(void *self, size_t size); void *gebs_arena_malloc(void *self, size_t size);
void gebs_arena_free(void *self, void *memory); void gebs_arena_free(void *self, void *memory);
void *gebs_arena_realloc(void *self, void *memory, size_t prev_size, size_t new_size); void *gebs_arena_realloc(void *self, void *memory, size_t prev_size, size_t new_size);
void gebs_arena_out_of_memory_handler(Gebs_Arena *self, size_t requested);
#define gebs_arena_get(cap) \ void gebs_arena_reset(Gebs_Arena *a);
void gebs_arena_destroy(Gebs_Arena *a);
Gebs_Arena_Chunk *gebs_arena_create_chunk(size_t capacity);
void gebs_arena_destroy_chunk(Gebs_Arena_Chunk *chunk);
#define gebs_arena_get() \
({ \ ({ \
Gebs_Arena __arena = {0}; \ Gebs_Arena __arena = {0}; \
__arena.malloc = &gebs_arena_malloc; \ __arena.malloc = &gebs_arena_malloc; \
__arena.realloc = &gebs_arena_realloc; \ __arena.realloc = &gebs_arena_realloc; \
__arena.free = &gebs_arena_free; \ __arena.free = &gebs_arena_free; \
__arena.capacity = (cap); \
__arena.out_of_memory_handler = &gebs_arena_out_of_memory_handler; \
__arena; \ __arena; \
}) })
#ifndef GEBS_ARENA_CHUNK_CAPACITY
# define GEBS_ARENA_CHUNK_CAPACITY (8*1024)
#endif
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Dynamic list // Dynamic list
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -375,10 +384,6 @@ void gebs_rebuild_self1_alloc(Gebs_Allocator *alloc, int argc, char ** argv,
// Scratch arena // Scratch arena
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#ifndef GEBS_SCRATCH_ARENA_SIZE
# define GEBS_SCRATCH_ARENA_SIZE 4096
#endif
extern Gebs_Arena gebs_scratch_arena; extern Gebs_Arena gebs_scratch_arena;
char *gebs_fmt(const char *fmt, ...); char *gebs_fmt(const char *fmt, ...);
@ -529,32 +534,52 @@ void *gebs_default_allocator_realloc(discard void *self, void *memory,
return p; return p;
} }
Gebs_Arena_Chunk *gebs_arena_create_chunk(size_t capacity)
{
size_t size = sizeof(Gebs_Arena_Chunk) + sizeof(uintptr_t)*capacity;
Gebs_Arena_Chunk *chunk = (Gebs_Arena_Chunk *)malloc(size);
chunk->next = NULL;
chunk->size = 0;
chunk->capacity = capacity;
return chunk;
}
void gebs_arena_destroy_chunk(Gebs_Arena_Chunk *chunk)
{
free(chunk);
}
void *gebs_arena_malloc(void *self, size_t size) void *gebs_arena_malloc(void *self, size_t size)
{ {
Gebs_Arena *a = (Gebs_Arena *)self; Gebs_Arena *a = (Gebs_Arena *)self;
if (a->buffer == NULL) { size_t sz = (size + sizeof(uintptr_t) - 1)/sizeof(uintptr_t);
#if GEBS_PLATFORM == GEBS_PLATFORM_POSIX
int prot = PROT_READ | PROT_WRITE;
int vis = MAP_SHARED | MAP_ANONYMOUS;
a->buffer = mmap(0, a->capacity, prot, vis, -1, 0);
#else
# error "gebs_arena_malloc unknown platform"
#endif
a->end = a->buffer;
}
void *p = a->end;
a->end = (void *)((uintptr_t)a->end + size);
size_t requested = (uintptr_t)a->end - (uintptr_t)a->buffer; if (a->end == NULL) {
if (requested > a->capacity) { size_t capacity = GEBS_ARENA_CHUNK_CAPACITY;
if (a->out_of_memory_handler == NULL) { if (capacity < sz) {
abort(); capacity = sz;
} }
a->out_of_memory_handler(a, requested); a->end = gebs_arena_create_chunk(capacity);
a->begin = a->end;
} }
return p; while (a->end->size + sz > a->end->capacity && a->end->next != NULL) {
a->end = a->end->next;
}
if (a->end->size + sz > a->end->capacity) {
size_t capacity = GEBS_ARENA_CHUNK_CAPACITY;
if (capacity < sz) {
capacity = sz;
}
a->end->next = gebs_arena_create_chunk(capacity);
a->end = a->end->next;
}
void *result = &a->end->memory[a->end->size];
a->end->size += sz;
return result;
} }
void gebs_arena_free(discard void *self, discard void *memory) void gebs_arena_free(discard void *self, discard void *memory)
@ -566,33 +591,35 @@ void *gebs_arena_realloc(void *self, void *memory,
{ {
Gebs_Arena *a = (Gebs_Arena *)self; Gebs_Arena *a = (Gebs_Arena *)self;
void *new = gebs_arena_malloc(a, new_size); if (new_size <= prev_size) {
memcpy(new, memory, prev_size); return memory;
return new; }
void *new_memory = gebs_arena_malloc(a, new_size);
for (size_t i = 0; i < prev_size; i++) {
((char *)new_memory)[i] = ((char *)memory)[i];
}
return new_memory;
} }
void gebs_arena_reset(Gebs_Arena *a) void gebs_arena_reset(Gebs_Arena *a)
{ {
a->end = a->buffer; for (Gebs_Arena_Chunk *chunk = a->begin; chunk != NULL; chunk = chunk->next) {
chunk->size = 0;
}
a->end = a->begin;
} }
void gebs_arena_destroy(Gebs_Arena *a) void gebs_arena_destroy(Gebs_Arena *a)
{ {
#if GEBS_PLATFORM == GEBS_PLATFORM_POSIX Gebs_Arena_Chunk *chunk = a->begin;
munmap(a->buffer, a->capacity); while (chunk) {
#else Gebs_Arena_Chunk *chunk1 = chunk;
# error "gebs_arena_destroy unknown platform" chunk = chunk->next;
#endif gebs_arena_destroy_chunk(chunk1);
} }
a->begin = NULL;
void gebs_arena_out_of_memory_handler(Gebs_Arena *self, size_t requested) a->end = NULL;
{
GEBS_LOGE("Arena ran out of memory. capacity = %zu, requested %zu\n",
self->capacity, requested);
GEBS_LOGI("Arena: buffer %p, end %p, diff %zu\n",
self->buffer, self->end,
(size_t)((uintptr_t)self->end - (uintptr_t)self->buffer));
abort();
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -604,7 +631,7 @@ Gebs_Arena gebs_scratch_arena;
__attribute__((constructor)) __attribute__((constructor))
void gebs_scratch_areana_init(void) void gebs_scratch_areana_init(void)
{ {
gebs_scratch_arena = gebs_arena_get(4*1024); gebs_scratch_arena = gebs_arena_get();
} }
__attribute__((destructor)) __attribute__((destructor))