Selaa lähdekoodia

add `PK_ENABLE_PROFILER`

blueloveTH 1 vuosi sitten
vanhempi
commit
6cc4d9c5cc

+ 5 - 0
CMakeLists.txt

@@ -29,6 +29,11 @@ if(PK_ENABLE_OS)
     add_definitions(-DPK_ENABLE_OS=1)
 endif()
 
+option(PK_ENABLE_PROFILER "" OFF)
+if(PK_ENABLE_PROFILER)
+    add_definitions(-DPK_ENABLE_PROFILER=1)
+endif()
+
 option(PK_NO_EXPORT_C_API "" OFF)
 if(PK_NO_EXPORT_C_API)
     add_definitions(-DPK_NO_EXPORT_C_API)

+ 1 - 1
docs/features/debugging.md

@@ -4,7 +4,7 @@ title: Debugging
 ---
 
 !!!
-This feature is available in `v1.4.5` or higher.
+This feature is available in `v1.4.5` or higher. Set `PK_ENABLE_PROFILER` to `1` to enable this feature.
 !!!
 
 You can invoke `breakpoint()` in your python code to start a PDB-like session.

+ 3 - 1
docs/modules/line_profiler.md

@@ -3,7 +3,9 @@ icon: package
 label: line_profiler
 ---
 
-Line-by-line profiler for Python.
+!!!
+This module is optional. Set `PK_ENABLE_PROFILER` to `1` to enable it.
+!!!
 
 ## Example
 

+ 5 - 0
include/pocketpy/config.h

@@ -13,6 +13,11 @@
 #define PK_ENABLE_THREAD            0
 #endif
 
+// Enable `line_profiler` module and `breakpoint()` function
+#ifndef PK_ENABLE_PROFILER          // can be overridden by cmake
+#define PK_ENABLE_PROFILER          0
+#endif
+
 // GC min threshold
 #ifndef PK_GC_MIN_THRESHOLD         // can be overridden by cmake
 #define PK_GC_MIN_THRESHOLD         32768

+ 5 - 1
include/pocketpy/vm.h

@@ -139,8 +139,10 @@ public:
 
     void (*_ceval_on_step)(VM*, Frame*, Bytecode bc) = nullptr;
 
+#if PK_ENABLE_PROFILER
     LineProfiler* _profiler = nullptr;
     NextBreakpoint _next_breakpoint;
+#endif
 
     PrintFunc _stdout;
     PrintFunc _stderr;
@@ -173,10 +175,12 @@ public:
     void _pop_frame(){
         s_data.reset(callstack.top()._sp_base);
         callstack.pop();
-        
+
+#if PK_ENABLE_PROFILER
         if(!_next_breakpoint.empty() && callstack.size()<_next_breakpoint.callstack_size){
             _next_breakpoint = NextBreakpoint();
         }
+#endif
     }
 
     PyObject* py_str(PyObject* obj);

+ 1 - 1
run_tests.sh

@@ -1,6 +1,6 @@
 python prebuild.py
 SRC=$(find src/ -name "*.cpp")
-clang++ -std=c++17 --coverage -O1 -stdlib=libc++ -frtti -Wfatal-errors -o main src2/main.cpp $SRC -Iinclude -DPK_ENABLE_OS=1 -DPK_DEBUG_PRECOMPILED_EXEC=1
+clang++ -std=c++17 --coverage -O1 -stdlib=libc++ -frtti -Wfatal-errors -o main src2/main.cpp $SRC -Iinclude -DPK_ENABLE_OS=1 -DPK_DEBUG_PRECOMPILED_EXEC=1 -DPK_ENABLE_PROFILER=1
 
 python scripts/run_tests.py
 

+ 15 - 10
src/ceval.cpp

@@ -72,12 +72,17 @@ PyObject* VM::_run_top_frame(){
  */
 {
 
+
+#if PK_ENABLE_PROFILER
 #define CEVAL_STEP_CALLBACK() \
     if(_ceval_on_step) _ceval_on_step(this, frame, byte);   \
     if(_profiler) _profiler->_step(callstack.size(), frame);        \
     if(!_next_breakpoint.empty()) { _next_breakpoint._step(this); }
+#else
+#define CEVAL_STEP_CALLBACK() \
+    if(_ceval_on_step) _ceval_on_step(this, frame, byte);
+#endif
 
-#define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; }
 __NEXT_FRAME:
     // cache
     const CodeObject* co = frame->co;
@@ -639,7 +644,10 @@ __NEXT_STEP:;
             (byte.arg>>8) & 0xFF,     // KWARGC
             true
         );
-        if(_0 == PY_OP_CALL) DISPATCH_OP_CALL();
+        if(_0 == PY_OP_CALL){
+            frame = top_frame();
+            goto __NEXT_FRAME;
+        }
         PUSH(_0);
     } DISPATCH();
     TARGET(CALL_TP){
@@ -671,7 +679,10 @@ __NEXT_STEP:;
                 true
             );
         }
-        if(_0 == PY_OP_CALL) DISPATCH_OP_CALL();
+        if(_0 == PY_OP_CALL){
+            frame = top_frame();
+            goto __NEXT_FRAME;
+        }
         PUSH(_0);
     } DISPATCH();
     TARGET(RETURN_VALUE){
@@ -931,13 +942,7 @@ __NEXT_STEP:;
     } DISPATCH();
     /*****************************************/
     }
