Skip to content

Commit 7d8d876

Browse files
markshannonmiss-islington
authored andcommitted
pythonGH-107674: Avoid allocating boxed ints for sys.settrace line events (pythonGH-107780)
(cherry picked from commit 37d8b90) Co-authored-by: Mark Shannon <mark@hotpy.org>
1 parent 7853c76 commit 7d8d876

2 files changed

Lines changed: 39 additions & 6 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed performance regression in ``sys.settrace``.

Python/instrumentation.c

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ call_instrumentation_vector(
950950
/* Offset visible to user should be the offset in bytes, as that is the
951951
* convention for APIs involving code offsets. */
952952
int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
953-
PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset);
953+
PyObject *offset_obj = PyLong_FromLong(bytes_offset);
954954
if (offset_obj == NULL) {
955955
return -1;
956956
}
@@ -1140,14 +1140,46 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
11401140
(interp->monitors.tools[PY_MONITORING_EVENT_LINE] |
11411141
code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE]
11421142
);
1143-
PyObject *line_obj = PyLong_FromSsize_t(line);
1143+
/* Special case sys.settrace to avoid boxing the line number,
1144+
* only to immediately unbox it. */
1145+
if (tools & (1 << PY_MONITORING_SYS_TRACE_ID)) {
1146+
if (tstate->c_tracefunc != NULL && line >= 0) {
1147+
PyFrameObject *frame_obj = _PyFrame_GetFrameObject(frame);
1148+
if (frame_obj == NULL) {
1149+
return -1;
1150+
}
1151+
if (frame_obj->f_trace_lines) {
1152+
/* Need to set tracing and what_event as if using
1153+
* the instrumentation call. */
1154+
int old_what = tstate->what_event;
1155+
tstate->what_event = PY_MONITORING_EVENT_LINE;
1156+
tstate->tracing++;
1157+
/* Call c_tracefunc directly, having set the line number. */
1158+
Py_INCREF(frame_obj);
1159+
frame_obj->f_lineno = line;
1160+
int err = tstate->c_tracefunc(tstate->c_traceobj, frame_obj, PyTrace_LINE, Py_None);
1161+
frame_obj->f_lineno = 0;
1162+
tstate->tracing--;
1163+
tstate->what_event = old_what;
1164+
Py_DECREF(frame_obj);
1165+
if (err) {
1166+
return -1;
1167+
}
1168+
}
1169+
}
1170+
tools &= (255 - (1 << PY_MONITORING_SYS_TRACE_ID));
1171+
}
1172+
if (tools == 0) {
1173+
goto done;
1174+
}
1175+
PyObject *line_obj = PyLong_FromLong(line);
11441176
if (line_obj == NULL) {
11451177
return -1;
11461178
}
11471179
PyObject *args[3] = { NULL, (PyObject *)code, line_obj };
1148-
while (tools) {
1180+
do {
11491181
int tool = most_significant_bit(tools);
1150-
assert(tool >= 0 && tool < 8);
1182+
assert(tool >= 0 && tool < PY_MONITORING_SYS_PROFILE_ID);
11511183
assert(tools & (1 << tool));
11521184
tools &= ~(1 << tool);
11531185
int res = call_one_instrument(interp, tstate, &args[1],
@@ -1165,7 +1197,7 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
11651197
/* DISABLE */
11661198
remove_line_tools(code, i, 1 << tool);
11671199
}
1168-
}
1200+
} while (tools);
11691201
Py_DECREF(line_obj);
11701202
done:
11711203
assert(original_opcode != 0);
@@ -1194,7 +1226,7 @@ _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame*
11941226
code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]
11951227
);
11961228
int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
1197-
PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset);
1229+
PyObject *offset_obj = PyLong_FromLong(bytes_offset);
11981230
if (offset_obj == NULL) {
11991231
return -1;
12001232
}

0 commit comments

Comments
 (0)