Skip to content

Commit 0a61e23

Browse files
gh-107674: Improve performance of sys.settrace (GH-114986)
1 parent 9578288 commit 0a61e23

File tree

7 files changed

+64
-53
lines changed

7 files changed

+64
-53
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improved the performance of :func:`sys.settrace` significantly

Python/bytecodes.c

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -143,22 +143,23 @@ dummy_func(
143143

144144
tier1 inst(RESUME, (--)) {
145145
assert(frame == tstate->current_frame);
146-
uintptr_t global_version =
147-
_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
148-
~_PY_EVAL_EVENTS_MASK;
149-
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
150-
assert((code_version & 255) == 0);
151-
if (code_version != global_version) {
152-
int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
153-
ERROR_IF(err, error);
154-
next_instr = this_instr;
155-
}
156-
else {
157-
if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) {
158-
CHECK_EVAL_BREAKER();
146+
if (tstate->tracing == 0) {
147+
uintptr_t global_version =
148+
_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
149+
~_PY_EVAL_EVENTS_MASK;
150+
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
151+
assert((code_version & 255) == 0);
152+
if (code_version != global_version) {
153+
int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
154+
ERROR_IF(err, error);
155+
next_instr = this_instr;
156+
DISPATCH();
159157
}
160-
this_instr->op.code = RESUME_CHECK;
161158
}
159+
if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) {
160+
CHECK_EVAL_BREAKER();
161+
}
162+
this_instr->op.code = RESUME_CHECK;
162163
}
163164

164165
inst(RESUME_CHECK, (--)) {
@@ -169,13 +170,13 @@ dummy_func(
169170
uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
170171
uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
171172
assert((version & _PY_EVAL_EVENTS_MASK) == 0);
172-
DEOPT_IF(eval_breaker != version);
173+
DEOPT_IF(eval_breaker != version && tstate->tracing == 0);
173174
}
174175

175176
inst(INSTRUMENTED_RESUME, (--)) {
176177
uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK;
177178
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
178-
if (code_version != global_version) {
179+
if (code_version != global_version && tstate->tracing == 0) {
179180
if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) {
180181
GOTO_ERROR(error);
181182
}

Python/ceval.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -800,17 +800,23 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
800800
{
801801
_Py_CODEUNIT *prev = frame->instr_ptr;
802802
_Py_CODEUNIT *here = frame->instr_ptr = next_instr;
803-
_PyFrame_SetStackPointer(frame, stack_pointer);
804-
int original_opcode = _Py_call_instrumentation_line(
805-
tstate, frame, here, prev);
806-
stack_pointer = _PyFrame_GetStackPointer(frame);
807-
if (original_opcode < 0) {
808-
next_instr = here+1;
809-
goto error;
810-
}
811-
next_instr = frame->instr_ptr;
812-
if (next_instr != here) {
813-
DISPATCH();
803+
int original_opcode = 0;
804+
if (tstate->tracing) {
805+
PyCodeObject *code = _PyFrame_GetCode(frame);
806+
original_opcode = code->_co_monitoring->lines[(int)(here - _PyCode_CODE(code))].original_opcode;
807+
} else {
808+
_PyFrame_SetStackPointer(frame, stack_pointer);
809+
original_opcode = _Py_call_instrumentation_line(
810+
tstate, frame, here, prev);
811+
stack_pointer = _PyFrame_GetStackPointer(frame);
812+
if (original_opcode < 0) {
813+
next_instr = here+1;
814+
goto error;
815+
}
816+
next_instr = frame->instr_ptr;
817+
if (next_instr != here) {
818+
DISPATCH();
819+
}
814820
}
815821
if (_PyOpcode_Caches[original_opcode]) {
816822
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1);

Python/ceval_macros.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,12 +339,16 @@ do { \
339339
// for an exception handler, displaying the traceback, and so on
340340
#define INSTRUMENTED_JUMP(src, dest, event) \
341341
do { \
342-
_PyFrame_SetStackPointer(frame, stack_pointer); \
343-
next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \
344-
stack_pointer = _PyFrame_GetStackPointer(frame); \
345-
if (next_instr == NULL) { \
346-
next_instr = (dest)+1; \
347-
goto error; \
342+
if (tstate->tracing) {\
343+
next_instr = dest; \
344+
} else { \
345+
_PyFrame_SetStackPointer(frame, stack_pointer); \
346+
next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \
347+
stack_pointer = _PyFrame_GetStackPointer(frame); \
348+
if (next_instr == NULL) { \
349+
next_instr = (dest)+1; \
350+
goto error; \
351+
} \
348352
} \
349353
} while (0);
350354

Python/executor_cases.c.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 17 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/instrumentation.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,15 +1156,13 @@ int
11561156
_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev)
11571157
{
11581158
PyCodeObject *code = _PyFrame_GetCode(frame);
1159+
assert(tstate->tracing == 0);
11591160
assert(is_version_up_to_date(code, tstate->interp));
11601161
assert(instrumentation_cross_checks(tstate->interp, code));
11611162
int i = (int)(instr - _PyCode_CODE(code));
11621163

11631164
_PyCoMonitoringData *monitoring = code->_co_monitoring;
11641165
_PyCoLineInstrumentationData *line_data = &monitoring->lines[i];
1165-
if (tstate->tracing) {
1166-
goto done;
1167-
}
11681166
PyInterpreterState *interp = tstate->interp;
11691167
int8_t line_delta = line_data->line_delta;
11701168
int line = compute_line(code, i, line_delta);

0 commit comments

Comments
 (0)