mirror of
https://github.com/pocketpy/pocketpy
synced 2025-12-06 10:10:17 +00:00
improve heap
This commit is contained in:
parent
d7cfc0403b
commit
ef9b4779f4
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user