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

This commit is contained in:
Tian Gao 2024-02-28 07:21:42 -08:00 committed by GitHub
parent 9578288a3e
commit 0a61e23700
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 64 additions and 53 deletions

View File

@ -0,0 +1 @@
Improved the performance of :func:`sys.settrace` significantly

View File

@ -143,22 +143,23 @@ dummy_func(
tier1 inst(RESUME, (--)) { tier1 inst(RESUME, (--)) {
assert(frame == tstate->current_frame); assert(frame == tstate->current_frame);
uintptr_t global_version = if (tstate->tracing == 0) {
_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & uintptr_t global_version =
~_PY_EVAL_EVENTS_MASK; _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version; ~_PY_EVAL_EVENTS_MASK;
assert((code_version & 255) == 0); uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
if (code_version != global_version) { assert((code_version & 255) == 0);
int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); if (code_version != global_version) {
ERROR_IF(err, error); int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
next_instr = this_instr; ERROR_IF(err, error);
} next_instr = this_instr;
else { DISPATCH();
if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) {
CHECK_EVAL_BREAKER();
} }
this_instr->op.code = RESUME_CHECK;
} }
if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) {
CHECK_EVAL_BREAKER();
}
this_instr->op.code = RESUME_CHECK;
} }
inst(RESUME_CHECK, (--)) { inst(RESUME_CHECK, (--)) {
@ -169,13 +170,13 @@ dummy_func(
uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version; uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
assert((version & _PY_EVAL_EVENTS_MASK) == 0); assert((version & _PY_EVAL_EVENTS_MASK) == 0);
DEOPT_IF(eval_breaker != version); DEOPT_IF(eval_breaker != version && tstate->tracing == 0);
} }
inst(INSTRUMENTED_RESUME, (--)) { inst(INSTRUMENTED_RESUME, (--)) {
uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK; uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK;
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version; uintptr_t code_version = _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)) { if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) {
GOTO_ERROR(error); GOTO_ERROR(error);
} }

View File

