improve heap

This commit is contained in:
blueloveTH 2025-11-28 12:56:25 +08:00
parent d7cfc0403b
commit ef9b4779f4
2 changed files with 63 additions and 79 deletions

View File

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

View File

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