mirror of
https://github.com/pocketpy/pocketpy
synced 2025-12-10 12:10:16 +00:00
Compare commits
7 Commits
dc9358aee3
...
1f782b799c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f782b799c | ||
|
|
673c3e2802 | ||
|
|
272388ed8f | ||
|
|
d03610071a | ||
|
|
1d30103f6a | ||
|
|
e2c065d18d | ||
|
|
c3291ef718 |
@ -4,5 +4,5 @@
|
|||||||
-std=c11
|
-std=c11
|
||||||
-Iinclude/
|
-Iinclude/
|
||||||
-I3rd/lz4/
|
-I3rd/lz4/
|
||||||
-I3rd/cute_headers/include/
|
-I3rd/cute_png/include/
|
||||||
-I3rd/msgpack/include/
|
-I3rd/msgpack/include/
|
||||||
|
|||||||
@ -17,9 +17,9 @@ typedef struct ManagedHeap {
|
|||||||
} ManagedHeap;
|
} ManagedHeap;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
clock_t start;
|
int64_t start_ns;
|
||||||
clock_t mark_end;
|
int64_t mark_end_ns;
|
||||||
clock_t swpet_end;
|
int64_t swpet_end_ns;
|
||||||
|
|
||||||
int types_length;
|
int types_length;
|
||||||
int* small_types;
|
int* small_types;
|
||||||
|
|||||||
@ -801,6 +801,8 @@ PK_API void py_profiler_reset();
|
|||||||
PK_API char* py_profiler_report();
|
PK_API char* py_profiler_report();
|
||||||
|
|
||||||
/************* Others *************/
|
/************* Others *************/
|
||||||
|
int64_t time_ns();
|
||||||
|
int64_t time_monotonic_ns();
|
||||||
|
|
||||||
/// An utility function to read a line from stdin for REPL.
|
/// An utility function to read a line from stdin for REPL.
|
||||||
PK_API int py_replinput(char* buf, int max_size);
|
PK_API int py_replinput(char* buf, int max_size);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from typing import Callable
|
from typing import Callable, Literal
|
||||||
|
|
||||||
def isenabled() -> bool:
|
def isenabled() -> bool:
|
||||||
"""Check if automatic garbage collection is enabled."""
|
"""Check if automatic garbage collection is enabled."""
|
||||||
@ -23,5 +23,5 @@ def collect_hint() -> None:
|
|||||||
and `gc.collect_hint()` is called at the end of each frame.
|
and `gc.collect_hint()` is called at the end of each frame.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setup_debug_callback(cb: Callable[[str], None] | None) -> None:
|
def setup_debug_callback(cb: Callable[[Literal['start', 'stop'], str], None] | None) -> None:
|
||||||
"""Setup a callback that will be triggered at the end of each collection."""
|
"""Setup a callback that will be triggered at the end of each collection."""
|
||||||
|
|||||||
@ -75,8 +75,6 @@ void c11_cond__broadcast(c11_cond_t* cond) { cnd_broadcast(cond); }
|
|||||||
#define C11_THRDPOOL_DEBUG 0
|
#define C11_THRDPOOL_DEBUG 0
|
||||||
|
|
||||||
#if C11_THRDPOOL_DEBUG
|
#if C11_THRDPOOL_DEBUG
|
||||||
int64_t time_ns();
|
|
||||||
|
|
||||||
static void c11_thrdpool_debug_log(int index, const char* format, ...) {
|
static void c11_thrdpool_debug_log(int index, const char* format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|||||||
@ -33,21 +33,33 @@ void ManagedHeap__dtor(ManagedHeap* self) {
|
|||||||
c11_vector__dtor(&self->gc_roots);
|
c11_vector__dtor(&self->gc_roots);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ManagedHeap__fire_debug_callback(ManagedHeap* self, ManagedHeapSwpetInfo* out_info) {
|
static void ManagedHeap__fire_debug_callback_start(ManagedHeap* self) {
|
||||||
|
py_push(&self->debug_callback);
|
||||||
|
py_pushnil();
|
||||||
|
py_newstr(py_pushtmp(), "start");
|
||||||
|
py_newstr(py_pushtmp(), "");
|
||||||
|
bool ok = py_vectorcall(2, 0);
|
||||||
|
if(!ok) {
|
||||||
|
char* msg = py_formatexc();
|
||||||
|
c11__abort("gc_debug_callback error!!\n%s", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ManagedHeap__fire_debug_callback_stop(ManagedHeap* self,
|
||||||
|
ManagedHeapSwpetInfo* out_info) {
|
||||||
assert(out_info != NULL);
|
assert(out_info != NULL);
|
||||||
|
|
||||||
c11_sbuf buf;
|
c11_sbuf buf;
|
||||||
c11_sbuf__ctor(&buf);
|
c11_sbuf__ctor(&buf);
|
||||||
|
|
||||||
const clock_t CLOCKS_PER_MS = CLOCKS_PER_SEC / 1000;
|
const int64_t NANOS_PER_MS = 1000000000 / 1000;
|
||||||
const char* DIVIDER = "------------------------------------------------------------\n";
|
const char* DIVIDER = "------------------------------------------------------------\n";
|
||||||
|
|
||||||
clock_t start = out_info->start / CLOCKS_PER_MS;
|
int64_t mark_ms = (out_info->mark_end_ns - out_info->start_ns) / NANOS_PER_MS;
|
||||||
clock_t mark_ms = (out_info->mark_end - out_info->start) / CLOCKS_PER_MS;
|
int64_t swpet_ms = (out_info->swpet_end_ns - out_info->mark_end_ns) / NANOS_PER_MS;
|
||||||
clock_t swpet_ms = (out_info->swpet_end - out_info->mark_end) / CLOCKS_PER_MS;
|
|
||||||
|
|
||||||
c11_sbuf__write_cstr(&buf, DIVIDER);
|
c11_sbuf__write_cstr(&buf, DIVIDER);
|
||||||
pk_sprintf(&buf, "start: %f\n", (double)start / 1000);
|
pk_sprintf(&buf, "start: %f\n", out_info->start_ns / 1e9);
|
||||||
pk_sprintf(&buf, "mark_ms: %i\n", (py_i64)mark_ms);
|
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, "swpet_ms: %i\n", (py_i64)swpet_ms);
|
||||||
pk_sprintf(&buf, "total_ms: %i\n", (py_i64)(mark_ms + swpet_ms));
|
pk_sprintf(&buf, "total_ms: %i\n", (py_i64)(mark_ms + swpet_ms));
|
||||||
@ -65,11 +77,11 @@ static void ManagedHeap__fire_debug_callback(ManagedHeap* self, ManagedHeapSwpet
|
|||||||
int l_freed = out_info->large_types[i];
|
int l_freed = out_info->large_types[i];
|
||||||
if(s_freed == 0 && l_freed == 0) continue;
|
if(s_freed == 0 && l_freed == 0) continue;
|
||||||
snprintf(line_buf,
|
snprintf(line_buf,
|
||||||
sizeof(line_buf),
|
sizeof(line_buf),
|
||||||
"[%-24s] small: %6d large: %6d\n",
|
"[%-24s] small: %6d large: %6d\n",
|
||||||
type_name,
|
type_name,
|
||||||
s_freed,
|
s_freed,
|
||||||
l_freed);
|
l_freed);
|
||||||
c11_sbuf__write_cstr(&buf, line_buf);
|
c11_sbuf__write_cstr(&buf, line_buf);
|
||||||
}
|
}
|
||||||
c11_sbuf__write_cstr(&buf, DIVIDER);
|
c11_sbuf__write_cstr(&buf, DIVIDER);
|
||||||
@ -85,9 +97,10 @@ static void ManagedHeap__fire_debug_callback(ManagedHeap* self, ManagedHeapSwpet
|
|||||||
|
|
||||||
py_push(&self->debug_callback);
|
py_push(&self->debug_callback);
|
||||||
py_pushnil();
|
py_pushnil();
|
||||||
|
py_newstr(py_pushtmp(), "stop");
|
||||||
py_StackRef arg = py_pushtmp();
|
py_StackRef arg = py_pushtmp();
|
||||||
c11_sbuf__py_submit(&buf, arg);
|
c11_sbuf__py_submit(&buf, arg);
|
||||||
bool ok = py_vectorcall(1, 0);
|
bool ok = py_vectorcall(2, 0);
|
||||||
if(!ok) {
|
if(!ok) {
|
||||||
char* msg = py_formatexc();
|
char* msg = py_formatexc();
|
||||||
c11__abort("gc_debug_callback error!!\n%s", msg);
|
c11__abort("gc_debug_callback error!!\n%s", msg);
|
||||||
@ -99,12 +112,15 @@ void ManagedHeap__collect_hint(ManagedHeap* self) {
|
|||||||
self->gc_counter = 0;
|
self->gc_counter = 0;
|
||||||
|
|
||||||
ManagedHeapSwpetInfo* out_info = NULL;
|
ManagedHeapSwpetInfo* out_info = NULL;
|
||||||
if(!py_isnone(&self->debug_callback)) out_info = ManagedHeapSwpetInfo__new();
|
if(!py_isnone(&self->debug_callback)) {
|
||||||
|
out_info = ManagedHeapSwpetInfo__new();
|
||||||
|
ManagedHeap__fire_debug_callback_start(self);
|
||||||
|
}
|
||||||
|
|
||||||
ManagedHeap__mark(self);
|
ManagedHeap__mark(self);
|
||||||
if(out_info) out_info->mark_end = clock();
|
if(out_info) out_info->mark_end_ns = time_ns();
|
||||||
int freed = ManagedHeap__sweep(self, out_info);
|
int freed = ManagedHeap__sweep(self, out_info);
|
||||||
if(out_info) out_info->swpet_end = clock();
|
if(out_info) out_info->swpet_end_ns = time_ns();
|
||||||
|
|
||||||
// adjust `gc_threshold` based on `freed_ma`
|
// adjust `gc_threshold` based on `freed_ma`
|
||||||
self->freed_ma[0] = self->freed_ma[1];
|
self->freed_ma[0] = self->freed_ma[1];
|
||||||
@ -126,7 +142,7 @@ void ManagedHeap__collect_hint(ManagedHeap* self) {
|
|||||||
self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper);
|
self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper);
|
||||||
|
|
||||||
if(!py_isnone(&self->debug_callback)) {
|
if(!py_isnone(&self->debug_callback)) {
|
||||||
ManagedHeap__fire_debug_callback(self, out_info);
|
ManagedHeap__fire_debug_callback_stop(self, out_info);
|
||||||
ManagedHeapSwpetInfo__delete(out_info);
|
ManagedHeapSwpetInfo__delete(out_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,12 +151,15 @@ int ManagedHeap__collect(ManagedHeap* self) {
|
|||||||
self->gc_counter = 0;
|
self->gc_counter = 0;
|
||||||
|
|
||||||
ManagedHeapSwpetInfo* out_info = NULL;
|
ManagedHeapSwpetInfo* out_info = NULL;
|
||||||
if(!py_isnone(&self->debug_callback)) out_info = ManagedHeapSwpetInfo__new();
|
if(!py_isnone(&self->debug_callback)) {
|
||||||
|
out_info = ManagedHeapSwpetInfo__new();
|
||||||
|
ManagedHeap__fire_debug_callback_start(self);
|
||||||
|
}
|
||||||
|
|
||||||
ManagedHeap__mark(self);
|
ManagedHeap__mark(self);
|
||||||
if(out_info) out_info->mark_end = clock();
|
if(out_info) out_info->mark_end_ns = time_ns();
|
||||||
int freed = ManagedHeap__sweep(self, out_info);
|
int freed = ManagedHeap__sweep(self, out_info);
|
||||||
if(out_info) out_info->swpet_end = clock();
|
if(out_info) out_info->swpet_end_ns = time_ns();
|
||||||
|
|
||||||
if(out_info) {
|
if(out_info) {
|
||||||
out_info->auto_thres.before = self->gc_threshold;
|
out_info->auto_thres.before = self->gc_threshold;
|
||||||
@ -148,7 +167,7 @@ int ManagedHeap__collect(ManagedHeap* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!py_isnone(&self->debug_callback)) {
|
if(!py_isnone(&self->debug_callback)) {
|
||||||
ManagedHeap__fire_debug_callback(self, out_info);
|
ManagedHeap__fire_debug_callback_stop(self, out_info);
|
||||||
ManagedHeapSwpetInfo__delete(out_info);
|
ManagedHeapSwpetInfo__delete(out_info);
|
||||||
}
|
}
|
||||||
return freed;
|
return freed;
|
||||||
|
|||||||
@ -140,7 +140,7 @@ ManagedHeapSwpetInfo* ManagedHeapSwpetInfo__new() {
|
|||||||
self->small_types[i] = 0;
|
self->small_types[i] = 0;
|
||||||
self->large_types[i] = 0;
|
self->large_types[i] = 0;
|
||||||
}
|
}
|
||||||
self->start = clock();
|
self->start_ns = time_ns();
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
#include "pocketpy/interpreter/vm.h"
|
#include "pocketpy/interpreter/vm.h"
|
||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
int64_t time_ns(); // from random.c
|
|
||||||
|
|
||||||
/* https://github.com/clibs/mt19937ar
|
/* https://github.com/clibs/mt19937ar
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,35 @@
|
|||||||
#include "pocketpy/pocketpy.h"
|
#define _XOPEN_SOURCE 700
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#undef _XOPEN_SOURCE
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <profileapi.h>
|
||||||
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "pocketpy/pocketpy.h"
|
||||||
|
#include "pocketpy/common/threads.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#define NANOS_PER_SEC 1000000000
|
#define NANOS_PER_SEC 1000000000
|
||||||
|
|
||||||
#ifndef __circle__
|
#ifndef __circle__
|
||||||
|
|
||||||
int64_t time_ns() {
|
int64_t time_ns() {
|
||||||
|
#ifdef _WIN32
|
||||||
|
FILETIME system_time;
|
||||||
|
ULARGE_INTEGER large;
|
||||||
|
|
||||||
|
GetSystemTimePreciseAsFileTime(&system_time);
|
||||||
|
large.u.LowPart = system_time.dwLowDateTime;
|
||||||
|
large.u.HighPart = system_time.dwHighDateTime;
|
||||||
|
/* 11,644,473,600,000,000,000: number of nanoseconds between
|
||||||
|
the 1st january 1601 and the 1st january 1970 (369 years + 89 leap
|
||||||
|
days). */
|
||||||
|
return (large.QuadPart - 116444736000000000) * 100;
|
||||||
|
#else
|
||||||
struct timespec tms;
|
struct timespec tms;
|
||||||
#ifdef CLOCK_REALTIME
|
#ifdef CLOCK_REALTIME
|
||||||
clock_gettime(CLOCK_REALTIME, &tms);
|
clock_gettime(CLOCK_REALTIME, &tms);
|
||||||
@ -18,9 +42,36 @@ int64_t time_ns() {
|
|||||||
/* Add full nanoseconds */
|
/* Add full nanoseconds */
|
||||||
nanos += tms.tv_nsec;
|
nanos += tms.tv_nsec;
|
||||||
return nanos;
|
return nanos;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t time_monotonic_ns() {
|
||||||
|
#ifdef _WIN32
|
||||||
|
LARGE_INTEGER now;
|
||||||
|
QueryPerformanceCounter(&now);
|
||||||
|
LONGLONG ticksll = now.QuadPart;
|
||||||
|
static LARGE_INTEGER freq;
|
||||||
|
if(freq.QuadPart == 0) QueryPerformanceFrequency(&freq);
|
||||||
|
/* Convert ticks to nanoseconds */
|
||||||
|
return (ticksll * NANOS_PER_SEC) / freq.QuadPart;
|
||||||
|
#else
|
||||||
|
struct timespec tms;
|
||||||
|
#ifdef CLOCK_MONOTONIC
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &tms);
|
||||||
|
#else
|
||||||
|
/* The C11 way */
|
||||||
|
timespec_get(&tms, TIME_UTC);
|
||||||
|
#endif
|
||||||
|
/* seconds, multiplied with 1 billion */
|
||||||
|
int64_t nanos = tms.tv_sec * (int64_t)NANOS_PER_SEC;
|
||||||
|
/* Add full nanoseconds */
|
||||||
|
nanos += tms.tv_nsec;
|
||||||
|
return nanos;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int64_t time_ns() { return 0; }
|
int64_t time_ns() { return 0; }
|
||||||
|
int64_t time_monotonic_ns() { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool time_time(int argc, py_Ref argv) {
|
static bool time_time(int argc, py_Ref argv) {
|
||||||
@ -37,7 +88,25 @@ static bool time_time_ns(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool time_time_monotonic(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(0);
|
||||||
|
int64_t nanos = time_monotonic_ns();
|
||||||
|
py_newfloat(py_retval(), (double)nanos / NANOS_PER_SEC);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool time_time_monotonic_ns(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(0);
|
||||||
|
int64_t nanos = time_monotonic_ns();
|
||||||
|
py_newint(py_retval(), nanos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool time_perf_counter(int argc, py_Ref argv) {
|
static bool time_perf_counter(int argc, py_Ref argv) {
|
||||||
|
return time_time_monotonic(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool time_process_time(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(0);
|
PY_CHECK_ARGC(0);
|
||||||
py_newfloat(py_retval(), (double)clock() / CLOCKS_PER_SEC);
|
py_newfloat(py_retval(), (double)clock() / CLOCKS_PER_SEC);
|
||||||
return true;
|
return true;
|
||||||
@ -48,11 +117,14 @@ static bool time_sleep(int argc, py_Ref argv) {
|
|||||||
py_f64 secs;
|
py_f64 secs;
|
||||||
if(!py_castfloat(argv, &secs)) return false;
|
if(!py_castfloat(argv, &secs)) return false;
|
||||||
|
|
||||||
clock_t start = clock();
|
int64_t start = time_monotonic_ns();
|
||||||
const clock_t end = start + (clock_t)(secs * CLOCKS_PER_SEC);
|
const int64_t end = start + secs * NANOS_PER_SEC;
|
||||||
while(true) {
|
while(true) {
|
||||||
clock_t now = clock();
|
int64_t now = time_monotonic_ns();
|
||||||
if(now >= end) break;
|
if(now >= end) break;
|
||||||
|
#if PK_ENABLE_THREADS
|
||||||
|
c11_thrd__yield();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
py_newnone(py_retval());
|
py_newnone(py_retval());
|
||||||
return true;
|
return true;
|
||||||
@ -105,7 +177,10 @@ void pk__add_module_time() {
|
|||||||
|
|
||||||
py_bindfunc(mod, "time", time_time);
|
py_bindfunc(mod, "time", time_time);
|
||||||
py_bindfunc(mod, "time_ns", time_time_ns);
|
py_bindfunc(mod, "time_ns", time_time_ns);
|
||||||
|
py_bindfunc(mod, "monotonic", time_time_monotonic);
|
||||||
|
py_bindfunc(mod, "monotonic_ns", time_time_monotonic_ns);
|
||||||
py_bindfunc(mod, "perf_counter", time_perf_counter);
|
py_bindfunc(mod, "perf_counter", time_perf_counter);
|
||||||
|
py_bindfunc(mod, "process_time", time_process_time);
|
||||||
py_bindfunc(mod, "sleep", time_sleep);
|
py_bindfunc(mod, "sleep", time_sleep);
|
||||||
py_bindfunc(mod, "localtime", time_localtime);
|
py_bindfunc(mod, "localtime", time_localtime);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "pocketpy/common/threads.h"
|
#include "pocketpy/common/threads.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int64_t time_ns();
|
int64_t time_monotonic_ns();
|
||||||
|
|
||||||
static void func(void* arg) {
|
static void func(void* arg) {
|
||||||
long long* val = (long long*)arg;
|
long long* val = (long long*)arg;
|
||||||
@ -31,10 +31,11 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("==> %dth run\n", i + 1);
|
printf("==> %dth run\n", i + 1);
|
||||||
int64_t start_ns = time_ns();
|
int64_t start_ns = time_monotonic_ns();
|
||||||
c11_thrdpool__map(&pool, func, args, num_tasks);
|
c11_thrdpool__map(&pool, func, args, num_tasks);
|
||||||
c11_thrdpool__join(&pool);
|
c11_thrdpool__join(&pool);
|
||||||
int64_t end_ns = time_ns();
|
int64_t end_ns = time_monotonic_ns();
|
||||||
|
printf("==> %lld -> %lld\n", (long long)start_ns, (long long)end_ns);
|
||||||
double elapsed = (end_ns - start_ns) / 1e9;
|
double elapsed = (end_ns - start_ns) / 1e9;
|
||||||
printf(" Results: %lld, %lld, %lld, %lld, %lld\n",
|
printf(" Results: %lld, %lld, %lld, %lld, %lld\n",
|
||||||
data[0],
|
data[0],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user