-
 }
-
-#undef DISPATCH
-#undef TARGET
-#undef DISPATCH_OP_CALL
-#undef CEVAL_STEP_CALLBACK
 /**********************************************************************/
             PK_UNREACHABLE()
         }catch(HandledException){
@@ -970,6 +975,6 @@ __NEXT_STEP:;
 
 #undef DISPATCH
 #undef TARGET
-#undef DISPATCH_OP_CALL
+#undef CEVAL_STEP_CALLBACK
 
 } // namespace pkpy

+ 41 - 34
src/modules.cpp

@@ -250,6 +250,43 @@ void add_module_gc(VM* vm){
     vm->bind_func<0>(mod, "collect", PK_LAMBDA(VAR(vm->heap.collect())));
 }
 
+void add_module_enum(VM* vm){
+    PyObject* mod = vm->new_module("enum");
+    CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
+    vm->_exec(code, mod);
+    PyObject* Enum = mod->attr("Enum");
+    vm->_all_types[PK_OBJ_GET(Type, Enum).index].on_end_subclass = \
+        [](VM* vm, PyTypeInfo* new_ti){
+            new_ti->subclass_enabled = false;    // Enum class cannot be subclassed twice
+            NameDict& attr = new_ti->obj->attr();
+            for(auto [k, v]: attr.items()){
+                // wrap every attribute
+                std::string_view k_sv = k.sv();
+                if(k_sv.empty() || k_sv[0] == '_') continue;
+                attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
+            }
+        };
+}
+
+void add_module___builtins(VM* vm){
+    PyObject* mod = vm->new_module("__builtins");
+
+    vm->bind_func<1>(mod, "next", [](VM* vm, ArgsView args){
+        return vm->py_next(args[0]);
+    });
+
+    vm->bind_func<1>(mod, "_enable_instance_dict", [](VM* vm, ArgsView args){
+        PyObject* self = args[0];
+        if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
+        if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
+        self->_enable_instance_dict();
+        return vm->None;
+    });
+}
+
+
+/************************************************/
+#if PK_ENABLE_PROFILER
 struct LineProfilerW;
 struct _LpGuard{
     PK_ALWAYS_PASS_BY_POINTER(_LpGuard)
@@ -317,40 +354,10 @@ void add_module_line_profiler(VM *vm){
     PyObject* mod = vm->new_module("line_profiler");
     LineProfilerW::register_class(vm, mod);
 }
-
-
-void add_module_enum(VM* vm){
-    PyObject* mod = vm->new_module("enum");
-    CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
-    vm->_exec(code, mod);
-    PyObject* Enum = mod->attr("Enum");
-    vm->_all_types[PK_OBJ_GET(Type, Enum).index].on_end_subclass = \
-        [](VM* vm, PyTypeInfo* new_ti){
-            new_ti->subclass_enabled = false;    // Enum class cannot be subclassed twice
-            NameDict& attr = new_ti->obj->attr();
-            for(auto [k, v]: attr.items()){
-                // wrap every attribute
-                std::string_view k_sv = k.sv();
-                if(k_sv.empty() || k_sv[0] == '_') continue;
-                attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
-            }
-        };
-}
-
-void add_module___builtins(VM* vm){
-    PyObject* mod = vm->new_module("__builtins");
-
-    vm->bind_func<1>(mod, "next", [](VM* vm, ArgsView args){
-        return vm->py_next(args[0]);
-    });
-
-    vm->bind_func<1>(mod, "_enable_instance_dict", [](VM* vm, ArgsView args){
-        PyObject* self = args[0];
-        if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
-        if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
-        self->_enable_instance_dict();
-        return vm->None;
-    });
+#else
+void add_module_line_profiler(VM* vm){
+    (void)vm;
 }
+#endif
 
 }   // namespace pkpy

+ 2 - 0
src/pocketpy.cpp

@@ -73,7 +73,9 @@ void init_builtins(VM* _vm) {
 
     // builtin functions
     _vm->bind_func<0>(_vm->builtins, "breakpoint", [](VM* vm, ArgsView args) {
+#if PK_ENABLE_PROFILER
         vm->_next_breakpoint = NextBreakpoint(vm->callstack.size(), vm->top_frame()->curr_lineno(), false);
+#endif
         return vm->None;
     });
 

+ 2 - 0
src/vm.cpp

@@ -1437,6 +1437,7 @@ void NextBreakpoint::_step(VM* vm){
 }
 
 void VM::_breakpoint(){
+#if PK_ENABLE_PROFILER
     _next_breakpoint = NextBreakpoint();
 
     bool show_where = false;
@@ -1569,6 +1570,7 @@ void VM::_breakpoint(){
             continue;
         }
     }
+#endif
 }
 
 }   // namespace pkpy

+ 5 - 1
tests/84_line_profiler.py

@@ -1,4 +1,8 @@
-from line_profiler import LineProfiler
+try:
+    from line_profiler import LineProfiler
+    print('[INFO] line_profiler is used')
+except ImportError:
+    exit(0)
 
 def f2(x):
     a = 0