From ef9b4779f44cd63d05a471c0b7bea4feb14e4db0 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 28 Nov 2025 12:56:25 +0800 Subject: [PATCH] improve heap --- include/pocketpy/interpreter/objectpool.h | 2 +- src/interpreter/objectpool.c | 140 ++++++++++------------ 2 files changed, 63 insertions(+), 79 deletions(-) diff --git a/include/pocketpy/interpreter/objectpool.h b/include/pocketpy/interpreter/objectpool.h index 8323a5e6..d86fa00f 100644 --- a/include/pocketpy/interpreter/objectpool.h +++ b/include/pocketpy/interpreter/objectpool.h @@ -22,7 +22,7 @@ typedef struct PoolArena { typedef struct Pool { c11_vector /* PoolArena* */ arenas; - c11_vector /* PoolArena* */ no_free_arenas; + int available_index; int block_size; } Pool; diff --git a/src/interpreter/objectpool.c b/src/interpreter/objectpool.c index a15a0dd6..e46eafac 100644 --- a/src/interpreter/objectpool.c +++ b/src/interpreter/objectpool.c @@ -21,14 +21,6 @@ static PoolArena* PoolArena__new(int block_size) { return self; } -static void PoolArena__delete(PoolArena* self) { - for(int i = 0; i < self->block_count; i++) { - PyObject* obj = (PyObject*)(self->data + i * self->block_size); - if(obj->type != 0) PyObject__dtor(obj); - } - PK_FREE(self); -} - static void* PoolArena__alloc(PoolArena* self) { assert(self->unused_length > 0); int index = self->unused[self->unused_length - 1]; @@ -37,7 +29,7 @@ static void* PoolArena__alloc(PoolArena* self) { } static int PoolArena__sweep_dealloc(PoolArena* self, int* out_types) { - int freed = 0; + int unused_length_before = self->unused_length; self->unused_length = 0; for(int i = 0; i < self->block_count; i++) { PyObject* obj = (PyObject*)(self->data + i * self->block_size); @@ -51,7 +43,6 @@ static int PoolArena__sweep_dealloc(PoolArena* self, int* out_types) { if(out_types) out_types[obj->type]++; PyObject__dtor(obj); obj->type = 0; - freed++; self->unused[self->unused_length] = i; self->unused_length++; } else { @@ -60,83 +51,87 @@ static int PoolArena__sweep_dealloc(PoolArena* self, int* out_types) { } } } - return freed; + return self->unused_length - unused_length_before; } static void Pool__ctor(Pool* self, int block_size) { c11_vector__ctor(&self->arenas, sizeof(PoolArena*)); - c11_vector__ctor(&self->no_free_arenas, sizeof(PoolArena*)); + self->available_index = 0; self->block_size = block_size; } static void Pool__dtor(Pool* self) { - c11__foreach(PoolArena*, &self->arenas, arena) PoolArena__delete(*arena); - c11__foreach(PoolArena*, &self->no_free_arenas, arena) PoolArena__delete(*arena); + for(int i = 0; i < self->arenas.length; i++) { + PoolArena* arena = c11__getitem(PoolArena*, &self->arenas, i); + for(int i = 0; i < arena->block_count; i++) { + PyObject* obj = (PyObject*)(arena->data + i * self->block_size); + if(obj->type != 0) PyObject__dtor(obj); + } + PK_FREE(arena); + } c11_vector__dtor(&self->arenas); - c11_vector__dtor(&self->no_free_arenas); } static void* Pool__alloc(Pool* self) { PoolArena* arena; - if(self->arenas.length == 0) { + if(self->available_index < self->arenas.length) { + arena = c11__getitem(PoolArena*, &self->arenas, self->available_index); + } else { arena = PoolArena__new(self->block_size); c11_vector__push(PoolArena*, &self->arenas, arena); - } else { - arena = c11_vector__back(PoolArena*, &self->arenas); + self->available_index = self->arenas.length - 1; } void* ptr = PoolArena__alloc(arena); - if(arena->unused_length == 0) { - c11_vector__pop(&self->arenas); - c11_vector__push(PoolArena*, &self->no_free_arenas, arena); - } + if(arena->unused_length == 0) self->available_index++; return ptr; } -static int Pool__sweep_dealloc(Pool* self, - c11_vector* arenas, - c11_vector* no_free_arenas, - int* out_types) { - c11_vector__clear(arenas); - c11_vector__clear(no_free_arenas); +static int Pool__sweep_dealloc(Pool* self, int* out_types) { + PoolArena** p = self->arenas.data; int freed = 0; for(int i = 0; i < self->arenas.length; i++) { - PoolArena* item = c11__getitem(PoolArena*, &self->arenas, i); - assert(item->unused_length > 0); - freed += PoolArena__sweep_dealloc(item, out_types); - if(item->unused_length == item->block_count) { - // all free - if(arenas->length > 0) { - // keep at least 1 arena - PK_FREE(item); - } else { - // no arena - c11_vector__push(PoolArena*, arenas, item); - } - } else { - // some free - c11_vector__push(PoolArena*, arenas, item); - } + freed += PoolArena__sweep_dealloc(p[i], out_types); } - for(int i = 0; i < self->no_free_arenas.length; i++) { - PoolArena* item = c11__getitem(PoolArena*, &self->no_free_arenas, i); - freed += PoolArena__sweep_dealloc(item, out_types); - if(item->unused_length == 0) { - // still no free - c11_vector__push(PoolArena*, no_free_arenas, item); - } else { - if(item->unused_length == item->block_count) { - // all free - PK_FREE(item); - } else { - // some free - c11_vector__push(PoolArena*, arenas, item); - } + + // move arenas with `unused_length == 0` to the front + int j = 0; + for(int i = 0; i < self->arenas.length; i++) { + if(p[i]->unused_length == 0) { + PoolArena* tmp = p[i]; + p[i] = p[j]; + p[j] = tmp; + j++; } } - c11_vector__swap(&self->arenas, arenas); - c11_vector__swap(&self->no_free_arenas, no_free_arenas); + // move arenas with `unused_length < block_count` to the front + int k = j; + for(int i = j; i < self->arenas.length; i++) { + if(p[i]->unused_length < p[i]->block_count) { + PoolArena* tmp = p[i]; + p[i] = p[k]; + p[k] = tmp; + k++; + } + } + + // free excess free arenas + int free_quota = self->arenas.length / 2; + int min_length = c11__max(free_quota, j + 1); + while(self->arenas.length > min_length) { + PoolArena* back_arena = c11_vector__back(PoolArena*, &self->arenas); + if(back_arena->unused_length == back_arena->block_count) { + PK_FREE(back_arena); + c11_vector__pop(&self->arenas); + } else { + break; + } + } + + // [[0, 0, 0, 0, 0, 1], 1, 1, 1, 2, 2] + // ^j=5 ^k + self->available_index = j; return freed; } @@ -151,17 +146,11 @@ void* MultiPool__alloc(MultiPool* self, int size) { } int MultiPool__sweep_dealloc(MultiPool* self, int* out_types) { - c11_vector arenas; - c11_vector no_free_arenas; - c11_vector__ctor(&arenas, sizeof(PoolArena*)); - c11_vector__ctor(&no_free_arenas, sizeof(PoolArena*)); int freed = 0; for(int i = 0; i < kMultiPoolCount; i++) { Pool* item = &self->pools[i]; - freed += Pool__sweep_dealloc(item, &arenas, &no_free_arenas, out_types); + freed += Pool__sweep_dealloc(item, out_types); } - c11_vector__dtor(&arenas); - c11_vector__dtor(&no_free_arenas); return freed; } @@ -181,8 +170,7 @@ size_t MultiPool__total_allocated_bytes(MultiPool* self) { size_t total = 0; for(int i = 0; i < kMultiPoolCount; i++) { Pool* item = &self->pools[i]; - int arena_count = item->arenas.length + item->no_free_arenas.length; - total += (size_t)arena_count * kPoolArenaSize; + total += (size_t)item->arenas.length * kPoolArenaSize; } return total; } @@ -194,22 +182,21 @@ c11_string* MultiPool__summary(MultiPool* self) { char buf[256]; for(int i = 0; i < kMultiPoolCount; i++) { Pool* item = &self->pools[i]; - arena_count += item->arenas.length + item->no_free_arenas.length; - int total_bytes = (item->arenas.length + item->no_free_arenas.length) * kPoolArenaSize; + arena_count += item->arenas.length; + int total_bytes = item->arenas.length * kPoolArenaSize; int used_bytes = 0; for(int j = 0; j < item->arenas.length; j++) { PoolArena* arena = c11__getitem(PoolArena*, &item->arenas, j); used_bytes += (arena->block_count - arena->unused_length) * arena->block_size; } - used_bytes += item->no_free_arenas.length * kPoolArenaSize; float used_pct = (float)used_bytes / total_bytes * 100; if(total_bytes == 0) used_pct = 0.0f; snprintf(buf, sizeof(buf), - "Pool %3d: len(arenas)=%d, len(no_free_arenas)=%d, %d/%d (%.1f%% used)\n", + "Pool %3d: len(arenas)=%d (%d full), size=%d/%d (%.1f%% used)\n", item->block_size, item->arenas.length, - item->no_free_arenas.length, + item->available_index, used_bytes, total_bytes, used_pct); @@ -217,10 +204,7 @@ c11_string* MultiPool__summary(MultiPool* self) { } long long total_size = arena_count * kPoolArenaSize; double total_size_mb = (long long)(total_size / 1024) / 1024.0; - snprintf(buf, - sizeof(buf), - "Total: %.2f MB\n", - total_size_mb); + snprintf(buf, sizeof(buf), "Total: %.2f MB\n", total_size_mb); c11_sbuf__write_cstr(&sbuf, buf); return c11_sbuf__submit(&sbuf); }