blueloveTH 6 mesiacov pred
rodič
commit
169e825197

+ 1 - 2
include/pocketpy/interpreter/line_profiler.h

@@ -24,5 +24,4 @@ void LineProfiler__begin(LineProfiler* self);
 void LineProfiler__tracefunc_line(LineProfiler* self, py_Frame* frame);
 void LineProfiler__end(LineProfiler* self);
 void LineProfiler__reset(LineProfiler* self);
-
-void LineProfiler__tracefunc(py_Frame* frame, enum py_TraceEvent event);
+c11_string* LineProfiler__get_report(LineProfiler* self);

+ 3 - 0
include/pocketpy/pocketpy.h

@@ -163,6 +163,9 @@ PK_API void py_Frame_newlocals(py_Frame* frame, py_OutRef out);
 /// Returns `NULL` if not available.
 PK_API py_StackRef py_Frame_function(py_Frame* frame);
 
+/// Trace function for the line profiler.
+PK_API void py_LineProfiler_tracefunc(py_Frame* frame, enum py_TraceEvent event);
+
 /// Run a source string.
 /// @param source source string.
 /// @param filename filename (for error messages).

+ 8 - 4
include/typings/pkpy.pyi

@@ -28,15 +28,19 @@ def currentvm() -> int:
 
 
 def watchdog_begin(timeout: int):
