mirror of
https://github.com/pocketpy/pocketpy
synced 2025-12-08 03:00:16 +00:00
improve heap
This commit is contained in:
parent
d7cfc0403b
commit
ef9b4779f4
@ -22,7 +22,7 @@ typedef struct PoolArena {
|
|||||||
|
|
||||||
typedef struct Pool {
|
typedef struct Pool {
|
||||||
c11_vector /* PoolArena* */ arenas;
|
c11_vector /* PoolArena* */ arenas;
|
||||||
c11_vector /* PoolArena* */ no_free_arenas;
|
int available_index;
|
||||||
int block_size;
|
int block_size;
|
||||||
} Pool;
|
} Pool;
|
||||||
|
|
||||||
|
|||||||
@ -21,14 +21,6 @@ static PoolArena* PoolArena__new(int block_size) {
|
|||||||
return self;
|
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) {
|
static void* PoolArena__alloc(PoolArena* self) {
|
||||||
assert(self->unused_length > 0);
|
assert(self->unused_length > 0);
|
||||||
int index = self->unused[self->unused_length - 1];
|
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) {
|
static int PoolArena__sweep_dealloc(PoolArena* self, int* out_types) {
|
||||||
int freed = 0;
|
int unused_length_before = self->unused_length;
|
||||||
self->unused_length = 0;
|
self->unused_length = 0;
|
||||||
for(int i = 0; i < self->block_count; i++) {
|
for(int i = 0; i < self->block_count; i++) {
|
||||||
PyObject* obj = (PyObject*)(self->data + i * self->block_size);
|
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]++;
|
if(out_types) out_types[obj->type]++;
|
||||||
PyObject__dtor(obj);
|
PyObject__dtor(obj);
|
||||||
obj->type = 0;
|
obj->type = 0;
|
||||||
freed++;
|
|
||||||
self->unused[self->unused_length] = i;
|
self->unused[self->unused_length] = i;
|
||||||
self->unused_length++;
|
self->unused_length++;
|
||||||
} else {
|
} 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) {
|
static void Pool__ctor(Pool* self, int block_size) {
|
||||||
c11_vector__ctor(&self->arenas, sizeof(PoolArena*));
|
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;
|
self->block_size = block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Pool__dtor(Pool* self) {
|
static void Pool__dtor(Pool* self) {
|
||||||
c11__foreach(PoolArena*, &self->arenas, arena) PoolArena__delete(*arena);
|
for(int i = 0; i < self->arenas.length; i++) {
|
||||||
c11__foreach(PoolArena*, &self->no_free_arenas, arena) PoolArena__delete(*arena);
|
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->arenas);
|
||||||
c11_vector__dtor(&self->no_free_arenas);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* Pool__alloc(Pool* self) {
|
static void* Pool__alloc(Pool* self) {
|
||||||
PoolArena* arena;
|
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);
|
arena = PoolArena__new(self->block_size);
|
||||||
c11_vector__push(PoolArena*, &self->arenas, arena);
|
c11_vector__push(PoolArena*, &self->arenas, arena);
|
||||||
} else {
|
self->available_index = self->arenas.length - 1;
|
||||||
arena = c11_vector__back(PoolArena*, &self->arenas);
|
|
||||||
}
|
}
|
||||||
void* ptr = PoolArena__alloc(arena);
|
void* ptr = PoolArena__alloc(arena);
|
||||||
if(arena->unused_length == 0) {
|
if(arena->unused_length == 0) self->available_index++;
|
||||||
c11_vector__pop(&self->arenas);
|
|
||||||
c11_vector__push(PoolArena*, &self->no_free_arenas, arena);
|
|
||||||
}
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Pool__sweep_dealloc(Pool* self,
|
static int Pool__sweep_dealloc(Pool* self, int* out_types) {
|
||||||
c11_vector* arenas,
|
PoolArena** p = self->arenas.data;
|
||||||
c11_vector* no_free_arenas,
|
|
||||||
int* out_types) {
|
|
||||||
c11_vector__clear(arenas);
|
|
||||||
c11_vector__clear(no_free_arenas);
|
|
||||||
|
|
||||||
int freed = 0;
|
int freed = 0;
|
||||||
for(int i = 0; i < self->arenas.length; i++) {
|
for(int i = 0; i < self->arenas.length; i++) {
|
||||||
PoolArena* item = c11__getitem(PoolArena*, &self->arenas, i);
|
freed += PoolArena__sweep_dealloc(p[i], out_types);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for(int i = 0; i < self->no_free_arenas.length; i++) {
|
|
||||||
PoolArena* item = c11__getitem(PoolArena*, &self->no_free_arenas, i);
|
// move arenas with `unused_length == 0` to the front
|
||||||
freed += PoolArena__sweep_dealloc(item, out_types);
|
int j = 0;
|
||||||
if(item->unused_length == 0) {
|
for(int i = 0; i < self->arenas.length; i++) {
|
||||||
// still no free
|
if(p[i]->unused_length == 0) {
|
||||||
c11_vector__push(PoolArena*, no_free_arenas, item);
|
PoolArena* tmp = p[i];
|
||||||
} else {
|
p[i] = p[j];
|
||||||
if(item->unused_length == item->block_count) {
|
p[j] = tmp;
|
||||||
// all free
|
j++;
|
||||||
PK_FREE(item);
|
|
||||||
} else {
|
|
||||||
// some free
|
|
||||||
c11_vector__push(PoolArena*, arenas, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c11_vector__swap(&self->arenas, arenas);
|
// move arenas with `unused_length < block_count` to the front
|
||||||
c11_vector__swap(&self->no_free_arenas, no_free_arenas);
|
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;
|
return freed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,17 +146,11 @@ void* MultiPool__alloc(MultiPool* self, int size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int MultiPool__sweep_dealloc(MultiPool* self, int* out_types) {
|
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;
|
int freed = 0;
|
||||||
for(int i = 0; i < kMultiPoolCount; i++) {
|
for(int i = 0; i < kMultiPoolCount; i++) {
|
||||||
Pool* item = &self->pools[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;
|
return freed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +170,7 @@ size_t MultiPool__total_allocated_bytes(MultiPool* self) {
|
|||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
for(int i = 0; i < kMultiPoolCount; i++) {
|
for(int i = 0; i < kMultiPoolCount; i++) {
|
||||||
Pool* item = &self->pools[i];
|
Pool* item = &self->pools[i];
|
||||||
int arena_count = item->arenas.length + item->no_free_arenas.length;
|
total += (size_t)item->arenas.length * kPoolArenaSize;
|
||||||
total += (size_t)arena_count * kPoolArenaSize;
|
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
@ -194,22 +182,21 @@ c11_string* MultiPool__summary(MultiPool* self) {
|
|||||||
char buf[256];
|
char buf[256];
|
||||||
for(int i = 0; i < kMultiPoolCount; i++) {
|
for(int i = 0; i < kMultiPoolCount; i++) {
|
||||||
Pool* item = &self->pools[i];
|
Pool* item = &self->pools[i];
|
||||||
arena_count += item->arenas.length + item->no_free_arenas.length;
|
arena_count += item->arenas.length;
|
||||||
int total_bytes = (item->arenas.length + item->no_free_arenas.length) * kPoolArenaSize;
|
int total_bytes = item->arenas.length * kPoolArenaSize;
|
||||||
int used_bytes = 0;
|
int used_bytes = 0;
|
||||||
for(int j = 0; j < item->arenas.length; j++) {
|
for(int j = 0; j < item->arenas.length; j++) {
|
||||||
PoolArena* arena = c11__getitem(PoolArena*, &item->arenas, j);
|
PoolArena* arena = c11__getitem(PoolArena*, &item->arenas, j);
|
||||||
used_bytes += (arena->block_count - arena->unused_length) * arena->block_size;
|
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;
|
float used_pct = (float)used_bytes / total_bytes * 100;
|
||||||
if(total_bytes == 0) used_pct = 0.0f;
|
if(total_bytes == 0) used_pct = 0.0f;
|
||||||
snprintf(buf,
|
snprintf(buf,
|
||||||
sizeof(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->block_size,
|
||||||
item->arenas.length,
|
item->arenas.length,
|
||||||
item->no_free_arenas.length,
|
item->available_index,
|
||||||
used_bytes,
|
used_bytes,
|
||||||
total_bytes,
|
total_bytes,
|
||||||
used_pct);
|
used_pct);
|
||||||
@ -217,10 +204,7 @@ c11_string* MultiPool__summary(MultiPool* self) {
|
|||||||
}
|
}
|
||||||
long long total_size = arena_count * kPoolArenaSize;
|
long long total_size = arena_count * kPoolArenaSize;
|
||||||
double total_size_mb = (long long)(total_size / 1024) / 1024.0;
|
double total_size_mb = (long long)(total_size / 1024) / 1024.0;
|
||||||
snprintf(buf,
|
snprintf(buf, sizeof(buf), "Total: %.2f MB\n", total_size_mb);
|
||||||
sizeof(buf),
|
|
||||||
"Total: %.2f MB\n",
|
|
||||||
total_size_mb);
|
|
||||||
c11_sbuf__write_cstr(&sbuf, buf);
|
c11_sbuf__write_cstr(&sbuf, buf);
|
||||||
return c11_sbuf__submit(&sbuf);
|
return c11_sbuf__submit(&sbuf);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user