@ -800,17 +800,23 @@ resume_frame:
{ {
_Py_CODEUNIT *prev = frame->instr_ptr; _Py_CODEUNIT *prev = frame->instr_ptr;
_Py_CODEUNIT *here = frame->instr_ptr = next_instr; _Py_CODEUNIT *here = frame->instr_ptr = next_instr;
_PyFrame_SetStackPointer(frame, stack_pointer); int original_opcode = 0;
int original_opcode = _Py_call_instrumentation_line( if (tstate->tracing) {
tstate, frame, here, prev); PyCodeObject *code = _PyFrame_GetCode(frame);
stack_pointer = _PyFrame_GetStackPointer(frame); original_opcode = code->_co_monitoring->lines[(int)(here - _PyCode_CODE(code))].original_opcode;
if (original_opcode < 0) { } else {
next_instr = here+1; _PyFrame_SetStackPointer(frame, stack_pointer);
goto error; original_opcode = _Py_call_instrumentation_line(
} tstate, frame, here, prev);
next_instr = frame->instr_ptr; stack_pointer = _PyFrame_GetStackPointer(frame);
if (next_instr != here) { if (original_opcode < 0) {
DISPATCH(); next_instr = here+1;
goto error;
}
next_instr = frame->instr_ptr;
if (next_instr != here) {
DISPATCH();
}
} }
if (_PyOpcode_Caches[original_opcode]) { if (_PyOpcode_Caches[original_opcode]) {
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1);

View File

@ -339,12 +339,16 @@ do { \
// for an exception handler, displaying the traceback, and so on // for an exception handler, displaying the traceback, and so on
#define INSTRUMENTED_JUMP(src, dest, event) \ #define INSTRUMENTED_JUMP(src, dest, event) \
do { \ do { \
_PyFrame_SetStackPointer(frame, stack_pointer); \ if (tstate->tracing) {\
next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \ next_instr = dest; \
stack_pointer = _PyFrame_GetStackPointer(frame); \ } else { \
if (next_instr == NULL) { \ _PyFrame_SetStackPointer(frame, stack_pointer); \
next_instr = (dest)+1; \ next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \
goto error; \ stack_pointer = _PyFrame_GetStackPointer(frame); \
if (next_instr == NULL) { \
next_instr = (dest)+1; \
goto error; \
} \
} \ } \
} while (0); } while (0);

View File

@ -20,7 +20,7 @@
uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version; uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
assert((version & _PY_EVAL_EVENTS_MASK) == 0); assert((version & _PY_EVAL_EVENTS_MASK) == 0);
if (eval_breaker != version) goto deoptimize; if (eval_breaker != version && tstate->tracing == 0) goto deoptimize;
break; break;
} }

View File

@ -3125,7 +3125,7 @@
INSTRUCTION_STATS(INSTRUMENTED_RESUME); INSTRUCTION_STATS(INSTRUMENTED_RESUME);
uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK; uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK;
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version; uintptr_t code_version = _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)) { if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) {
GOTO_ERROR(error); GOTO_ERROR(error);
} }
@ -4780,22 +4780,23 @@
PREDICTED(RESUME); PREDICTED(RESUME);
_Py_CODEUNIT *this_instr = next_instr - 1; _Py_CODEUNIT *this_instr = next_instr - 1;
assert(frame == tstate->current_frame); assert(frame == tstate->current_frame);
uintptr_t global_version = if (tstate->tracing == 0) {
_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & uintptr_t global_version =
~_PY_EVAL_EVENTS_MASK; _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version; ~_PY_EVAL_EVENTS_MASK;
assert((code_version & 255) == 0); uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
if (code_version != global_version) { assert((code_version & 255) == 0);
int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); if (code_version != global_version) {
if (err) goto error; int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
next_instr = this_instr; if (err) goto error;
} next_instr = this_instr;
else { DISPATCH();
if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) {
CHECK_EVAL_BREAKER();
} }
this_instr->op.code = RESUME_CHECK;
} }
if ((oparg & RESUME_OPARG_LOCATION_MASK) < RESUME_AFTER_YIELD_FROM) {
CHECK_EVAL_BREAKER();
}
this_instr->op.code = RESUME_CHECK;
DISPATCH(); DISPATCH();
} }
@ -4811,7 +4812,7 @@
uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version; uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version;
assert((version & _PY_EVAL_EVENTS_MASK) == 0); assert((version & _PY_EVAL_EVENTS_MASK) == 0);
DEOPT_IF(eval_breaker != version, RESUME); DEOPT_IF(eval_breaker != version && tstate->tracing == 0, RESUME);
DISPATCH(); DISPATCH();
} }

View File

@ -1156,15 +1156,13 @@ int
_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev)
{ {
PyCodeObject *code = _PyFrame_GetCode(frame); PyCodeObject *code = _PyFrame_GetCode(frame);
assert(tstate->tracing == 0);
assert(is_version_up_to_date(code, tstate->interp)); assert(is_version_up_to_date(code, tstate->interp));
assert(instrumentation_cross_checks(tstate->interp, code)); assert(instrumentation_cross_checks(tstate->interp, code));
int i = (int)(instr - _PyCode_CODE(code)); int i = (int)(instr - _PyCode_CODE(code));
_PyCoMonitoringData *monitoring = code->_co_monitoring; _PyCoMonitoringData *monitoring = code->_co_monitoring;
_PyCoLineInstrumentationData *line_data = &monitoring->lines[i]; _PyCoLineInstrumentationData *line_data = &monitoring->lines[i];
if (tstate->tracing) {
goto done;
}
PyInterpreterState *interp = tstate->interp; PyInterpreterState *interp = tstate->interp;
int8_t line_delta = line_data->line_delta; int8_t line_delta = line_data->line_delta;
int line = compute_line(code, i, line_delta); int line = compute_line(code, i, line_delta);