-    """
-    Begin the watchdog with `timeout` in milliseconds.
+    """Begin the watchdog with `timeout` in milliseconds.
+
     `PK_ENABLE_WATCHDOG` must be defined to `1` to use this feature.
     You need to call `watchdog_end()` later.
     If `timeout` is reached, `TimeoutError` will be raised.
     """
-def watchdog_end():
-    """Reset the watchdog."""
+def watchdog_end() -> None:
+    """End the watchdog after a call to `watchdog_begin()`."""
 
+def profiler_begin() -> None: ...
+def profiler_end() -> None: ...
+def profiler_reset() -> None: ...
+def profiler_report() -> dict[str, list[list]]: ...
 
 class ComputeThread:
     def __init__(self, vm_index: Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]): ...

+ 32 - 0
src/interpreter/line_profier.c

@@ -1,4 +1,6 @@
+#include "pocketpy/common/sstream.h"
 #include "pocketpy/interpreter/line_profiler.h"
+#include "pocketpy/objects/sourcedata.h"
 #include <assert.h>
 
 void LineProfiler__ctor(LineProfiler* self) {
@@ -60,3 +62,33 @@ void LineProfiler__reset(LineProfiler* self) {
     LineProfiler__dtor(self);
     LineProfiler__ctor(self);
 }
+
+c11_string* LineProfiler__get_report(LineProfiler* self) {
+    c11_sbuf sbuf;
+    c11_sbuf__ctor(&sbuf);
+    c11_sbuf__write_char(&sbuf, '{');
+    for(int i = 0; i < self->records.length; i++) {
+        c11_smallmap_p2i_KV kv = c11__getitem(c11_smallmap_p2i_KV, &self->records, i);
+        SourceData_ src = (SourceData_)kv.key;
+        int line_record_length = src->line_starts.length + 1;
+        c11_sv src_name = c11_string__sv(src->filename);
+        c11_sbuf__write_quoted(&sbuf, src_name, '"');
+        c11_sbuf__write_cstr(&sbuf, ": [");
+        LineRecord* lines = (LineRecord*)kv.value;
+        for(int j = 1; j < line_record_length; j++) {
+            // [<j>, <hits>, <time>]
+            c11_sbuf__write_cstr(&sbuf, "[");
+            c11_sbuf__write_int(&sbuf, j);
+            c11_sbuf__write_cstr(&sbuf, ", ");
+            c11_sbuf__write_i64(&sbuf, lines[j].hits);
+            c11_sbuf__write_cstr(&sbuf, ", ");
+            c11_sbuf__write_i64(&sbuf, lines[j].time);
+            c11_sbuf__write_cstr(&sbuf, "]");
+            if(j < line_record_length - 1) c11_sbuf__write_cstr(&sbuf, ", ");
+        }
+        c11_sbuf__write_cstr(&sbuf, "]");
+        if(i < self->records.length - 1) c11_sbuf__write_cstr(&sbuf, ", ");
+    }
+    c11_sbuf__write_char(&sbuf, '}');
+    return c11_sbuf__submit(&sbuf);
+}

+ 5 - 5
src/interpreter/vm.c

@@ -34,9 +34,9 @@ static void pk_default_flush() { fflush(stdout); }
 
 static int pk_default_getchr() { return getchar(); }
 
-void LineProfiler__tracefunc(py_Frame* frame, enum py_TraceEvent event) {
+void py_LineProfiler_tracefunc(py_Frame* frame, enum py_TraceEvent event) {
     LineProfiler* self = &pk_current_vm->line_profiler;
-    if(self->enabled && event == TRACE_EVENT_LINE) { LineProfiler__tracefunc_line(self, frame); }
+    if(self->enabled && event == TRACE_EVENT_LINE) LineProfiler__tracefunc_line(self, frame);
 }
 
 static int BinTree__cmp_cstr(void* lhs, void* rhs) {
@@ -234,9 +234,9 @@ void VM__ctor(VM* self) {
     pk__add_module_unicodedata();
 
     pk__add_module_conio();
-    pk__add_module_lz4();    // optional
-    pk__add_module_libhv();  // optional
-    pk__add_module_cute_png(); // optional
+    pk__add_module_lz4();       // optional
+    pk__add_module_libhv();     // optional
+    pk__add_module_cute_png();  // optional
     pk__add_module_pkpy();
 
     // add python builtins

+ 35 - 1
src/modules/pkpy.c

@@ -458,7 +458,7 @@ static void pk_ComputeThread__register(py_Ref mod) {
     py_bindmethod(type, "eval", ComputeThread_eval);
 }
 
-#endif // PK_ENABLE_THREADS
+#endif  // PK_ENABLE_THREADS
 
 static void pkpy_configmacros_add(py_Ref dict, const char* key, int val) {
     assert(dict->type == tp_dict);
@@ -467,6 +467,35 @@ static void pkpy_configmacros_add(py_Ref dict, const char* key, int val) {
     py_dict_setitem_by_str(dict, key, &tmp);
 }
 
+static bool pkpy_profiler_begin(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(0);
+    LineProfiler__begin(&pk_current_vm->line_profiler);
+    py_newnone(py_retval());
+    return true;
+}
+
+static bool pkpy_profiler_end(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(0);
+    LineProfiler__end(&pk_current_vm->line_profiler);
+    py_newnone(py_retval());
+    return true;
+}
+
+static bool pkpy_profiler_reset(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(0);
+    LineProfiler__reset(&pk_current_vm->line_profiler);
+    py_newnone(py_retval());
+    return true;
+}
+
+static bool pkpy_profiler_report(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(0);
+    c11_string* report = LineProfiler__get_report(&pk_current_vm->line_profiler);
+    bool ok = py_json_loads(report->data);
+    c11_string__delete(report);
+    return ok;
+}
+
 void pk__add_module_pkpy() {
     py_Ref mod = py_newmodule("pkpy");
 
@@ -516,6 +545,11 @@ void pk__add_module_pkpy() {
     pk_ComputeThread__register(mod);
 #endif
 
+    py_bindfunc(mod, "profiler_begin", pkpy_profiler_begin);
+    py_bindfunc(mod, "profiler_end", pkpy_profiler_end);
+    py_bindfunc(mod, "profiler_reset", pkpy_profiler_reset);
+    py_bindfunc(mod, "profiler_report", pkpy_profiler_report);
+
     py_Ref configmacros = py_emplacedict(mod, py_name("configmacros"));
     py_newdict(configmacros);
     pkpy_configmacros_add(configmacros, "PK_ENABLE_OS", PK_ENABLE_OS);

+ 1 - 3
src2/main.c

@@ -25,7 +25,6 @@ static char* read_file(const char* path) {
     return buffer;
 }
 
-// void LineProfiler__tracefunc(py_Frame* frame, enum py_TraceEvent event);
 static char buf[2048];
 
 int main(int argc, char** argv) {
@@ -52,8 +51,7 @@ int main(int argc, char** argv) {
     py_initialize();
     py_sys_setargv(argc, argv);
 
-    assert(!profile);  // not implemented yet
-    // if(profile) py_sys_settrace(LineProfiler__tracefunc, true);
+    if(profile) py_sys_settrace(py_LineProfiler_tracefunc, true);
 
     if(filename == NULL) {
         printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");