blueloveTH 3 mesiacov pred
rodič
commit
ef9b4779f4

+ 1 - 1
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;
 

+ 60 - 76
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);
+    }
+
+    // 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);
 }