[no ci] backup

This commit is contained in:
张皓晟 2025-11-23 15:26:02 +08:00
parent 6e2e9706dd
commit af823da627
6 changed files with 128 additions and 18 deletions

View File

@ -13,19 +13,22 @@ typedef struct ManagedHeap {
int gc_threshold; // threshold for gc_counter
int gc_counter; // objects created since last gc
bool gc_enabled;
py_Ref debug_callback;
} ManagedHeap;
typedef struct {
clock_t start;
clock_t end;
clock_t mark_end;
clock_t swpet_end;
int types_length;
int* small_types;
int* large_types;
int small_freed;
int large_freed;
struct {
bool valid;
int before;
int after;
int upper;
@ -38,11 +41,11 @@ typedef struct {
void ManagedHeap__ctor(ManagedHeap* self);
void ManagedHeap__dtor(ManagedHeap* self);
void ManagedHeapSwpetInfo__ctor(ManagedHeapSwpetInfo* self);
void ManagedHeapSwpetInfo__dtor(ManagedHeapSwpetInfo* self);
ManagedHeapSwpetInfo* ManagedHeapSwpetInfo__new();
void ManagedHeapSwpetInfo__delete(ManagedHeapSwpetInfo* self);
void ManagedHeap__collect_if_needed(ManagedHeap* self, ManagedHeapSwpetInfo* out_info);
int ManagedHeap__collect(ManagedHeap* self, ManagedHeapSwpetInfo* out_info);
void ManagedHeap__collect_if_needed(ManagedHeap* self);
int ManagedHeap__collect(ManagedHeap* self);
int ManagedHeap__sweep(ManagedHeap* self, ManagedHeapSwpetInfo* out_info);
#define ManagedHeap__new(self, type, slots, udsize) \

View File

@ -1,4 +1,4 @@
from typing import Self, Literal
from typing import Self, Literal, Callable
from vmath import vec2, vec2i
class TValue[T]:
@ -16,6 +16,8 @@ configmacros: dict[str, int]
def memory_usage() -> str:
"""Return a summary of the memory usage."""
def setup_gc_debug_callback(cb: Callable[[str], None]) -> None:
"""Setup a callback that will be triggered at the end of GC."""
def is_user_defined_type(t: type) -> bool:
"""Check if a type is user-defined. This means the type was created by executing python `class` statement."""

View File

@ -2,6 +2,7 @@
#include "pocketpy/config.h"
#include "pocketpy/interpreter/objectpool.h"
#include "pocketpy/objects/base.h"
#include "pocketpy/common/sstream.h"
#include "pocketpy/pocketpy.h"
#include <assert.h>
@ -16,6 +17,7 @@ void ManagedHeap__ctor(ManagedHeap* self) {
self->gc_threshold = PK_GC_MIN_THRESHOLD;
self->gc_counter = 0;
self->gc_enabled = true;
self->debug_callback = NULL;
}
void ManagedHeap__dtor(ManagedHeap* self) {
@ -31,10 +33,76 @@ void ManagedHeap__dtor(ManagedHeap* self) {
c11_vector__dtor(&self->gc_roots);
}
void ManagedHeap__collect_if_needed(ManagedHeap* self, ManagedHeapSwpetInfo* out_info) {
static void ManagedHeap__fire_debug_callback(ManagedHeap* self, ManagedHeapSwpetInfo* out_info) {
assert(self->debug_callback != NULL);
assert(out_info != NULL);
c11_sbuf buf;
c11_sbuf__ctor(&buf);
const clock_t CLOCKS_PER_MS = CLOCKS_PER_SEC / 1000;
const char* DIVIDER = "------------------------------";
clock_t start = out_info->start / CLOCKS_PER_MS;
clock_t mark_ms = (out_info->mark_end - out_info->start) / CLOCKS_PER_MS;
clock_t swpet_ms = (out_info->swpet_end - out_info->mark_end) / CLOCKS_PER_MS;
c11_sbuf__write_cstr(&buf, DIVIDER);
pk_sprintf(&buf, "start: %f\n", (double)start / 1000);
pk_sprintf(&buf, "mark_ms: %i\n", (py_i64)mark_ms);
pk_sprintf(&buf, "swpet_ms: %i\n", (py_i64)swpet_ms);
pk_sprintf(&buf, "total_ms: %i\n", (py_i64)(mark_ms + swpet_ms));
c11_sbuf__write_cstr(&buf, DIVIDER);
pk_sprintf(&buf, "types_length: %d\n", out_info->types_length);
pk_sprintf(&buf, "small_freed: %d\n", out_info->small_freed);
pk_sprintf(&buf, "large_freed: %d\n", out_info->large_freed);
c11_sbuf__write_cstr(&buf, DIVIDER);
char line_buf[256];
for(int i = 0; i < out_info->types_length; i++) {
const char* type_name = py_tpname(i);
int s_freed = out_info->small_types[i];
int l_freed = out_info->large_types[i];
if(s_freed == 0 && l_freed == 0) continue;
snprintf(line_buf,
sizeof(line_buf),
"[-%24s] small: %6d large: %6d\n",
type_name,
s_freed,
l_freed);
c11_sbuf__write_cstr(&buf, line_buf);
}
c11_sbuf__write_cstr(&buf, DIVIDER);
pk_sprintf(&buf, "auto_thres.before: %d\n", out_info->auto_thres.before);
pk_sprintf(&buf, "auto_thres.after: %d\n", out_info->auto_thres.after);
pk_sprintf(&buf, "auto_thres.upper: %d\n", out_info->auto_thres.upper);
pk_sprintf(&buf, "auto_thres.lower: %d\n", out_info->auto_thres.lower);
pk_sprintf(&buf, "auto_thres.avg_freed: %d\n", out_info->auto_thres.avg_freed);
pk_sprintf(&buf, "auto_thres.free_ratio: %f\n", out_info->auto_thres.free_ratio);
c11_sbuf__write_cstr(&buf, DIVIDER);
py_Ref p0 = py_peek(0);
py_push(self->debug_callback);
py_pushnil();
py_StackRef arg = py_pushtmp();
c11_sbuf__py_submit(&buf, arg);
bool ok = py_vectorcall(1, 0);
if(!ok) py_clearexc(p0); // noexcept
}
void ManagedHeap__collect_if_needed(ManagedHeap* self) {
if(!self->gc_enabled) return;
if(self->gc_counter < self->gc_threshold) return;
int freed = ManagedHeap__collect(self, out_info);
self->gc_counter = 0;
ManagedHeapSwpetInfo* out_info = NULL;
if(self->debug_callback) out_info = ManagedHeapSwpetInfo__new();
ManagedHeap__mark(self);
if(out_info) out_info->mark_end = clock();
int freed = ManagedHeap__sweep(self, out_info);
if(out_info) out_info->swpet_end = clock();
// adjust `gc_threshold` based on `freed_ma`
self->freed_ma[0] = self->freed_ma[1];
self->freed_ma[1] = self->freed_ma[2];
@ -45,7 +113,6 @@ void ManagedHeap__collect_if_needed(ManagedHeap* self, ManagedHeapSwpetInfo* out
float free_ratio = (float)avg_freed / self->gc_threshold;
int new_threshold = self->gc_threshold * (1.5f / free_ratio);
if(out_info) {
out_info->auto_thres.valid = true;
out_info->auto_thres.before = self->gc_threshold;
out_info->auto_thres.after = new_threshold;
out_info->auto_thres.upper = upper;
@ -54,12 +121,29 @@ void ManagedHeap__collect_if_needed(ManagedHeap* self, ManagedHeapSwpetInfo* out
out_info->auto_thres.free_ratio = free_ratio;
}
self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper);
if(self->debug_callback) {
ManagedHeap__fire_debug_callback(self, out_info);
ManagedHeapSwpetInfo__delete(out_info);
}
}
int ManagedHeap__collect(ManagedHeap* self, ManagedHeapSwpetInfo* out_info) {
int ManagedHeap__collect(ManagedHeap* self) {
self->gc_counter = 0;
ManagedHeapSwpetInfo* out_info = NULL;
if(self->debug_callback) out_info = ManagedHeapSwpetInfo__new();
ManagedHeap__mark(self);
return ManagedHeap__sweep(self, out_info);
if(out_info) out_info->mark_end = clock();
int freed = ManagedHeap__sweep(self, out_info);
if(out_info) out_info->swpet_end = clock();
if(self->debug_callback) {
ManagedHeap__fire_debug_callback(self, out_info);
ManagedHeapSwpetInfo__delete(out_info);
}
return freed;
}
int ManagedHeap__sweep(ManagedHeap* self, ManagedHeapSwpetInfo* out_info) {
@ -86,7 +170,6 @@ int ManagedHeap__sweep(ManagedHeap* self, ManagedHeapSwpetInfo* out_info) {
if(out_info) {
out_info->small_freed = small_freed;
out_info->large_freed = large_freed;
out_info->end = clock();
}
return small_freed + large_freed;
}

View File

@ -685,6 +685,8 @@ void ManagedHeap__mark(ManagedHeap* self) {
for(int i = 0; i < c11__count_array(vm->reg); i++) {
pk__mark_value(&vm->reg[i]);
}
// mark gc debug callback
if(vm->heap.debug_callback) pk__mark_value(vm->heap.debug_callback);
// mark user func
if(vm->callbacks.gc_mark) vm->callbacks.gc_mark(pk__mark_value_func, p_stack);
/*****************************/

View File

@ -130,15 +130,23 @@ void PyObject__dtor(PyObject* self) {
}
}
void ManagedHeapSwpetInfo__ctor(ManagedHeapSwpetInfo* self) {
ManagedHeapSwpetInfo* ManagedHeapSwpetInfo__new() {
ManagedHeapSwpetInfo* self = py_malloc(sizeof(ManagedHeapSwpetInfo));
memset(self, 0, sizeof(ManagedHeapSwpetInfo));
self->start = clock();
self->small_types = py_malloc(sizeof(int) * pk_current_vm->types.length);
self->large_types = py_malloc(sizeof(int) * pk_current_vm->types.length);
self->types_length = pk_current_vm->types.length;
self->small_types = py_malloc(sizeof(int) * self->types_length);
self->large_types = py_malloc(sizeof(int) * self->types_length);
for(int i = 0; i < self->types_length; i++) {
self->small_types[i] = 0;
self->large_types[i] = 0;
}
return self;
}
void ManagedHeapSwpetInfo__dtor(ManagedHeapSwpetInfo* self) {
void ManagedHeapSwpetInfo__delete(ManagedHeapSwpetInfo* self) {
py_free(self->small_types);
py_free(self->large_types);
memset(self, 0, sizeof(ManagedHeapSwpetInfo));
py_free(self);
}

View File

@ -57,6 +57,17 @@ static bool pkpy_memory_usage(int argc, py_Ref argv) {
return true;
}
static bool pkpy_setup_gc_debug_callback(int argc, py_Ref argv) {
PY_CHECK_ARGC(0);
ManagedHeap* heap = &pk_current_vm->heap;
if(py_isnone(argv)) {
heap->debug_callback = NULL;
} else {
heap->debug_callback = argv;
}
return true;
}
static bool pkpy_is_user_defined_type(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_type);
@ -530,6 +541,7 @@ void pk__add_module_pkpy() {
py_pop();
py_bindfunc(mod, "memory_usage", pkpy_memory_usage);
py_bindfunc(mod, "setup_gc_debug_callback", pkpy_setup_gc_debug_callback);
py_bindfunc(mod, "is_user_defined_type", pkpy_is_user_defined_type);
py_bindfunc(mod, "currentvm", pkpy_currentvm);