https://github.com/python/cpython/commit/55b230333fc86137271d9e253abb3e4b61c2978f
commit: 55b230333fc86137271d9e253abb3e4b61c2978f
branch: 3.12
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: Yhg1s <tho...@python.org>
date: 2025-04-06T19:48:53Z
summary:

[3.12] GH-107674: Avoid allocating boxed ints for `sys.settrace` line events 
(GH-107780) (#107841)

GH-107674: Avoid allocating boxed ints for `sys.settrace` line events 
(GH-107780)
(cherry picked from commit 37d8b904f8b5b660f556597b21c0933b841d18de)

Co-authored-by: Mark Shannon <m...@hotpy.org>

files:
A Misc/NEWS.d/next/Core and 
Builtins/2023-08-05-04-47-18.gh-issue-107674.0sYhR2.rst
M Python/instrumentation.c

diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2023-08-05-04-47-18.gh-issue-107674.0sYhR2.rst b/Misc/NEWS.d/next/Core 
and Builtins/2023-08-05-04-47-18.gh-issue-107674.0sYhR2.rst
new file mode 100644
index 00000000000000..acfbf1fa2adf2c
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2023-08-05-04-47-18.gh-issue-107674.0sYhR2.rst 
@@ -0,0 +1 @@
+Fixed performance regression in ``sys.settrace``.
diff --git a/Python/instrumentation.c b/Python/instrumentation.c
index a6ff7a8a98506c..2f94f103e43186 100644
--- a/Python/instrumentation.c
+++ b/Python/instrumentation.c
@@ -962,7 +962,7 @@ call_instrumentation_vector(
     /* Offset visible to user should be the offset in bytes, as that is the
      * convention for APIs involving code offsets. */
     int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
-    PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset);
+    PyObject *offset_obj = PyLong_FromLong(bytes_offset);
     if (offset_obj == NULL) {
         return -1;
     }
@@ -1141,14 +1141,46 @@ _Py_call_instrumentation_line(PyThreadState *tstate, 
_PyInterpreterFrame* frame,
         (interp->monitors.tools[PY_MONITORING_EVENT_LINE] |
          code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE]
         );
-    PyObject *line_obj = PyLong_FromSsize_t(line);
+    /* Special case sys.settrace to avoid boxing the line number,
+     * only to immediately unbox it. */
+    if (tools & (1 << PY_MONITORING_SYS_TRACE_ID)) {
+        if (tstate->c_tracefunc != NULL && line >= 0) {
+            PyFrameObject *frame_obj = _PyFrame_GetFrameObject(frame);
+            if (frame_obj == NULL) {
+                return -1;
+            }
+            if (frame_obj->f_trace_lines) {
+                /* Need to set tracing and what_event as if using
+                 * the instrumentation call. */
+                int old_what = tstate->what_event;
+                tstate->what_event = PY_MONITORING_EVENT_LINE;
+                tstate->tracing++;
+                /* Call c_tracefunc directly, having set the line number. */
+                Py_INCREF(frame_obj);
+                frame_obj->f_lineno = line;
+                int err = tstate->c_tracefunc(tstate->c_traceobj, frame_obj, 
PyTrace_LINE, Py_None);
+                frame_obj->f_lineno = 0;
+                tstate->tracing--;
+                tstate->what_event = old_what;
+                Py_DECREF(frame_obj);
+                if (err) {
+                    return -1;
+                }
+            }
+        }
+        tools &= (255 - (1 << PY_MONITORING_SYS_TRACE_ID));
+    }
+    if (tools == 0) {
+        goto done;
+    }
+    PyObject *line_obj = PyLong_FromLong(line);
     if (line_obj == NULL) {
         return -1;
     }
     PyObject *args[3] = { NULL, (PyObject *)code, line_obj };
-    while (tools) {
+    do {
         int tool = most_significant_bit(tools);
-        assert(tool >= 0 && tool < 8);
+        assert(tool >= 0 && tool < PY_MONITORING_SYS_PROFILE_ID);
         assert(tools & (1 << tool));
         tools &= ~(1 << tool);
         int res = call_one_instrument(interp, tstate, &args[1],
@@ -1166,7 +1198,7 @@ _Py_call_instrumentation_line(PyThreadState *tstate, 
_PyInterpreterFrame* frame,
             /* DISABLE  */
             remove_line_tools(code, i, 1 << tool);
         }
-    }
+    } while (tools);
     Py_DECREF(line_obj);
     uint8_t original_opcode;
 done:
@@ -1197,7 +1229,7 @@ _Py_call_instrumentation_instruction(PyThreadState 
*tstate, _PyInterpreterFrame*
          
code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]
         );
     int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
-    PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset);
+    PyObject *offset_obj = PyLong_FromLong(bytes_offset);
     if (offset_obj == NULL) {
         return -1;
     }

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to