|
|
@@ -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);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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++;
|
|
|
}
|
|
|
}
|
|
|
- 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);
|
|
|
+
|
|
|
+ // 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 {
|
|
|
- if(item->unused_length == item->block_count) {
|
|
|
- // all free
|
|
|
- PK_FREE(item);
|
|
|
- } else {
|
|
|
- // some free
|
|
|
- c11_vector__push(PoolArena*, arenas, item);
|
|
|
- }
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- c11_vector__swap(&self->arenas, arenas);
|
|
|
- c11_vector__swap(&self->no_free_arenas, no_free_arenas);
|
|
|
+ // [[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);
|
|
|
}
|