https://github.com/python/cpython/commit/9c14ed06188aa4d462cd0fc4218c6023f9bf03cb
commit: 9c14ed06188aa4d462cd0fc4218c6023f9bf03cb
branch: main
author: Tian Gao <[email protected]>
committer: markshannon <[email protected]>
date: 2024-05-03T19:49:24+01:00
summary:

gh-107674: Improve performance of `sys.settrace` (GH-117133)

* Check tracing in RESUME_CHECK

* Only change to RESUME_CHECK if not tracing

files:
A Misc/NEWS.d/next/Core and 
Builtins/2024-02-04-07-45-29.gh-issue-107674.q8mCmi.rst
M Python/bytecodes.c
M Python/ceval.c
M Python/ceval_macros.h
M Python/executor_cases.c.h
M Python/generated_cases.c.h
M Python/instrumentation.c

diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2024-02-04-07-45-29.gh-issue-107674.q8mCmi.rst b/Misc/NEWS.d/next/Core 
and Builtins/2024-02-04-07-45-29.gh-issue-107674.q8mCmi.rst
new file mode 100644
index 00000000000000..f9b96788bfad94
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2024-02-04-07-45-29.gh-issue-107674.q8mCmi.rst 
@@ -0,0 +1 @@
+Improved the performance of :func:`sys.settrace` significantly
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 9769cfe68aaeba..e8383eda6a9d49 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -148,20 +148,18 @@ dummy_func(
 
         tier1 inst(RESUME, (--)) {
             assert(frame == tstate->current_frame);
-            uintptr_t global_version =
-                _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
-                ~_PY_EVAL_EVENTS_MASK;
-            PyCodeObject *code = _PyFrame_GetCode(frame);
-            uintptr_t code_version = 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(code->_co_instrumentation_version);
-            assert((code_version & 255) == 0);
-            if (code_version != global_version) {
-                int err = _Py_Instrument(code, tstate->interp);
-                ERROR_IF(err, error);
-                next_instr = this_instr;
-            }
-            else {
-                if ((oparg & RESUME_OPARG_LOCATION_MASK) < 
RESUME_AFTER_YIELD_FROM) {
-                    CHECK_EVAL_BREAKER();
+            if (tstate->tracing == 0) {
+                uintptr_t global_version =
+                    _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
+                    ~_PY_EVAL_EVENTS_MASK;
+                PyCodeObject* code = _PyFrame_GetCode(frame);
+                uintptr_t code_version = 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(code->_co_instrumentation_version);
+                assert((code_version & 255) == 0);
+                if (code_version != global_version) {
+                    int err = _Py_Instrument(_PyFrame_GetCode(frame), 
tstate->interp);
+                    ERROR_IF(err, error);
+                    next_instr = this_instr;
+                    DISPATCH();
                 }
                 assert(this_instr->op.code == RESUME ||
                        this_instr->op.code == RESUME_CHECK ||
@@ -173,6 +171,9 @@ dummy_func(
                     #endif  /* ENABLE_SPECIALIZATION */
                 }
             }
+            if ((oparg & RESUME_OPARG_LOCATION_MASK) < 
RESUME_AFTER_YIELD_FROM) {
+                CHECK_EVAL_BREAKER();
+            }
         }
 
         inst(RESUME_CHECK, (--)) {
@@ -189,7 +190,7 @@ dummy_func(
         inst(INSTRUMENTED_RESUME, (--)) {
             uintptr_t global_version = 
_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK;
             uintptr_t code_version = 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version);
-            if (code_version != global_version) {
+            if (code_version != global_version && tstate->tracing == 0) {
                 if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) {
                     ERROR_NO_POP();
                 }
@@ -4284,7 +4285,7 @@ dummy_func(
 #endif
             uintptr_t eval_breaker = 
_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
             DEOPT_IF(eval_breaker & _PY_EVAL_EVENTS_MASK);
-            assert(eval_breaker == 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
+            assert(tstate->tracing || eval_breaker == 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
         }
 
 // END BYTECODES //
diff --git a/Python/ceval.c b/Python/ceval.c
index 59498bc826e941..118746909902f3 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -808,17 +808,23 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, 
_PyInterpreterFrame *frame, int
     {
         _Py_CODEUNIT *prev = frame->instr_ptr;
         _Py_CODEUNIT *here = frame->instr_ptr = next_instr;
-        _PyFrame_SetStackPointer(frame, stack_pointer);
-        int original_opcode = _Py_call_instrumentation_line(
-                tstate, frame, here, prev);
-        stack_pointer = _PyFrame_GetStackPointer(frame);
-        if (original_opcode < 0) {
-            next_instr = here+1;
-            goto error;
-        }
-        next_instr = frame->instr_ptr;
-        if (next_instr != here) {
-            DISPATCH();
+        int original_opcode = 0;
+        if (tstate->tracing) {
+            PyCodeObject *code = _PyFrame_GetCode(frame);
+            original_opcode = code->_co_monitoring->lines[(int)(here - 
_PyCode_CODE(code))].original_opcode;
+        } else {
+            _PyFrame_SetStackPointer(frame, stack_pointer);
+            original_opcode = _Py_call_instrumentation_line(
+                    tstate, frame, here, prev);
+            stack_pointer = _PyFrame_GetStackPointer(frame);
+            if (original_opcode < 0) {
+                next_instr = here+1;
+                goto error;
+            }
+            next_instr = frame->instr_ptr;
+            if (next_instr != here) {
+                DISPATCH();
+            }
         }
         if (_PyOpcode_Caches[original_opcode]) {
             _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1);
diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h
index c88a07c1f5e951..50941e4ec473e8 100644
--- a/Python/ceval_macros.h
+++ b/Python/ceval_macros.h
@@ -358,12 +358,16 @@ do { \
 // for an exception handler, displaying the traceback, and so on
 #define INSTRUMENTED_JUMP(src, dest, event) \
 do { \
-    _PyFrame_SetStackPointer(frame, stack_pointer); \
-    next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, 
dest); \
-    stack_pointer = _PyFrame_GetStackPointer(frame); \
-    if (next_instr == NULL) { \
-        next_instr = (dest)+1; \
-        goto error; \
+    if (tstate->tracing) {\
+        next_instr = dest; \
+    } else { \
+        _PyFrame_SetStackPointer(frame, stack_pointer); \
+        next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, 
dest); \
+        stack_pointer = _PyFrame_GetStackPointer(frame); \
+        if (next_instr == NULL) { \
+            next_instr = (dest)+1; \
+            goto error; \
+        } \
     } \
 } while (0);
 
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 03db9b623cbd86..c3ee6e9039c900 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -4346,7 +4346,7 @@
                 UOP_STAT_INC(uopcode, miss);
                 JUMP_TO_JUMP_TARGET();
             }
-            assert(eval_breaker == 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
+            assert(tstate->tracing || eval_breaker == 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
             break;
         }
 
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 2a0f268ce6ed54..800d19229e3d6a 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -3292,7 +3292,7 @@
             INSTRUCTION_STATS(INSTRUMENTED_RESUME);
             uintptr_t global_version = 
_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK;
             uintptr_t code_version = 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version);
-            if (code_version != global_version) {
+            if (code_version != global_version && tstate->tracing == 0) {
                 if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) {
                     goto error;
                 }
@@ -4948,20 +4948,18 @@
             _Py_CODEUNIT *this_instr = next_instr - 1;
             (void)this_instr;
             assert(frame == tstate->current_frame);
-            uintptr_t global_version =
-            _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
-            ~_PY_EVAL_EVENTS_MASK;
-            PyCodeObject *code = _PyFrame_GetCode(frame);
-            uintptr_t code_version = 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(code->_co_instrumentation_version);
-            assert((code_version & 255) == 0);
-            if (code_version != global_version) {
-                int err = _Py_Instrument(code, tstate->interp);
-                if (err) goto error;
-                next_instr = this_instr;
-            }
-            else {
-                if ((oparg & RESUME_OPARG_LOCATION_MASK) < 
RESUME_AFTER_YIELD_FROM) {
-                    CHECK_EVAL_BREAKER();
+            if (tstate->tracing == 0) {
+                uintptr_t global_version =
+                _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
+                ~_PY_EVAL_EVENTS_MASK;
+                PyCodeObject* code = _PyFrame_GetCode(frame);
+                uintptr_t code_version = 
FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(code->_co_instrumentation_version);
+                assert((code_version & 255) == 0);
+                if (code_version != global_version) {
+                    int err = _Py_Instrument(_PyFrame_GetCode(frame), 
tstate->interp);
+                    if (err) goto error;
+                    next_instr = this_instr;
+                    DISPATCH();
                 }
                 assert(this_instr->op.code == RESUME ||
                        this_instr->op.code == RESUME_CHECK ||
@@ -4973,6 +4971,9 @@
                     #endif  /* ENABLE_SPECIALIZATION */
                 }
             }
+            if ((oparg & RESUME_OPARG_LOCATION_MASK) < 
RESUME_AFTER_YIELD_FROM) {
+                CHECK_EVAL_BREAKER();
+            }
             DISPATCH();
         }
 
diff --git a/Python/instrumentation.c b/Python/instrumentation.c
index 5614f4867a390d..8085d7335fe21a 100644
--- a/Python/instrumentation.c
+++ b/Python/instrumentation.c
@@ -1217,15 +1217,13 @@ int
 _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* 
frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev)
 {
     PyCodeObject *code = _PyFrame_GetCode(frame);
+    assert(tstate->tracing == 0);
     assert(is_version_up_to_date(code, tstate->interp));
     assert(instrumentation_cross_checks(tstate->interp, code));
     int i = (int)(instr - _PyCode_CODE(code));
 
     _PyCoMonitoringData *monitoring = code->_co_monitoring;
     _PyCoLineInstrumentationData *line_data = &monitoring->lines[i];
-    if (tstate->tracing) {
-        goto done;
-    }
     PyInterpreterState *interp = tstate->interp;
     int8_t line_delta = line_data->line_delta;
     int line = 0;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to