From 1d30103f6a4fc45c0f40ae781e370bb62deecb91 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Wed, 26 Nov 2025 22:56:39 +0800 Subject: [PATCH] fix time module --- include/pocketpy/interpreter/heap.h | 6 +-- include/pocketpy/pocketpy.h | 2 + src/common/threads.c | 2 - src/interpreter/heap.c | 17 +++++---- src/interpreter/vmx.c | 2 +- src/modules/random.c | 3 -- src/modules/time.c | 58 ++++++++++++++++++++++++++++- src2/test_threads.c | 7 ++-- 8 files changed, 75 insertions(+), 22 deletions(-) diff --git a/include/pocketpy/interpreter/heap.h b/include/pocketpy/interpreter/heap.h index f09d882a..8e204827 100644 --- a/include/pocketpy/interpreter/heap.h +++ b/include/pocketpy/interpreter/heap.h @@ -17,9 +17,9 @@ typedef struct ManagedHeap { } ManagedHeap; typedef struct { - clock_t start; - clock_t mark_end; - clock_t swpet_end; + int64_t start_ns; + int64_t mark_end_ns; + int64_t swpet_end_ns; int types_length; int* small_types; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 62767e5a..1c3eaf00 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -801,6 +801,8 @@ PK_API void py_profiler_reset(); PK_API char* py_profiler_report(); /************* Others *************/ +int64_t time_ns(); +int64_t time_monotonic_ns(); /// An utility function to read a line from stdin for REPL. PK_API int py_replinput(char* buf, int max_size); diff --git a/src/common/threads.c b/src/common/threads.c index a53ed569..33792b15 100644 --- a/src/common/threads.c +++ b/src/common/threads.c @@ -75,8 +75,6 @@ void c11_cond__broadcast(c11_cond_t* cond) { cnd_broadcast(cond); } #define C11_THRDPOOL_DEBUG 0 #if C11_THRDPOOL_DEBUG -int64_t time_ns(); - static void c11_thrdpool_debug_log(int index, const char* format, ...) { va_list args; va_start(args, format); diff --git a/src/interpreter/heap.c b/src/interpreter/heap.c index f4298001..5408d9d1 100644 --- a/src/interpreter/heap.c +++ b/src/interpreter/heap.c @@ -6,6 +6,7 @@ #include "pocketpy/pocketpy.h" #include + void ManagedHeap__ctor(ManagedHeap* self) { MultiPool__ctor(&self->small_objects); c11_vector__ctor(&self->large_objects, sizeof(PyObject*)); @@ -39,12 +40,12 @@ static void ManagedHeap__fire_debug_callback(ManagedHeap* self, ManagedHeapSwpet c11_sbuf buf; c11_sbuf__ctor(&buf); - const clock_t CLOCKS_PER_MS = CLOCKS_PER_SEC / 1000; + const int64_t NANOS_PER_SEC = 1000000000; const char* DIVIDER = "------------------------------------------------------------\n"; - 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; + double start = out_info->start_ns / 1e9; + int64_t mark_ms = (out_info->mark_end_ns - out_info->start_ns) / NANOS_PER_SEC; + int64_t swpet_ms = (out_info->swpet_end_ns - out_info->mark_end_ns) / NANOS_PER_SEC; c11_sbuf__write_cstr(&buf, DIVIDER); pk_sprintf(&buf, "start: %f\n", (double)start / 1000); @@ -102,9 +103,9 @@ void ManagedHeap__collect_hint(ManagedHeap* self) { if(!py_isnone(&self->debug_callback)) out_info = ManagedHeapSwpetInfo__new(); 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); - 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` self->freed_ma[0] = self->freed_ma[1]; @@ -138,9 +139,9 @@ int ManagedHeap__collect(ManagedHeap* self) { if(!py_isnone(&self->debug_callback)) out_info = ManagedHeapSwpetInfo__new(); 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); - if(out_info) out_info->swpet_end = clock(); + if(out_info) out_info->swpet_end_ns = time_ns(); if(out_info) { out_info->auto_thres.before = self->gc_threshold; diff --git a/src/interpreter/vmx.c b/src/interpreter/vmx.c index 300bbbad..75e1960f 100644 --- a/src/interpreter/vmx.c +++ b/src/interpreter/vmx.c @@ -140,7 +140,7 @@ ManagedHeapSwpetInfo* ManagedHeapSwpetInfo__new() { self->small_types[i] = 0; self->large_types[i] = 0; } - self->start = clock(); + self->start_ns = time_ns(); return self; } diff --git a/src/modules/random.c b/src/modules/random.c index cc6f2010..b6be294f 100644 --- a/src/modules/random.c +++ b/src/modules/random.c @@ -1,8 +1,5 @@ #include "pocketpy/interpreter/vm.h" #include "pocketpy/pocketpy.h" -#include - -int64_t time_ns(); // from random.c /* https://github.com/clibs/mt19937ar diff --git a/src/modules/time.c b/src/modules/time.c index 998a3e87..bffabffc 100644 --- a/src/modules/time.c +++ b/src/modules/time.c @@ -2,6 +2,13 @@ #include #undef _XOPEN_SOURCE +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#undef WIN32_LEAN_AND_MEAN +#endif + #include "pocketpy/pocketpy.h" #include "pocketpy/common/threads.h" #include @@ -23,8 +30,34 @@ int64_t time_ns() { nanos += tms.tv_nsec; return nanos; } + +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; +#endif + + 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; +} #else int64_t time_ns() { return 0; } +int64_t time_monotonic_ns() { return 0; } #endif static bool time_time(int argc, py_Ref argv) { @@ -41,7 +74,25 @@ static bool time_time_ns(int argc, py_Ref argv) { 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) { + return time_time_monotonic(argc, argv); +} + +static bool time_process_time(int argc, py_Ref argv) { PY_CHECK_ARGC(0); py_newfloat(py_retval(), (double)clock() / CLOCKS_PER_SEC); return true; @@ -52,10 +103,10 @@ static bool time_sleep(int argc, py_Ref argv) { py_f64 secs; if(!py_castfloat(argv, &secs)) return false; - int64_t start = time_ns(); + int64_t start = time_monotonic_ns(); const int64_t end = start + secs * NANOS_PER_SEC; while(true) { - int64_t now = time_ns(); + int64_t now = time_monotonic_ns(); if(now >= end) break; #if PK_ENABLE_THREADS c11_thrd__yield(); @@ -112,7 +163,10 @@ void pk__add_module_time() { py_bindfunc(mod, "time", time_time); 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, "process_time", time_process_time); py_bindfunc(mod, "sleep", time_sleep); py_bindfunc(mod, "localtime", time_localtime); } diff --git a/src2/test_threads.c b/src2/test_threads.c index bbf673dd..02652915 100644 --- a/src2/test_threads.c +++ b/src2/test_threads.c @@ -1,7 +1,7 @@ #include "pocketpy/common/threads.h" #include -int64_t time_ns(); +int64_t time_monotonic_ns(); static void func(void* arg) { long long* val = (long long*)arg; @@ -31,10 +31,11 @@ int main(int argc, char** argv) { } 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__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; printf(" Results: %lld, %lld, %lld, %lld, %lld\n", data[0],