blueloveTH 6 месяцев назад
Родитель
Сommit
03ee6563c8

+ 2 - 1
.gitignore

@@ -40,4 +40,5 @@ docs/C-API/functions.md
 
 
 cmake-build-*
-tmp/
+tmp/
+profiler_report.json

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

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

+ 8 - 3
include/pocketpy/pocketpy.h

@@ -163,9 +163,6 @@ 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).
@@ -704,6 +701,14 @@ PK_API bool py_json_loads(const char* source) PY_RAISE PY_RETURN;
 PK_API bool py_pickle_dumps(py_Ref val) PY_RAISE PY_RETURN;
 /// Python equivalent to `pickle.loads(val)`.
 PK_API bool py_pickle_loads(const unsigned char* data, int size) PY_RAISE PY_RETURN;
+
+/************* Profiler *************/
+
+PK_API void py_profiler_begin();
+PK_API void py_profiler_end();
+PK_API void py_profiler_reset();
+PK_API char* py_profiler_report();
+
 /************* Unchecked Functions *************/
 
 PK_API py_ObjectRef py_tuple_data(py_Ref self);

+ 7 - 0
src/interpreter/line_profier.c → src/interpreter/line_profiler.c

@@ -66,6 +66,12 @@ void LineProfiler__reset(LineProfiler* self) {
 c11_string* LineProfiler__get_report(LineProfiler* self) {
     c11_sbuf sbuf;
     c11_sbuf__ctor(&sbuf);
+    c11_sbuf__write_char(&sbuf, '{');
+    c11_sbuf__write_cstr(&sbuf, "\"version\": 1, ");
+    c11_sbuf__write_cstr(&sbuf, "\"CLOCKS_PER_SEC\": ");
+    c11_sbuf__write_i64(&sbuf, CLOCKS_PER_SEC);
+    c11_sbuf__write_cstr(&sbuf, ", \"records\": ");
+
     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);
@@ -90,5 +96,6 @@ c11_string* LineProfiler__get_report(LineProfiler* self) {
         if(i < self->records.length - 1) c11_sbuf__write_cstr(&sbuf, ", ");
     }
     c11_sbuf__write_char(&sbuf, '}');
+    c11_sbuf__write_char(&sbuf, '}');
     return c11_sbuf__submit(&sbuf);
 }

+ 30 - 3
src/interpreter/vm.c

@@ -34,9 +34,36 @@ static void pk_default_flush() { fflush(stdout); }
 
 static int pk_default_getchr() { return getchar(); }
 
-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);
+void py_profiler_begin() {
+    LineProfiler* lp = &pk_current_vm->line_profiler;
+    TraceInfo* trace_info = &pk_current_vm->trace_info;
+    if(trace_info->func == NULL) py_sys_settrace(LineProfiler_tracefunc, true);
+    c11__rtassert(trace_info->func == LineProfiler_tracefunc);
+    LineProfiler__begin(lp);
+}
+
+void py_profiler_end() {
+    LineProfiler* lp = &pk_current_vm->line_profiler;
+    LineProfiler__end(lp);
+}
+
+void py_profiler_reset() {
+    LineProfiler* lp = &pk_current_vm->line_profiler;
+    LineProfiler__reset(lp);
+}
+
+char* py_profiler_report() {
+    LineProfiler* lp = &pk_current_vm->line_profiler;
+    if(lp->enabled) LineProfiler__end(lp);
+    c11_string* s = LineProfiler__get_report(lp);
+    char* s_dup = c11_strdup(s->data);
+    c11_string__delete(s);
+    return s_dup;
+}
+
+void LineProfiler_tracefunc(py_Frame* frame, enum py_TraceEvent event) {
+    LineProfiler* lp = &pk_current_vm->line_profiler;
+    if(lp->enabled && event == TRACE_EVENT_LINE) LineProfiler__tracefunc_line(lp, frame);
 }
 
 static int BinTree__cmp_cstr(void* lhs, void* rhs) {

+ 4 - 2
src/modules/pkpy.c

@@ -469,8 +469,10 @@ static void pkpy_configmacros_add(py_Ref dict, const char* key, int val) {
 
 static bool pkpy_profiler_begin(int argc, py_Ref argv) {
     PY_CHECK_ARGC(0);
-    if(pk_current_vm->trace_info.func != py_LineProfiler_tracefunc) {
-        return RuntimeError("py_LineProfiler_tracefunc() should be set as the trace function");
+    TraceInfo* trace_info = &pk_current_vm->trace_info;
+    if(trace_info->func == NULL) py_sys_settrace(LineProfiler_tracefunc, true);
+    if(trace_info->func != LineProfiler_tracefunc) {
+        return RuntimeError("LineProfiler_tracefunc() should be set as the trace function");
     }
     LineProfiler__begin(&pk_current_vm->line_profiler);
     py_newnone(py_retval());

+ 15 - 2
src2/main.c

@@ -78,10 +78,23 @@ int main(int argc, char** argv) {
             }
         }
     } else {
-        if(profile) py_sys_settrace(py_LineProfiler_tracefunc, true);
+        if(profile) py_profiler_begin();
         char* source = read_file(filename);
         if(source) {
-            if(!py_exec(source, filename, EXEC_MODE, NULL)) py_printexc();
+            if(!py_exec(source, filename, EXEC_MODE, NULL))
+                py_printexc();
+            else {
+                if(profile) {
+                    char* json_report = py_profiler_report();
+                    FILE* report_file = fopen("profiler_report.json", "w");
+                    if(report_file) {
+                        fprintf(report_file, "%s", json_report);
+                        fclose(report_file);
+                    }
+                    PK_FREE(json_report);
+                }
+            }
+
             PK_FREE(source);
         }
     }