From 723407dafebd15a879ccd1d4b0d4e2f280ca97dc Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 21 Jan 2025 19:13:36 +0800 Subject: [PATCH 1/8] backup backup backup ... --- README.md | 4 +- docs/index.md | 2 +- docs/quick-start.md | 2 +- docs/retype.yml | 2 +- include/pocketpy/common/memorypool.h | 10 - include/pocketpy/common/vector.h | 1 + include/pocketpy/config.h | 4 +- include/pocketpy/interpreter/heap.h | 19 +- include/pocketpy/interpreter/objectpool.h | 30 +++ include/pocketpy/objects/object.h | 5 +- plugins/flutter/pocketpy/pubspec.yaml | 2 +- src/common/memorypool.c | 232 ---------------------- src/common/vector.c | 6 + src/interpreter/heap.c | 126 ++++++------ src/interpreter/objectpool.c | 174 ++++++++++++++++ src/interpreter/vm.c | 18 +- 16 files changed, 294 insertions(+), 343 deletions(-) create mode 100644 include/pocketpy/interpreter/objectpool.h create mode 100644 src/interpreter/objectpool.c diff --git a/README.md b/README.md index dc4ec8d1..4d8b6434 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Please see https://pocketpy.dev for details and try the following resources. pkpy should work on any platform with a C11 compiler. These platforms are officially tested. -> C99 compilers also work currently according to users' feedback. +> C99 compilers may also work currently according to users' feedback. + Windows 64-bit + Linux 64-bit / 32-bit @@ -74,7 +74,7 @@ It is safe to use `main` branch in production if CI badge is green. To compile it with your project, these flags must be set: -+ `--std=c11` flag must be set (`--std=c99` may also work) ++ `--std=c11` flag must be set + For MSVC, `/utf-8` flag must be set + `NDEBUG` macro should be defined for release build, or you will get poor performance diff --git a/docs/index.md b/docs/index.md index 21794657..550f106b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,7 +32,7 @@ print(primes) pkpy should work on any platform with a C11 compiler. These platforms are officially tested. -> C99 compilers also work currently according to users' feedback. +> C99 compilers may also work currently according to users' feedback. + Windows 64-bit + Linux 64-bit / 32-bit diff --git a/docs/quick-start.md b/docs/quick-start.md index 99b4b0c2..a585e3ab 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -29,7 +29,7 @@ It is safe to use `main` branch in production if CI badge is green. To compile it with your project, these flags must be set: -+ `--std=c11` flag must be set (`--std=c99` may also work) ++ `--std=c11` flag must be set + For MSVC, `/utf-8` flag must be set + `NDEBUG` macro should be defined for release build, or you will get poor performance diff --git a/docs/retype.yml b/docs/retype.yml index c702101d..ef382904 100644 --- a/docs/retype.yml +++ b/docs/retype.yml @@ -3,7 +3,7 @@ output: .retype url: https://pocketpy.dev branding: title: pocketpy - label: v2.0.5 + label: v2.0.6 logo: "./static/logo.png" favicon: "./static/logo.png" meta: diff --git a/include/pocketpy/common/memorypool.h b/include/pocketpy/common/memorypool.h index 4afc6fb1..49a542ff 100644 --- a/include/pocketpy/common/memorypool.h +++ b/include/pocketpy/common/memorypool.h @@ -2,10 +2,6 @@ #define kPoolExprBlockSize 128 #define kPoolFrameBlockSize 80 -#define kPoolObjectBlockSize 80 - -#define kPoolObjectArenaSize (256*1024) -#define kPoolObjectMaxBlocks (kPoolObjectArenaSize / kPoolObjectBlockSize) void MemoryPools__initialize(); void MemoryPools__finalize(); @@ -14,9 +10,3 @@ void* PoolExpr_alloc(); void PoolExpr_dealloc(void*); void* PoolFrame_alloc(); void PoolFrame_dealloc(void*); - -void* PoolObject_alloc(); -void PoolObject_dealloc(void* p); -void PoolObject_shrink_to_fit(); - -void Pools_debug_info(char* buffer, int size); diff --git a/include/pocketpy/common/vector.h b/include/pocketpy/common/vector.h index 836c792e..a37ae111 100644 --- a/include/pocketpy/common/vector.h +++ b/include/pocketpy/common/vector.h @@ -22,6 +22,7 @@ void c11_vector__clear(c11_vector* self); void* c11_vector__emplace(c11_vector* self); bool c11_vector__contains(const c11_vector* self, void* elem); void* c11_vector__submit(c11_vector* self, int* length); +void c11_vector__swap(c11_vector* self, c11_vector* other); #define c11__getitem(T, self, index) (((T*)(self)->data)[index]) #define c11__setitem(T, self, index, value) ((T*)(self)->data)[index] = value; diff --git a/include/pocketpy/config.h b/include/pocketpy/config.h index f72144b8..e512ffa5 100644 --- a/include/pocketpy/config.h +++ b/include/pocketpy/config.h @@ -1,10 +1,10 @@ #pragma once // clang-format off -#define PK_VERSION "2.0.5" +#define PK_VERSION "2.0.6" #define PK_VERSION_MAJOR 2 #define PK_VERSION_MINOR 0 -#define PK_VERSION_PATCH 5 +#define PK_VERSION_PATCH 6 /*************** feature settings ***************/ diff --git a/include/pocketpy/interpreter/heap.h b/include/pocketpy/interpreter/heap.h index 03986143..c997fd22 100644 --- a/include/pocketpy/interpreter/heap.h +++ b/include/pocketpy/interpreter/heap.h @@ -1,24 +1,25 @@ #include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/objectpool.h" -typedef struct ManagedHeap{ - c11_vector no_gc; - c11_vector gen; +typedef struct ManagedHeap { + MultiPool small_objects; + c11_vector large_objects; - int gc_threshold; - int gc_counter; + int freed_ma[3]; + int gc_threshold; // threshold for gc_counter + int gc_counter; // objects created since last gc bool gc_enabled; - - VM* vm; } ManagedHeap; -void ManagedHeap__ctor(ManagedHeap* self, VM* vm); +void ManagedHeap__ctor(ManagedHeap* self); void ManagedHeap__dtor(ManagedHeap* self); void ManagedHeap__collect_if_needed(ManagedHeap* self); int ManagedHeap__collect(ManagedHeap* self); int ManagedHeap__sweep(ManagedHeap* self); -PyObject* ManagedHeap__new(ManagedHeap* self, py_Type type, int slots, int udsize); +#define ManagedHeap__new(self, type, slots, udsize) \ + ManagedHeap__gcnew((self), (type), (slots), (udsize)) PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize); // external implementation diff --git a/include/pocketpy/interpreter/objectpool.h b/include/pocketpy/interpreter/objectpool.h new file mode 100644 index 00000000..51d06d49 --- /dev/null +++ b/include/pocketpy/interpreter/objectpool.h @@ -0,0 +1,30 @@ +#pragma once + +#include "pocketpy/common/vector.h" + +#define kPoolArenaSize (120 * 1024) +#define kMultiPoolCount 5 +#define kPoolMaxBlockSize (32*kMultiPoolCount) + +typedef struct PoolArena { + int block_size; + int block_count; + int unused_count; + int* unused; + char data[kPoolArenaSize]; +} PoolArena; + +typedef struct Pool { + c11_vector /* PoolArena* */ arenas; + c11_vector /* PoolArena* */ not_free_arenas; + int block_size; +} Pool; + +typedef struct MultiPool { + Pool pools[kMultiPoolCount]; +} MultiPool; + +void* MultiPool__alloc(MultiPool* self, int size); +int MultiPool__sweep_dealloc(MultiPool* self); +void MultiPool__ctor(MultiPool* self); +void MultiPool__dtor(MultiPool* self); diff --git a/include/pocketpy/objects/object.h b/include/pocketpy/objects/object.h index 622dc187..822df540 100644 --- a/include/pocketpy/objects/object.h +++ b/include/pocketpy/objects/object.h @@ -5,7 +5,7 @@ typedef struct PyObject { py_Type type; // we have a duplicated type here for convenience - bool gc_is_large; + // bool _; bool gc_marked; int slots; // number of slots in the object char flex[]; @@ -23,5 +23,4 @@ void* PyObject__userdata(PyObject* self); #define PK_OBJ_SLOTS_SIZE(slots) ((slots) >= 0 ? sizeof(py_TValue) * (slots) : sizeof(NameDict)) -PyObject* PyObject__new(py_Type type, int slots, int size); -void PyObject__delete(PyObject* self); +void PyObject__dtor(PyObject* self); diff --git a/plugins/flutter/pocketpy/pubspec.yaml b/plugins/flutter/pocketpy/pubspec.yaml index 798f767d..b6200886 100644 --- a/plugins/flutter/pocketpy/pubspec.yaml +++ b/plugins/flutter/pocketpy/pubspec.yaml @@ -1,6 +1,6 @@ name: pocketpy description: A lightweight Python interpreter for game engines. It supports Android/iOS/Windows/Linux/MacOS. -version: 2.0.5 +version: 2.0.6 homepage: https://pocketpy.dev repository: https://github.com/pocketpy/pocketpy diff --git a/src/common/memorypool.c b/src/common/memorypool.c index 5c09861b..76c24723 100644 --- a/src/common/memorypool.c +++ b/src/common/memorypool.c @@ -2,183 +2,8 @@ #include "pocketpy/pocketpy.h" #include -#include -#include -#include #include -typedef struct LinkedListNode { - struct LinkedListNode* prev; - struct LinkedListNode* next; -} LinkedListNode; - -typedef struct LinkedList { - int length; - LinkedListNode head; - LinkedListNode tail; -} LinkedList; - -static void LinkedList__ctor(LinkedList* self) { - self->length = 0; - self->head.prev = NULL; - self->head.next = &self->tail; - self->tail.prev = &self->head; - self->tail.next = NULL; -} - -static void LinkedList__push_back(LinkedList* self, LinkedListNode* node) { - node->prev = self->tail.prev; - node->next = &self->tail; - self->tail.prev->next = node; - self->tail.prev = node; - self->length++; -} - -static void LinkedList__push_front(LinkedList* self, LinkedListNode* node) { - node->prev = &self->head; - node->next = self->head.next; - self->head.next->prev = node; - self->head.next = node; - self->length++; -} - -static void LinkedList__pop_back(LinkedList* self) { - assert(self->length > 0); - self->tail.prev->prev->next = &self->tail; - self->tail.prev = self->tail.prev->prev; - self->length--; -} - -static LinkedListNode* LinkedList__back(LinkedList* self) { - assert(self->length > 0); - return self->tail.prev; -} - -static void LinkedList__erase(LinkedList* self, LinkedListNode* node) { - node->prev->next = node->next; - node->next->prev = node->prev; - self->length--; -} - -#define LinkedList__apply(self, __STATEMENTS__) \ - do { \ - LinkedListNode* node = (self)->head.next; \ - while(node != &(self)->tail) { \ - LinkedListNode* next = node->next; \ - __STATEMENTS__ \ - node = next; \ - } \ - } while(0) - -typedef struct MemoryPoolBlock{ - void* arena; - char data[kPoolObjectBlockSize]; -} MemoryPoolBlock; - -typedef struct MemoryPoolArena{ - /* LinkedListNode */ - LinkedListNode* prev; - LinkedListNode* next; - /* Arena */ - MemoryPoolBlock _blocks[kPoolObjectMaxBlocks]; - MemoryPoolBlock* _free_list[kPoolObjectMaxBlocks]; - int _free_list_size; -} MemoryPoolArena; - -typedef struct MemoryPool{ - LinkedList _arenas; - LinkedList _empty_arenas; -} MemoryPool; - -static void MemoryPoolArena__ctor(MemoryPoolArena* self) { - self->prev = NULL; - self->next = NULL; - self->_free_list_size = kPoolObjectMaxBlocks; - for(int i = 0; i < kPoolObjectMaxBlocks; i++) { - self->_blocks[i].arena = self; - self->_free_list[i] = &self->_blocks[i]; - } -} - -static bool MemoryPoolArena__empty(MemoryPoolArena* self) { - return self->_free_list_size == 0; -} - -static bool MemoryPoolArena__full(MemoryPoolArena* self) { - return self->_free_list_size == kPoolObjectMaxBlocks; -} - -static int MemoryPoolArena__total_bytes(MemoryPoolArena* self) { - return kPoolObjectArenaSize; -} - -static int MemoryPoolArena__used_bytes(MemoryPoolArena* self) { - return kPoolObjectBlockSize * (kPoolObjectMaxBlocks - self->_free_list_size); -} - -static MemoryPoolBlock* MemoryPoolArena__alloc(MemoryPoolArena* self) { - assert(!MemoryPoolArena__empty(self)); - self->_free_list_size--; - return self->_free_list[self->_free_list_size]; -} - -static void MemoryPoolArena__dealloc(MemoryPoolArena* self, MemoryPoolBlock* block) { - assert(!MemoryPoolArena__full(self)); - self->_free_list[self->_free_list_size] = block; - self->_free_list_size++; -} - -static void MemoryPool__ctor(MemoryPool* self) { - LinkedList__ctor(&self->_arenas); - LinkedList__ctor(&self->_empty_arenas); -} - -static void* MemoryPool__alloc(MemoryPool* self) { - MemoryPoolArena* arena; - if(self->_arenas.length == 0){ - arena = PK_MALLOC(sizeof(MemoryPoolArena)); - MemoryPoolArena__ctor(arena); - LinkedList__push_back(&self->_arenas, (LinkedListNode*)arena); - } else { - arena = (MemoryPoolArena*)LinkedList__back(&self->_arenas); - } - void* p = MemoryPoolArena__alloc(arena)->data; - if(MemoryPoolArena__empty(arena)) { - LinkedList__pop_back(&self->_arenas); - LinkedList__push_back(&self->_empty_arenas, (LinkedListNode*)arena); - } - return p; -} - -static void MemoryPool__dealloc(MemoryPool* self, void* p) { - assert(p != NULL); - MemoryPoolBlock* block = (MemoryPoolBlock*)((char*)p - sizeof(void*)); - assert(block->arena != NULL); - MemoryPoolArena* arena = (MemoryPoolArena*)block->arena; - if(MemoryPoolArena__empty(arena)) { - LinkedList__erase(&self->_empty_arenas, (LinkedListNode*)arena); - LinkedList__push_front(&self->_arenas, (LinkedListNode*)arena); - } - MemoryPoolArena__dealloc(arena, block); -} - -static void MemoryPool__shrink_to_fit(MemoryPool* self) { - const int MIN_ARENA_COUNT = PK_GC_MIN_THRESHOLD * 100 / (kPoolObjectArenaSize); - if(self->_arenas.length < MIN_ARENA_COUNT) return; - LinkedList__apply(&self->_arenas, - MemoryPoolArena* arena = (MemoryPoolArena*)node; - if(MemoryPoolArena__full(arena)) { - LinkedList__erase(&self->_arenas, node); - PK_FREE(arena); - }); -} - - -static void MemoryPool__dtor(MemoryPool* self) { - LinkedList__apply(&self->_arenas, PK_FREE(node);); - LinkedList__apply(&self->_empty_arenas, PK_FREE(node);); -} - typedef struct FixedMemoryPool { int BlockSize; int BlockCount; @@ -240,18 +65,15 @@ static int FixedMemoryPool__total_bytes(FixedMemoryPool* self) { static FixedMemoryPool PoolExpr; static FixedMemoryPool PoolFrame; -static MemoryPool PoolObject; void MemoryPools__initialize(){ FixedMemoryPool__ctor(&PoolExpr, kPoolExprBlockSize, 64); FixedMemoryPool__ctor(&PoolFrame, kPoolFrameBlockSize, 128); - MemoryPool__ctor(&PoolObject); } void MemoryPools__finalize(){ FixedMemoryPool__dtor(&PoolExpr); FixedMemoryPool__dtor(&PoolFrame); - MemoryPool__dtor(&PoolObject); } void* PoolExpr_alloc() { @@ -269,57 +91,3 @@ void* PoolFrame_alloc() { void PoolFrame_dealloc(void* p) { FixedMemoryPool__dealloc(&PoolFrame, p); } - -void* PoolObject_alloc() { - return MemoryPool__alloc(&PoolObject); -} - -void PoolObject_dealloc(void* p) { - MemoryPool__dealloc(&PoolObject, p); -} - -void PoolObject_shrink_to_fit() { - MemoryPool__shrink_to_fit(&PoolObject); -} - -void Pools_debug_info(char* buffer, int size) { - double BYTES_PER_MB = 1024.0f * 1024.0f; - double BYTES_PER_KB = 1024.0f; - int n = 0; - n = snprintf( - buffer, size, "PoolExpr: %.2f KB (used) / %.2f KB (total) - %.2f KB (exceeded)\n", - FixedMemoryPool__used_bytes(&PoolExpr) / BYTES_PER_KB, - FixedMemoryPool__total_bytes(&PoolExpr) / BYTES_PER_KB, - PoolExpr.exceeded_bytes / BYTES_PER_KB - ); - buffer += n; size -= n; - n = snprintf( - buffer, size, "PoolFrame: %.2f KB (used) / %.2f KB (total) - %.2f KB (exceeded)\n", - FixedMemoryPool__used_bytes(&PoolFrame) / BYTES_PER_KB, - FixedMemoryPool__total_bytes(&PoolFrame) / BYTES_PER_KB, - PoolFrame.exceeded_bytes / BYTES_PER_KB - ); - buffer += n; size -= n; - // PoolObject - int empty_arenas = PoolObject._empty_arenas.length; - int arenas = PoolObject._arenas.length; - // print empty arenas count - n = snprintf( - buffer, size, "PoolObject: %d empty arenas, %d arenas\n", - empty_arenas, arenas - ); - buffer += n; size -= n; - // log each non-empty arena - LinkedList__apply(&PoolObject._arenas, - MemoryPoolArena* arena = (MemoryPoolArena*)node; - n = snprintf( - buffer, size, " - %p: %.2f MB (used) / %.2f MB (total)\n", - (void*)arena, - MemoryPoolArena__used_bytes(arena) / BYTES_PER_MB, - MemoryPoolArena__total_bytes(arena) / BYTES_PER_MB - ); - buffer += n; size -= n; - ); -} - -#undef LinkedList__apply \ No newline at end of file diff --git a/src/common/vector.c b/src/common/vector.c index f26a833a..32b97fe4 100644 --- a/src/common/vector.c +++ b/src/common/vector.c @@ -62,3 +62,9 @@ void* c11_vector__submit(c11_vector* self, int* length) { self->capacity = 0; return retval; } + +void c11_vector__swap(c11_vector *self, c11_vector *other){ + c11_vector tmp = *self; + *self = *other; + *other = tmp; +} diff --git a/src/interpreter/heap.c b/src/interpreter/heap.c index be74615c..952a1455 100644 --- a/src/interpreter/heap.c +++ b/src/interpreter/heap.c @@ -1,39 +1,46 @@ #include "pocketpy/interpreter/heap.h" -#include "pocketpy/common/memorypool.h" #include "pocketpy/config.h" +#include "pocketpy/interpreter/objectpool.h" #include "pocketpy/objects/base.h" +#include "pocketpy/pocketpy.h" -void ManagedHeap__ctor(ManagedHeap* self, VM* vm) { - c11_vector__ctor(&self->no_gc, sizeof(PyObject*)); - c11_vector__ctor(&self->gen, sizeof(PyObject*)); +void ManagedHeap__ctor(ManagedHeap* self) { + MultiPool__ctor(&self->small_objects); + c11_vector__ctor(&self->large_objects, sizeof(PyObject*)); + for(int i = 0; i < c11__count_array(self->freed_ma); i++) { + self->freed_ma[i] = PK_GC_MIN_THRESHOLD; + } self->gc_threshold = PK_GC_MIN_THRESHOLD; self->gc_counter = 0; self->gc_enabled = true; - - self->vm = vm; } void ManagedHeap__dtor(ManagedHeap* self) { - for(int i = 0; i < self->gen.length; i++) { - PyObject* obj = c11__getitem(PyObject*, &self->gen, i); - PyObject__delete(obj); + // small_objects + MultiPool__dtor(&self->small_objects); + // large_objects + for(int i = 0; i < self->large_objects.length; i++) { + PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i); + PyObject__dtor(obj); + PK_FREE(obj); } - for(int i = 0; i < self->no_gc.length; i++) { - PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i); - PyObject__delete(obj); - } - c11_vector__dtor(&self->no_gc); - c11_vector__dtor(&self->gen); + c11_vector__dtor(&self->large_objects); } void ManagedHeap__collect_if_needed(ManagedHeap* self) { if(!self->gc_enabled) return; if(self->gc_counter < self->gc_threshold) return; self->gc_counter = 0; - ManagedHeap__collect(self); - self->gc_threshold = self->gen.length * 2; - if(self->gc_threshold < PK_GC_MIN_THRESHOLD) { self->gc_threshold = PK_GC_MIN_THRESHOLD; } + int freed = ManagedHeap__collect(self); + // adjust `gc_threshold` based on `freed_ma` + self->freed_ma[0] = self->freed_ma[1]; + self->freed_ma[1] = self->freed_ma[2]; + self->freed_ma[2] = freed; + int avg_freed = (self->freed_ma[0] + self->freed_ma[1] + self->freed_ma[2]) / 3; + int upper = self->gc_threshold * 2; + int lower = c11__max(PK_GC_MIN_THRESHOLD, self->gc_threshold / 2 + 1); + self->gc_threshold = c11__min(c11__max(avg_freed, lower), upper); } int ManagedHeap__collect(ManagedHeap* self) { @@ -43,71 +50,52 @@ int ManagedHeap__collect(ManagedHeap* self) { } int ManagedHeap__sweep(ManagedHeap* self) { - c11_vector alive; - c11_vector__ctor(&alive, sizeof(PyObject*)); - c11_vector__reserve(&alive, self->gen.length / 2); - - for(int i = 0; i < self->gen.length; i++) { - PyObject* obj = c11__getitem(PyObject*, &self->gen, i); + // small_objects + int small_freed = MultiPool__sweep_dealloc(&self->small_objects); + // large_objects + int large_living_count = 0; + for(int i = 0; i < self->large_objects.length; i++) { + PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i); if(obj->gc_marked) { obj->gc_marked = false; - c11_vector__push(PyObject*, &alive, obj); + c11__setitem(PyObject*, &self->large_objects, large_living_count, obj); + large_living_count++; } else { - PyObject__delete(obj); + PyObject__dtor(obj); + PK_FREE(obj); + // type and module objects are perpectual + assert(obj->type != tp_type); + assert(obj->type != tp_module); } } - - // clear _no_gc marked flag - for(int i = 0; i < self->no_gc.length; i++) { - PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i); - obj->gc_marked = false; - } - - int freed = self->gen.length - alive.length; - - // destroy old gen - c11_vector__dtor(&self->gen); - // move alive to gen - self->gen = alive; - - PoolObject_shrink_to_fit(); - return freed; -} - -PyObject* ManagedHeap__new(ManagedHeap* self, py_Type type, int slots, int udsize) { - PyObject* obj = PyObject__new(type, slots, udsize); - c11_vector__push(PyObject*, &self->no_gc, obj); - return obj; + // shrink `self->large_objects` + int large_freed = self->large_objects.length - large_living_count; + self->large_objects.length = large_living_count; + return small_freed + large_freed; } PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize) { - PyObject* obj = PyObject__new(type, slots, udsize); - c11_vector__push(PyObject*, &self->gen, obj); - self->gc_counter++; - return obj; -} - -PyObject* PyObject__new(py_Type type, int slots, int size) { assert(slots >= 0 || slots == -1); - PyObject* self; + PyObject* obj; // header + slots + udsize - size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + size; - if(!PK_LOW_MEMORY_MODE && size <= kPoolObjectBlockSize) { - self = PoolObject_alloc(); - self->gc_is_large = false; + int size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + udsize; + if(!PK_LOW_MEMORY_MODE && size <= kPoolMaxBlockSize) { + obj = MultiPool__alloc(&self->small_objects, size); } else { - self = PK_MALLOC(size); - self->gc_is_large = true; + obj = PK_MALLOC(size); + c11_vector__push(PyObject*, &self->large_objects, obj); } - self->type = type; - self->gc_marked = false; - self->slots = slots; + obj->type = type; + obj->gc_marked = false; + obj->slots = slots; // initialize slots or dict if(slots >= 0) { - memset(self->flex, 0, slots * sizeof(py_TValue)); + memset(obj->flex, 0, slots * sizeof(py_TValue)); } else { - NameDict__ctor((void*)self->flex); + NameDict__ctor((void*)obj->flex); } - return self; -} + + self->gc_counter++; + return obj; +} \ No newline at end of file diff --git a/src/interpreter/objectpool.c b/src/interpreter/objectpool.c new file mode 100644 index 00000000..34def166 --- /dev/null +++ b/src/interpreter/objectpool.c @@ -0,0 +1,174 @@ +#include "pocketpy/interpreter/objectpool.h" + +#include "pocketpy/config.h" +#include "pocketpy/objects/object.h" + +#include +#include +#include +#include + +static PoolArena* PoolArena__new(int block_size) { + assert(kPoolArenaSize % block_size == 0); + int block_count = kPoolArenaSize / block_size; + int total_size = sizeof(PoolArena) + sizeof(int) * block_count; + PoolArena* self = PK_MALLOC(total_size); + self->block_size = block_size; + self->block_count = block_count; + self->unused_count = block_count; + self->unused = PK_MALLOC(sizeof(int) * block_count); + for(int i = 0; i < block_count; i++) { + self->unused[i] = i; + } + memset(self->data, 0, kPoolArenaSize); + 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->unused); + PK_FREE(self); +} + +static void* PoolArena__alloc(PoolArena* self) { + assert(self->unused_count > 0); + int index = self->unused[self->unused_count - 1]; + self->unused_count--; + return self->data + index * self->block_size; +} + +static int PoolArena__sweep_dealloc(PoolArena* self) { + int freed = 0; + self->unused_count = 0; + for(int i = 0; i < self->block_count; i++) { + PyObject* obj = (PyObject*)(self->data + i * self->block_size); + if(obj->type == 0) { + self->unused[self->unused_count] = i; + self->unused_count++; + } else { + if(!obj->gc_marked) { + obj->type = 0; + freed++; + self->unused[self->unused_count] = i; + self->unused_count++; + } else { + obj->gc_marked = false; + } + } + } + return freed; +} + +static void Pool__ctor(Pool* self, int block_size) { + c11_vector__ctor(&self->arenas, sizeof(PoolArena*)); + c11_vector__ctor(&self->not_free_arenas, sizeof(PoolArena*)); + self->block_size = block_size; +} + +static void Pool__dtor(Pool* self) { + c11__foreach(PoolArena*, &self->arenas, arena) { PoolArena__delete(*arena); } + c11__foreach(PoolArena*, &self->not_free_arenas, arena) { PoolArena__delete(*arena); } + c11_vector__dtor(&self->arenas); + c11_vector__dtor(&self->not_free_arenas); +} + +static void* Pool__alloc(Pool* self) { + PoolArena* arena; + if(self->arenas.length == 0) { + arena = PoolArena__new(self->block_size); + c11_vector__push(PoolArena*, &self->arenas, arena); + } else { + arena = c11_vector__back(PoolArena*, &self->arenas); + } + void* ptr = PoolArena__alloc(arena); + if(arena->unused_count == 0) { + c11_vector__pop(&self->arenas); + c11_vector__push(PoolArena*, &self->not_free_arenas, arena); + } + return ptr; +} + +static int Pool__sweep_dealloc(Pool* self, c11_vector* arenas, c11_vector* not_free_arenas) { + c11_vector__clear(arenas); + c11_vector__clear(not_free_arenas); + + int freed = 0; + for(int i = 0; i < self->arenas.length; i++) { + PoolArena* item = c11__getitem(PoolArena*, &self->arenas, i); + assert(item->unused_count > 0); + freed += PoolArena__sweep_dealloc(item); + if(item->unused_count == item->block_count) { + // all free + if(self->arenas.length > 0) { + // at least one arena + PoolArena__delete(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->not_free_arenas.length; i++) { + PoolArena* item = c11__getitem(PoolArena*, &self->not_free_arenas, i); + freed += PoolArena__sweep_dealloc(item); + if(item->unused_count == 0) { + // still not free + c11_vector__push(PoolArena*, not_free_arenas, item); + } else { + if(item->unused_count == item->block_count) { + // all free + PoolArena__delete(item); + } else { + // some free + c11_vector__push(PoolArena*, arenas, item); + } + } + } + + c11_vector__swap(&self->arenas, arenas); + c11_vector__swap(&self->not_free_arenas, not_free_arenas); + return freed; +} + +void* MultiPool__alloc(MultiPool* self, int size) { + if(size == 0) return NULL; + int index = (size - 1) >> 5; + if(index < kMultiPoolCount) { + Pool* pool = &self->pools[index]; + return Pool__alloc(pool); + } + return NULL; +} + +int MultiPool__sweep_dealloc(MultiPool* self) { + c11_vector arenas; + c11_vector not_free_arenas; + c11_vector__ctor(&arenas, sizeof(PoolArena*)); + c11_vector__ctor(¬_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, ¬_free_arenas); + } + c11_vector__dtor(&arenas); + c11_vector__dtor(¬_free_arenas); + return freed; +} + +void MultiPool__ctor(MultiPool* self) { + for(int i = 0; i < kMultiPoolCount; i++) { + Pool__ctor(&self->pools[i], 32 * (i + 1)); + } +} + +void MultiPool__dtor(MultiPool* self) { + for(int i = 0; i < kMultiPoolCount; i++) { + Pool__dtor(&self->pools[i]); + } +} \ No newline at end of file diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 5d5deb6d..1d77862e 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -1,5 +1,4 @@ #include "pocketpy/interpreter/vm.h" -#include "pocketpy/common/memorypool.h" #include "pocketpy/common/sstream.h" #include "pocketpy/common/utils.h" #include "pocketpy/interpreter/generator.h" @@ -76,7 +75,7 @@ void VM__ctor(VM* self) { self->__curr_class = NULL; self->__curr_function = NULL; - ManagedHeap__ctor(&self->heap, self); + ManagedHeap__ctor(&self->heap); ValueStack__ctor(&self->stack); /* Init Builtin Types */ @@ -569,15 +568,10 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall } /****************************************/ -void PyObject__delete(PyObject* self) { +void PyObject__dtor(PyObject* self) { py_TypeInfo* ti = pk__type_info(self->type); if(ti->dtor) ti->dtor(PyObject__userdata(self)); if(self->slots == -1) NameDict__dtor(PyObject__dict(self)); - if(self->gc_is_large) { - PK_FREE(self); - } else { - PoolObject_dealloc(self); - } } static void mark_object(PyObject* obj); @@ -636,10 +630,10 @@ void CodeObject__gc_mark(const CodeObject* self) { } void ManagedHeap__mark(ManagedHeap* self) { - VM* vm = self->vm; - // mark heap objects - for(int i = 0; i < self->no_gc.length; i++) { - PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i); + VM* vm = pk_current_vm; + // mark large objects + for(int i = 0; i < self->large_objects.length; i++) { + PyObject* obj = c11__getitem(PyObject*, &self->large_objects, i); mark_object(obj); } // mark value stack From ce9758768999ab5e7ab0a7aeef377ba7adf9c6e1 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 23 Jan 2025 13:14:41 +0800 Subject: [PATCH 2/8] ... --- include/pocketpy/common/memorypool.h | 22 ++++++---- include/pocketpy/interpreter/vm.h | 2 + src/common/memorypool.c | 61 +++++-------------------- src/compiler/compiler.c | 66 ++++++++++------------------ src/interpreter/frame.c | 6 +-- src/interpreter/vm.c | 4 ++ src/public/internal.c | 2 - 7 files changed, 55 insertions(+), 108 deletions(-) diff --git a/include/pocketpy/common/memorypool.h b/include/pocketpy/common/memorypool.h index 49a542ff..e732d19f 100644 --- a/include/pocketpy/common/memorypool.h +++ b/include/pocketpy/common/memorypool.h @@ -1,12 +1,18 @@ #pragma once -#define kPoolExprBlockSize 128 -#define kPoolFrameBlockSize 80 +typedef struct FixedMemoryPool { + int BlockSize; + int BlockCount; -void MemoryPools__initialize(); -void MemoryPools__finalize(); + char* data; + char* data_end; + int exceeded_bytes; -void* PoolExpr_alloc(); -void PoolExpr_dealloc(void*); -void* PoolFrame_alloc(); -void PoolFrame_dealloc(void*); + char** _free_list; + char** _free_list_end; +} FixedMemoryPool; + +void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount); +void FixedMemoryPool__dtor(FixedMemoryPool* self); +void* FixedMemoryPool__alloc(FixedMemoryPool* self); +void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p); \ No newline at end of file diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 678cdd20..77df406c 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -1,5 +1,6 @@ #pragma once +#include "pocketpy/common/memorypool.h" #include "pocketpy/objects/codeobject.h" #include "pocketpy/pocketpy.h" #include "pocketpy/interpreter/heap.h" @@ -38,6 +39,7 @@ typedef struct VM { py_StackRef __curr_function; py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES]; + FixedMemoryPool pool_frame; ManagedHeap heap; ValueStack stack; // put `stack` at the end for better cache locality } VM; diff --git a/src/common/memorypool.c b/src/common/memorypool.c index 76c24723..4104fa17 100644 --- a/src/common/memorypool.c +++ b/src/common/memorypool.c @@ -4,19 +4,7 @@ #include #include -typedef struct FixedMemoryPool { - int BlockSize; - int BlockCount; - - char* data; - char* data_end; - int exceeded_bytes; - - char** _free_list; - char** _free_list_end; -} FixedMemoryPool; - -static void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount) { +void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount) { self->BlockSize = BlockSize; self->BlockCount = BlockCount; self->exceeded_bytes = 0; @@ -29,12 +17,12 @@ static void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int Bloc } } -static void FixedMemoryPool__dtor(FixedMemoryPool* self) { +void FixedMemoryPool__dtor(FixedMemoryPool* self) { PK_FREE(self->_free_list); PK_FREE(self->data); } -static void* FixedMemoryPool__alloc(FixedMemoryPool* self) { +void* FixedMemoryPool__alloc(FixedMemoryPool* self) { if(self->_free_list_end != self->_free_list) { self->_free_list_end--; return *self->_free_list_end; @@ -44,7 +32,7 @@ static void* FixedMemoryPool__alloc(FixedMemoryPool* self) { } } -static void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p) { +void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p) { bool is_valid = (char*)p >= self->data && (char*)p < self->data_end; if(is_valid) { *self->_free_list_end = p; @@ -55,39 +43,10 @@ static void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p) { } } -static int FixedMemoryPool__used_bytes(FixedMemoryPool* self) { - return (self->_free_list_end - self->_free_list) * self->BlockSize; -} +// static int FixedMemoryPool__used_bytes(FixedMemoryPool* self) { +// return (self->_free_list_end - self->_free_list) * self->BlockSize; +// } -static int FixedMemoryPool__total_bytes(FixedMemoryPool* self) { - return self->BlockCount * self->BlockSize; -} - -static FixedMemoryPool PoolExpr; -static FixedMemoryPool PoolFrame; - -void MemoryPools__initialize(){ - FixedMemoryPool__ctor(&PoolExpr, kPoolExprBlockSize, 64); - FixedMemoryPool__ctor(&PoolFrame, kPoolFrameBlockSize, 128); -} - -void MemoryPools__finalize(){ - FixedMemoryPool__dtor(&PoolExpr); - FixedMemoryPool__dtor(&PoolFrame); -} - -void* PoolExpr_alloc() { - return FixedMemoryPool__alloc(&PoolExpr); -} - -void PoolExpr_dealloc(void* p) { - FixedMemoryPool__dealloc(&PoolExpr, p); -} - -void* PoolFrame_alloc() { - return FixedMemoryPool__alloc(&PoolFrame); -} - -void PoolFrame_dealloc(void* p) { - FixedMemoryPool__dealloc(&PoolFrame, p); -} +// static int FixedMemoryPool__total_bytes(FixedMemoryPool* self) { +// return self->BlockCount * self->BlockSize; +// } \ No newline at end of file diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index b6aee04c..eeefad2d 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -1,10 +1,10 @@ #include "pocketpy/compiler/compiler.h" #include "pocketpy/compiler/lexer.h" +#include "pocketpy/objects/base.h" #include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/sourcedata.h" #include "pocketpy/objects/object.h" #include "pocketpy/common/sstream.h" -#include "pocketpy/common/memorypool.h" #include #include @@ -30,8 +30,6 @@ typedef struct ExprVt { void (*dtor)(Expr*); } ExprVt; -#define static_assert_expr_size(T) static_assert(sizeof(T) <= kPoolExprBlockSize, "") - #define vtcall(f, self, ctx) ((self)->vt->f((self), (ctx))) #define vtemit_(self, ctx) vtcall(emit_, (self), (ctx)) #define vtemit_del(self, ctx) ((self)->vt->emit_del ? vtcall(emit_del, self, ctx) : false) @@ -44,7 +42,7 @@ typedef struct ExprVt { do { \ if(self) { \ if((self)->vt->dtor) (self)->vt->dtor(self); \ - PoolExpr_dealloc(self); \ + PK_FREE(self); \ } \ } while(0) @@ -148,8 +146,7 @@ NameExpr* NameExpr__new(int line, py_Name name, NameScope scope) { .emit_del = NameExpr__emit_del, .emit_store = NameExpr__emit_store, .is_name = true}; - static_assert_expr_size(NameExpr); - NameExpr* self = PoolExpr_alloc(); + NameExpr* self = PK_MALLOC(sizeof(NameExpr)); self->vt = &Vt; self->line = line; self->name = name; @@ -186,8 +183,7 @@ StarredExpr* StarredExpr__new(int line, Expr* child, int level) { .emit_store = StarredExpr__emit_store, .is_starred = true, .dtor = StarredExpr__dtor}; - static_assert_expr_size(StarredExpr); - StarredExpr* self = PoolExpr_alloc(); + StarredExpr* self = PK_MALLOC(sizeof(StarredExpr)); self->vt = &Vt; self->line = line; self->child = child; @@ -216,8 +212,7 @@ static void UnaryExpr__emit_(Expr* self_, Ctx* ctx) { UnaryExpr* UnaryExpr__new(int line, Expr* child, Opcode opcode) { const static ExprVt Vt = {.emit_ = UnaryExpr__emit_, .dtor = UnaryExpr__dtor}; - static_assert_expr_size(UnaryExpr); - UnaryExpr* self = PoolExpr_alloc(); + UnaryExpr* self = PK_MALLOC(sizeof(UnaryExpr)); self->vt = &Vt; self->line = line; self->child = child; @@ -240,8 +235,7 @@ void FStringSpecExpr__emit_(Expr* self_, Ctx* ctx) { FStringSpecExpr* FStringSpecExpr__new(int line, Expr* child, c11_sv spec) { const static ExprVt Vt = {.emit_ = FStringSpecExpr__emit_, .dtor = UnaryExpr__dtor}; - static_assert_expr_size(FStringSpecExpr); - FStringSpecExpr* self = PoolExpr_alloc(); + FStringSpecExpr* self = PK_MALLOC(sizeof(FStringSpecExpr)); self->vt = &Vt; self->line = line; self->child = child; @@ -263,8 +257,7 @@ void RawStringExpr__emit_(Expr* self_, Ctx* ctx) { RawStringExpr* RawStringExpr__new(int line, c11_sv value, Opcode opcode) { const static ExprVt Vt = {.emit_ = RawStringExpr__emit_}; - static_assert_expr_size(RawStringExpr); - RawStringExpr* self = PoolExpr_alloc(); + RawStringExpr* self = PK_MALLOC(sizeof(RawStringExpr)); self->vt = &Vt; self->line = line; self->value = value; @@ -288,8 +281,7 @@ void ImagExpr__emit_(Expr* self_, Ctx* ctx) { ImagExpr* ImagExpr__new(int line, double value) { const static ExprVt Vt = {.emit_ = ImagExpr__emit_}; - static_assert_expr_size(ImagExpr); - ImagExpr* self = PoolExpr_alloc(); + ImagExpr* self = PK_MALLOC(sizeof(ImagExpr)); self->vt = &Vt; self->line = line; self->value = value; @@ -333,8 +325,7 @@ void LiteralExpr__emit_(Expr* self_, Ctx* ctx) { LiteralExpr* LiteralExpr__new(int line, const TokenValue* value) { const static ExprVt Vt = {.emit_ = LiteralExpr__emit_, .is_literal = true}; - static_assert_expr_size(LiteralExpr); - LiteralExpr* self = PoolExpr_alloc(); + LiteralExpr* self = PK_MALLOC(sizeof(LiteralExpr)); self->vt = &Vt; self->line = line; self->value = value; @@ -362,8 +353,7 @@ void Literal0Expr__emit_(Expr* self_, Ctx* ctx) { Literal0Expr* Literal0Expr__new(int line, TokenIndex token) { const static ExprVt Vt = {.emit_ = Literal0Expr__emit_}; - static_assert_expr_size(Literal0Expr); - Literal0Expr* self = PoolExpr_alloc(); + Literal0Expr* self = PK_MALLOC(sizeof(Literal0Expr)); self->vt = &Vt; self->line = line; self->token = token; @@ -403,8 +393,7 @@ void SliceExpr__emit_(Expr* self_, Ctx* ctx) { SliceExpr* SliceExpr__new(int line) { const static ExprVt Vt = {.dtor = SliceExpr__dtor, .emit_ = SliceExpr__emit_}; - static_assert_expr_size(SliceExpr); - SliceExpr* self = PoolExpr_alloc(); + SliceExpr* self = PK_MALLOC(sizeof(SliceExpr)); self->vt = &Vt; self->line = line; self->start = NULL; @@ -433,8 +422,7 @@ static void DictItemExpr__emit_(Expr* self_, Ctx* ctx) { static DictItemExpr* DictItemExpr__new(int line) { const static ExprVt Vt = {.dtor = DictItemExpr__dtor, .emit_ = DictItemExpr__emit_}; - static_assert_expr_size(DictItemExpr); - DictItemExpr* self = PoolExpr_alloc(); + DictItemExpr* self = PK_MALLOC(sizeof(DictItemExpr)); self->vt = &Vt; self->line = line; self->key = NULL; @@ -521,8 +509,7 @@ bool TupleExpr__emit_del(Expr* self_, Ctx* ctx) { } static SequenceExpr* SequenceExpr__new(int line, const ExprVt* vt, int count, Opcode opcode) { - static_assert_expr_size(SequenceExpr); - SequenceExpr* self = PoolExpr_alloc(); + SequenceExpr* self = PK_MALLOC(sizeof(SequenceExpr)); self->vt = vt; self->line = line; self->opcode = opcode; @@ -608,8 +595,7 @@ void CompExpr__emit_(Expr* self_, Ctx* ctx) { CompExpr* CompExpr__new(int line, Opcode op0, Opcode op1) { const static ExprVt Vt = {.dtor = CompExpr__dtor, .emit_ = CompExpr__emit_}; - static_assert_expr_size(CompExpr); - CompExpr* self = PoolExpr_alloc(); + CompExpr* self = PK_MALLOC(sizeof(CompExpr)); self->vt = &Vt; self->line = line; self->op0 = op0; @@ -633,8 +619,7 @@ static void LambdaExpr__emit_(Expr* self_, Ctx* ctx) { LambdaExpr* LambdaExpr__new(int line, int index) { const static ExprVt Vt = {.emit_ = LambdaExpr__emit_}; - static_assert_expr_size(LambdaExpr); - LambdaExpr* self = PoolExpr_alloc(); + LambdaExpr* self = PK_MALLOC(sizeof(LambdaExpr)); self->vt = &Vt; self->line = line; self->index = index; @@ -665,8 +650,7 @@ void LogicBinaryExpr__emit_(Expr* self_, Ctx* ctx) { LogicBinaryExpr* LogicBinaryExpr__new(int line, Opcode opcode) { const static ExprVt Vt = {.emit_ = LogicBinaryExpr__emit_, .dtor = LogicBinaryExpr__dtor}; - static_assert_expr_size(LogicBinaryExpr); - LogicBinaryExpr* self = PoolExpr_alloc(); + LogicBinaryExpr* self = PK_MALLOC(sizeof(LogicBinaryExpr)); self->vt = &Vt; self->line = line; self->lhs = NULL; @@ -705,8 +689,7 @@ GroupedExpr* GroupedExpr__new(int line, Expr* child) { .emit_ = GroupedExpr__emit_, .emit_del = GroupedExpr__emit_del, .emit_store = GroupedExpr__emit_store}; - static_assert_expr_size(GroupedExpr); - GroupedExpr* self = PoolExpr_alloc(); + GroupedExpr* self = PK_MALLOC(sizeof(GroupedExpr)); self->vt = &Vt; self->line = line; self->child = child; @@ -833,8 +816,7 @@ BinaryExpr* BinaryExpr__new(int line, TokenIndex op, bool inplace) { const static ExprVt Vt = {.emit_ = BinaryExpr__emit_, .dtor = BinaryExpr__dtor, .is_binary = true}; - static_assert_expr_size(BinaryExpr); - BinaryExpr* self = PoolExpr_alloc(); + BinaryExpr* self = PK_MALLOC(sizeof(BinaryExpr)); self->vt = &Vt; self->line = line; self->lhs = NULL; @@ -871,8 +853,7 @@ void TernaryExpr__emit_(Expr* self_, Ctx* ctx) { TernaryExpr* TernaryExpr__new(int line) { const static ExprVt Vt = {.dtor = TernaryExpr__dtor, .emit_ = TernaryExpr__emit_}; - static_assert_expr_size(TernaryExpr); - TernaryExpr* self = PoolExpr_alloc(); + TernaryExpr* self = PK_MALLOC(sizeof(TernaryExpr)); self->vt = &Vt; self->line = line; self->cond = NULL; @@ -942,8 +923,7 @@ SubscrExpr* SubscrExpr__new(int line) { .emit_del = SubscrExpr__emit_del, .is_subscr = true, }; - static_assert_expr_size(SubscrExpr); - SubscrExpr* self = PoolExpr_alloc(); + SubscrExpr* self = PK_MALLOC(sizeof(SubscrExpr)); self->vt = &Vt; self->line = line; self->lhs = NULL; @@ -1005,8 +985,7 @@ AttribExpr* AttribExpr__new(int line, Expr* child, py_Name name) { .emit_istore = AttribExpr__emit_istore, .dtor = AttribExpr__dtor, .is_attrib = true}; - static_assert_expr_size(AttribExpr); - AttribExpr* self = PoolExpr_alloc(); + AttribExpr* self = PK_MALLOC(sizeof(AttribExpr)); self->vt = &Vt; self->line = line; self->child = child; @@ -1078,8 +1057,7 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) { CallExpr* CallExpr__new(int line, Expr* callable) { const static ExprVt Vt = {.dtor = CallExpr__dtor, .emit_ = CallExpr__emit_}; - static_assert_expr_size(CallExpr); - CallExpr* self = PoolExpr_alloc(); + CallExpr* self = PK_MALLOC(sizeof(CallExpr)); self->vt = &Vt; self->line = line; self->callable = callable; diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index cd6e417c..64c7e5ee 100644 --- a/src/interpreter/frame.c +++ b/src/interpreter/frame.c @@ -1,4 +1,5 @@ #include "pocketpy/interpreter/frame.h" +#include "pocketpy/common/memorypool.h" #include "pocketpy/interpreter/vm.h" #include "pocketpy/objects/base.h" #include "pocketpy/objects/codeobject.h" @@ -42,8 +43,7 @@ Frame* Frame__new(const CodeObject* co, py_StackRef p0, py_StackRef locals, bool has_function) { - static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)"); - Frame* self = PoolFrame_alloc(); + Frame* self = FixedMemoryPool__alloc(&pk_current_vm->pool_frame); self->f_back = NULL; self->ip = (Bytecode*)co->codes.data - 1; self->co = co; @@ -62,7 +62,7 @@ void Frame__delete(Frame* self) { self->uw_list = p->next; UnwindTarget__delete(p); } - PoolFrame_dealloc(self); + FixedMemoryPool__dealloc(&pk_current_vm->pool_frame, self); } int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) { diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 1d77862e..9275533d 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -1,4 +1,5 @@ #include "pocketpy/interpreter/vm.h" +#include "pocketpy/common/memorypool.h" #include "pocketpy/common/sstream.h" #include "pocketpy/common/utils.h" #include "pocketpy/interpreter/generator.h" @@ -75,6 +76,8 @@ void VM__ctor(VM* self) { self->__curr_class = NULL; self->__curr_function = NULL; + FixedMemoryPool__ctor(&self->pool_frame, sizeof(Frame), 32); + ManagedHeap__ctor(&self->heap); ValueStack__ctor(&self->stack); @@ -246,6 +249,7 @@ void VM__dtor(VM* self) { VM__pop_frame(self); ModuleDict__dtor(&self->modules); TypeList__dtor(&self->types); + FixedMemoryPool__dtor(&self->pool_frame); ValueStack__clear(&self->stack); } diff --git a/src/public/internal.c b/src/public/internal.c index 3e74eccd..5aa94d1e 100644 --- a/src/public/internal.c +++ b/src/public/internal.c @@ -27,7 +27,6 @@ void py_initialize() { static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16"); static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4"); - MemoryPools__initialize(); py_Name__initialize(); pk_current_vm = pk_all_vm[0] = &pk_default_vm; @@ -63,7 +62,6 @@ void py_finalize() { VM__dtor(&pk_default_vm); pk_current_vm = NULL; py_Name__finalize(); - MemoryPools__finalize(); } void py_switchvm(int index) { From 7233cff311d594324001f04173f7c198dde20d93 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 23 Jan 2025 13:20:29 +0800 Subject: [PATCH 3/8] add `getchar` to `py_Callbacks` --- include/pocketpy/pocketpy.h | 2 ++ src/common/sstream.c | 42 ------------------------------------ src/interpreter/vm.c | 43 +++++++++++++++++++++++++++++++++++++ src/public/modules.c | 3 ++- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index d66ba6d4..fff7920e 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -40,6 +40,8 @@ typedef struct py_Callbacks { char* (*importfile)(const char*); /// Used by `print` to output a string. void (*print)(const char*); + /// Used by `input` to get a character. + int (*getchar)(); } py_Callbacks; #define PY_RAISE diff --git a/src/common/sstream.c b/src/common/sstream.c index eaab46fb..5c57d9bd 100644 --- a/src/common/sstream.c +++ b/src/common/sstream.c @@ -244,45 +244,3 @@ void pk_sprintf(c11_sbuf* ss, const char* fmt, ...) { pk_vsprintf(ss, fmt, args); va_end(args); } - -int py_replinput(char* buf, int max_size) { - buf[0] = '\0'; // reset first char because we check '@' at the beginning - - int size = 0; - bool multiline = false; - printf(">>> "); - - while(true) { - int c = getchar(); - if(c == EOF) return -1; - - if(c == '\n') { - char last = '\0'; - if(size > 0) last = buf[size - 1]; - if(multiline) { - if(last == '\n') { - break; // 2 consecutive newlines to end multiline input - } else { - printf("... "); - } - } else { - if(last == ':' || last == '(' || last == '[' || last == '{' || buf[0] == '@') { - printf("... "); - multiline = true; - } else { - break; - } - } - } - - if(size == max_size - 1) { - buf[size] = '\0'; - return size; - } - - buf[size++] = c; - } - - buf[size] = '\0'; - return size; -} \ No newline at end of file diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 9275533d..986baf86 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -66,6 +66,7 @@ void VM__ctor(VM* self) { self->callbacks.importfile = pk_default_importfile; self->callbacks.print = pk_default_print; + self->callbacks.getchar = getchar; self->last_retval = *py_NIL(); self->curr_exception = *py_NIL(); @@ -748,3 +749,45 @@ bool pk_wrapper__NotImplementedError(int argc, py_Ref argv) { } py_TypeInfo* pk__type_info(py_Type type) { return TypeList__get(&pk_current_vm->types, type); } + +int py_replinput(char* buf, int max_size) { + buf[0] = '\0'; // reset first char because we check '@' at the beginning + + int size = 0; + bool multiline = false; + printf(">>> "); + + while(true) { + int c = pk_current_vm->callbacks.getchar(); + if(c == EOF) return -1; + + if(c == '\n') { + char last = '\0'; + if(size > 0) last = buf[size - 1]; + if(multiline) { + if(last == '\n') { + break; // 2 consecutive newlines to end multiline input + } else { + printf("... "); + } + } else { + if(last == ':' || last == '(' || last == '[' || last == '{' || buf[0] == '@') { + printf("... "); + multiline = true; + } else { + break; + } + } + } + + if(size == max_size - 1) { + buf[size] = '\0'; + return size; + } + + buf[size++] = c; + } + + buf[size] = '\0'; + return size; +} \ No newline at end of file diff --git a/src/public/modules.c b/src/public/modules.c index c4b35297..ec832d9d 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -1,4 +1,5 @@ #include "pocketpy/common/str.h" +#include "pocketpy/objects/base.h" #include "pocketpy/objects/codeobject.h" #include "pocketpy/pocketpy.h" #include "pocketpy/common/utils.h" @@ -208,7 +209,7 @@ static bool builtins_input(int argc, py_Ref argv) { c11_sbuf buf; c11_sbuf__ctor(&buf); while(true) { - int c = getchar(); + int c = pk_current_vm->callbacks.getchar(); if(c == '\n') break; if(c == EOF) break; c11_sbuf__write_char(&buf, c); From adceacc0f5a15bef86e2203bc546ea3f75217267 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 23 Jan 2025 14:00:51 +0800 Subject: [PATCH 4/8] ... --- include/pocketpy/interpreter/objectpool.h | 4 +- include/pocketpy/interpreter/vm.h | 1 - include/pocketpy/objects/namedict.h | 1 + src/interpreter/heap.c | 1 + src/interpreter/objectpool.c | 68 ++++++++++++----------- src/interpreter/vm.c | 8 +-- src/objects/namedict.c | 8 ++- 7 files changed, 50 insertions(+), 41 deletions(-) diff --git a/include/pocketpy/interpreter/objectpool.h b/include/pocketpy/interpreter/objectpool.h index 51d06d49..751c4975 100644 --- a/include/pocketpy/interpreter/objectpool.h +++ b/include/pocketpy/interpreter/objectpool.h @@ -9,14 +9,14 @@ typedef struct PoolArena { int block_size; int block_count; - int unused_count; + int unused_length; int* unused; char data[kPoolArenaSize]; } PoolArena; typedef struct Pool { c11_vector /* PoolArena* */ arenas; - c11_vector /* PoolArena* */ not_free_arenas; + c11_vector /* PoolArena* */ no_free_arenas; int block_size; } Pool; diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 77df406c..ddd2da90 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -60,7 +60,6 @@ bool pk__object_new(int argc, py_Ref argv); py_TypeInfo* pk__type_info(py_Type type); bool pk_wrapper__self(int argc, py_Ref argv); -bool pk_wrapper__NotImplementedError(int argc, py_Ref argv); const char* pk_op2str(py_Name op); diff --git a/include/pocketpy/objects/namedict.h b/include/pocketpy/objects/namedict.h index c74e6ebf..92debe8c 100644 --- a/include/pocketpy/objects/namedict.h +++ b/include/pocketpy/objects/namedict.h @@ -25,3 +25,4 @@ void ModuleDict__dtor(ModuleDict* self); void ModuleDict__set(ModuleDict* self, const char* key, py_TValue val); py_TValue* ModuleDict__try_get(ModuleDict* self, const char* path); bool ModuleDict__contains(ModuleDict* self, const char* path); +void ModuleDict__apply_mark(ModuleDict* self, void (*marker)(PyObject*)); diff --git a/src/interpreter/heap.c b/src/interpreter/heap.c index 952a1455..b2d1b6c5 100644 --- a/src/interpreter/heap.c +++ b/src/interpreter/heap.c @@ -81,6 +81,7 @@ PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int uds int size = sizeof(PyObject) + PK_OBJ_SLOTS_SIZE(slots) + udsize; if(!PK_LOW_MEMORY_MODE && size <= kPoolMaxBlockSize) { obj = MultiPool__alloc(&self->small_objects, size); + assert(obj != NULL); } else { obj = PK_MALLOC(size); c11_vector__push(PyObject*, &self->large_objects, obj); diff --git a/src/interpreter/objectpool.c b/src/interpreter/objectpool.c index 34def166..3c49a529 100644 --- a/src/interpreter/objectpool.c +++ b/src/interpreter/objectpool.c @@ -11,11 +11,10 @@ static PoolArena* PoolArena__new(int block_size) { assert(kPoolArenaSize % block_size == 0); int block_count = kPoolArenaSize / block_size; - int total_size = sizeof(PoolArena) + sizeof(int) * block_count; - PoolArena* self = PK_MALLOC(total_size); + PoolArena* self = PK_MALLOC(sizeof(PoolArena) + sizeof(int) * block_count); self->block_size = block_size; self->block_count = block_count; - self->unused_count = block_count; + self->unused_length = block_count; self->unused = PK_MALLOC(sizeof(int) * block_count); for(int i = 0; i < block_count; i++) { self->unused[i] = i; @@ -34,27 +33,30 @@ static void PoolArena__delete(PoolArena* self) { } static void* PoolArena__alloc(PoolArena* self) { - assert(self->unused_count > 0); - int index = self->unused[self->unused_count - 1]; - self->unused_count--; + assert(self->unused_length > 0); + int index = self->unused[self->unused_length - 1]; + self->unused_length--; return self->data + index * self->block_size; } static int PoolArena__sweep_dealloc(PoolArena* self) { int freed = 0; - self->unused_count = 0; + self->unused_length = 0; for(int i = 0; i < self->block_count; i++) { PyObject* obj = (PyObject*)(self->data + i * self->block_size); if(obj->type == 0) { - self->unused[self->unused_count] = i; - self->unused_count++; + // free slot + self->unused[self->unused_length] = i; + self->unused_length++; } else { if(!obj->gc_marked) { + // not marked, need to free obj->type = 0; freed++; - self->unused[self->unused_count] = i; - self->unused_count++; + self->unused[self->unused_length] = i; + self->unused_length++; } else { + // marked, clear mark obj->gc_marked = false; } } @@ -64,15 +66,15 @@ static int PoolArena__sweep_dealloc(PoolArena* self) { static void Pool__ctor(Pool* self, int block_size) { c11_vector__ctor(&self->arenas, sizeof(PoolArena*)); - c11_vector__ctor(&self->not_free_arenas, sizeof(PoolArena*)); + c11_vector__ctor(&self->no_free_arenas, sizeof(PoolArena*)); self->block_size = block_size; } static void Pool__dtor(Pool* self) { - c11__foreach(PoolArena*, &self->arenas, arena) { PoolArena__delete(*arena); } - c11__foreach(PoolArena*, &self->not_free_arenas, arena) { PoolArena__delete(*arena); } + c11__foreach(PoolArena*, &self->arenas, arena) PoolArena__delete(*arena); + c11__foreach(PoolArena*, &self->no_free_arenas, arena) PoolArena__delete(*arena); c11_vector__dtor(&self->arenas); - c11_vector__dtor(&self->not_free_arenas); + c11_vector__dtor(&self->no_free_arenas); } static void* Pool__alloc(Pool* self) { @@ -84,25 +86,25 @@ static void* Pool__alloc(Pool* self) { arena = c11_vector__back(PoolArena*, &self->arenas); } void* ptr = PoolArena__alloc(arena); - if(arena->unused_count == 0) { + if(arena->unused_length == 0) { c11_vector__pop(&self->arenas); - c11_vector__push(PoolArena*, &self->not_free_arenas, arena); + c11_vector__push(PoolArena*, &self->no_free_arenas, arena); } return ptr; } -static int Pool__sweep_dealloc(Pool* self, c11_vector* arenas, c11_vector* not_free_arenas) { +static int Pool__sweep_dealloc(Pool* self, c11_vector* arenas, c11_vector* no_free_arenas) { c11_vector__clear(arenas); - c11_vector__clear(not_free_arenas); + c11_vector__clear(no_free_arenas); int freed = 0; for(int i = 0; i < self->arenas.length; i++) { PoolArena* item = c11__getitem(PoolArena*, &self->arenas, i); - assert(item->unused_count > 0); + assert(item->unused_length > 0); freed += PoolArena__sweep_dealloc(item); - if(item->unused_count == item->block_count) { + if(item->unused_length == item->block_count) { // all free - if(self->arenas.length > 0) { + if(arenas->length > 0) { // at least one arena PoolArena__delete(item); } else { @@ -114,14 +116,14 @@ static int Pool__sweep_dealloc(Pool* self, c11_vector* arenas, c11_vector* not_f c11_vector__push(PoolArena*, arenas, item); } } - for(int i = 0; i < self->not_free_arenas.length; i++) { - PoolArena* item = c11__getitem(PoolArena*, &self->not_free_arenas, i); + 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); - if(item->unused_count == 0) { - // still not free - c11_vector__push(PoolArena*, not_free_arenas, item); + if(item->unused_length == 0) { + // still no free + c11_vector__push(PoolArena*, no_free_arenas, item); } else { - if(item->unused_count == item->block_count) { + if(item->unused_length == item->block_count) { // all free PoolArena__delete(item); } else { @@ -132,7 +134,7 @@ static int Pool__sweep_dealloc(Pool* self, c11_vector* arenas, c11_vector* not_f } c11_vector__swap(&self->arenas, arenas); - c11_vector__swap(&self->not_free_arenas, not_free_arenas); + c11_vector__swap(&self->no_free_arenas, no_free_arenas); return freed; } @@ -148,16 +150,16 @@ void* MultiPool__alloc(MultiPool* self, int size) { int MultiPool__sweep_dealloc(MultiPool* self) { c11_vector arenas; - c11_vector not_free_arenas; + c11_vector no_free_arenas; c11_vector__ctor(&arenas, sizeof(PoolArena*)); - c11_vector__ctor(¬_free_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, ¬_free_arenas); + freed += Pool__sweep_dealloc(item, &arenas, &no_free_arenas); } c11_vector__dtor(&arenas); - c11_vector__dtor(¬_free_arenas); + c11_vector__dtor(&no_free_arenas); return freed; } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 986baf86..4a635acd 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -645,11 +645,15 @@ void ManagedHeap__mark(ManagedHeap* self) { for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) { pk__mark_value(p); } + // mark modules + ModuleDict__apply_mark(&vm->modules, mark_object); // mark types int types_length = vm->types.length; // 0-th type is placeholder for(py_Type i = 1; i < types_length; i++) { py_TypeInfo* ti = TypeList__get(&vm->types, i); + // mark type object + pk__mark_value(&ti->self); // mark common magic slots for(int j = 0; j < PK_MAGIC_SLOTS_COMMON_LENGTH; j++) { py_TValue* slot = ti->magic_0 + j; @@ -744,10 +748,6 @@ bool pk_wrapper__self(int argc, py_Ref argv) { return true; } -bool pk_wrapper__NotImplementedError(int argc, py_Ref argv) { - return py_exception(tp_NotImplementedError, ""); -} - py_TypeInfo* pk__type_info(py_Type type) { return TypeList__get(&pk_current_vm->types, type); } int py_replinput(char* buf, int max_size) { diff --git a/src/objects/namedict.c b/src/objects/namedict.c index 5ece63cf..922f245a 100644 --- a/src/objects/namedict.c +++ b/src/objects/namedict.c @@ -72,4 +72,10 @@ py_TValue* ModuleDict__try_get(ModuleDict* self, const char* path) { bool ModuleDict__contains(ModuleDict* self, const char* path) { return ModuleDict__try_get(self, path) != NULL; -} \ No newline at end of file +} + +void ModuleDict__apply_mark(ModuleDict *self, void (*marker)(PyObject*)) { + if(self->left) ModuleDict__apply_mark(self->left, marker); + if(self->right) ModuleDict__apply_mark(self->right, marker); + marker(self->module._obj); +} From a9ead56505d41cfdd87f050a6d0f7cf038de436d Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 23 Jan 2025 14:35:40 +0800 Subject: [PATCH 5/8] ... --- include/pocketpy/interpreter/objectpool.h | 2 ++ src/interpreter/objectpool.c | 32 ++++++++++++++++++++++- src/modules/pkpy.c | 22 ++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/include/pocketpy/interpreter/objectpool.h b/include/pocketpy/interpreter/objectpool.h index 751c4975..c9700583 100644 --- a/include/pocketpy/interpreter/objectpool.h +++ b/include/pocketpy/interpreter/objectpool.h @@ -1,6 +1,7 @@ #pragma once #include "pocketpy/common/vector.h" +#include "pocketpy/common/str.h" #define kPoolArenaSize (120 * 1024) #define kMultiPoolCount 5 @@ -28,3 +29,4 @@ void* MultiPool__alloc(MultiPool* self, int size); int MultiPool__sweep_dealloc(MultiPool* self); void MultiPool__ctor(MultiPool* self); void MultiPool__dtor(MultiPool* self); +c11_string* MultiPool__summary(MultiPool* self); \ No newline at end of file diff --git a/src/interpreter/objectpool.c b/src/interpreter/objectpool.c index 3c49a529..686ca5b7 100644 --- a/src/interpreter/objectpool.c +++ b/src/interpreter/objectpool.c @@ -2,6 +2,7 @@ #include "pocketpy/config.h" #include "pocketpy/objects/object.h" +#include "pocketpy/common/sstream.h" #include #include @@ -173,4 +174,33 @@ void MultiPool__dtor(MultiPool* self) { for(int i = 0; i < kMultiPoolCount; i++) { Pool__dtor(&self->pools[i]); } -} \ No newline at end of file +} + +c11_string* MultiPool__summary(MultiPool* self) { + c11_sbuf sbuf; + c11_sbuf__ctor(&sbuf); + for(int i = 0; i < kMultiPoolCount; i++) { + Pool* item = &self->pools[i]; + int total_bytes = (item->arenas.length + item->no_free_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; + char buf[256]; + snprintf(buf, + sizeof(buf), + "Pool<%d>: len(arenas)=%d, len(no_free_arenas)=%d, %d/%d (%.1f%% used)", + item->block_size, + item->arenas.length, + item->no_free_arenas.length, + used_bytes, + total_bytes, + used_pct); + c11_sbuf__write_cstr(&sbuf, buf); + c11_sbuf__write_char(&sbuf, '\n'); + } + return c11_sbuf__submit(&sbuf); +} diff --git a/src/modules/pkpy.c b/src/modules/pkpy.c index 4706c564..bc58b19c 100644 --- a/src/modules/pkpy.c +++ b/src/modules/pkpy.c @@ -1,3 +1,5 @@ +#include "pocketpy/interpreter/objectpool.h" +#include "pocketpy/objects/base.h" #include "pocketpy/pocketpy.h" #include "pocketpy/common/utils.h" @@ -33,6 +35,24 @@ DEF_TVALUE_METHODS(float, _f64) DEF_TVALUE_METHODS(vec2, _vec2) DEF_TVALUE_METHODS(vec2i, _vec2i) +static bool pkpy_memory_usage(int argc, py_Ref argv) { + PY_CHECK_ARGC(0); + ManagedHeap* heap = &pk_current_vm->heap; + c11_string* small_objects_usage = MultiPool__summary(&heap->small_objects); + int large_object_count = heap->large_objects.length; + c11_sbuf buf; + c11_sbuf__ctor(&buf); + c11_sbuf__write_cstr(&buf, "== heap.small_objects ==\n"); + c11_sbuf__write_cstr(&buf, small_objects_usage->data); + c11_sbuf__write_cstr(&buf, "== heap.large_objects ==\n"); + c11_sbuf__write_cstr(&buf, "len(large_objects)=\n"); + c11_sbuf__write_int(&buf, large_object_count); + // c11_sbuf__write_cstr(&buf, "== vm.pool_frame ==\n"); + c11_sbuf__py_submit(&buf, py_retval()); + c11_string__delete(small_objects_usage); + return true; +} + void pk__add_module_pkpy() { py_Ref mod = py_newmodule("pkpy"); @@ -66,6 +86,8 @@ void pk__add_module_pkpy() { py_setdict(mod, py_name("TValue"), TValue_dict); py_pop(); + + py_bindfunc(mod, "memory_usage", pkpy_memory_usage); } #undef DEF_TVALUE_METHODS \ No newline at end of file From d5ce8d12e45e5be9a567cfe2d693734140096f95 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 23 Jan 2025 14:48:09 +0800 Subject: [PATCH 6/8] Update pkpy.c --- src/modules/pkpy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/pkpy.c b/src/modules/pkpy.c index bc58b19c..dafef142 100644 --- a/src/modules/pkpy.c +++ b/src/modules/pkpy.c @@ -45,7 +45,7 @@ static bool pkpy_memory_usage(int argc, py_Ref argv) { c11_sbuf__write_cstr(&buf, "== heap.small_objects ==\n"); c11_sbuf__write_cstr(&buf, small_objects_usage->data); c11_sbuf__write_cstr(&buf, "== heap.large_objects ==\n"); - c11_sbuf__write_cstr(&buf, "len(large_objects)=\n"); + c11_sbuf__write_cstr(&buf, "len(large_objects)="); c11_sbuf__write_int(&buf, large_object_count); // c11_sbuf__write_cstr(&buf, "== vm.pool_frame ==\n"); c11_sbuf__py_submit(&buf, py_retval()); From f38bf0a2b923089b751f6a88cf079b44d70798e9 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 23 Jan 2025 14:49:29 +0800 Subject: [PATCH 7/8] Update pkpy.pyi --- include/typings/pkpy.pyi | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/typings/pkpy.pyi b/include/typings/pkpy.pyi index e315dd6d..24fd6c61 100644 --- a/include/typings/pkpy.pyi +++ b/include/typings/pkpy.pyi @@ -7,7 +7,10 @@ class TValue[T]: @property def value(self) -> T: ... -# TValue_int = TValue[int] -# TValue_float = TValue[float] -# TValue_vec2i = TValue[vec2i] -# TValue_vec2 = TValue[vec2] +TValue_int = TValue[int] +TValue_float = TValue[float] +TValue_vec2i = TValue[vec2i] +TValue_vec2 = TValue[vec2] + +def memory_usage() -> str: + """Return a summary of the memory usage.""" From 181a9465d62f319b428ccca8ac2b77c18f1f431a Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 23 Jan 2025 14:50:36 +0800 Subject: [PATCH 8/8] Update pkpy.pyi --- include/typings/pkpy.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/typings/pkpy.pyi b/include/typings/pkpy.pyi index 24fd6c61..e6837216 100644 --- a/include/typings/pkpy.pyi +++ b/include/typings/pkpy.pyi @@ -7,10 +7,10 @@ class TValue[T]: @property def value(self) -> T: ... -TValue_int = TValue[int] -TValue_float = TValue[float] -TValue_vec2i = TValue[vec2i] -TValue_vec2 = TValue[vec2] +# TValue_int = TValue[int] +# TValue_float = TValue[float] +# TValue_vec2i = TValue[vec2i] +# TValue_vec2 = TValue[vec2] def memory_usage() -> str: """Return a summary of the memory usage."""