diff options
author | Tian Gao <gaogaotiantian@hotmail.com> | 2023-11-03 16:39:50 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-03 16:39:50 (GMT) |
commit | e0afed7e276b6611a2142ec70a0440298d528305 (patch) | |
tree | 9170a4828e2961750e84251115ee5ac91f31f31e /Python | |
parent | 2bc01cc0c72a3d91bdcce09886efa987a90396d9 (diff) | |
download | cpython-e0afed7e276b6611a2142ec70a0440298d528305.zip cpython-e0afed7e276b6611a2142ec70a0440298d528305.tar.gz cpython-e0afed7e276b6611a2142ec70a0440298d528305.tar.bz2 |
gh-103615: Use local events for opcode tracing (GH-109472)
* Use local monitoring for opcode trace
* Remove f_opcode_trace_set
* Add test for setting f_trace_opcodes after settrace
Diffstat (limited to 'Python')
-rw-r--r-- | Python/instrumentation.c | 17 | ||||
-rw-r--r-- | Python/legacy_tracing.c | 52 | ||||
-rw-r--r-- | Python/pystate.c | 2 |
3 files changed, 65 insertions, 6 deletions
diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 9ee1158..35b0e7a 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1833,6 +1833,23 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent return 0; } +int +_PyMonitoring_GetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet *events) +{ + assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (check_tool(interp, tool_id)) { + return -1; + } + if (code->_co_monitoring == NULL) { + *events = 0; + return 0; + } + _Py_LocalMonitors *local = &code->_co_monitoring->local_monitors; + *events = get_local_events(local, tool_id); + return 0; +} + /*[clinic input] module monitoring [clinic start generated code]*/ diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index ddc7271..ccbb3eb 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -117,6 +117,35 @@ sys_profile_call_or_return( Py_RETURN_NONE; } +int +_PyEval_SetOpcodeTrace( + PyFrameObject *frame, + bool enable +) { + assert(frame != NULL); + assert(PyCode_Check(frame->f_frame->f_executable)); + + PyCodeObject *code = (PyCodeObject *)frame->f_frame->f_executable; + _PyMonitoringEventSet events = 0; + + if (_PyMonitoring_GetLocalEvents(code, PY_MONITORING_SYS_TRACE_ID, &events) < 0) { + return -1; + } + + if (enable) { + if (events & (1 << PY_MONITORING_EVENT_INSTRUCTION)) { + return 0; + } + events |= (1 << PY_MONITORING_EVENT_INSTRUCTION); + } else { + if (!(events & (1 << PY_MONITORING_EVENT_INSTRUCTION))) { + return 0; + } + events &= (~(1 << PY_MONITORING_EVENT_INSTRUCTION)); + } + return _PyMonitoring_SetLocalEvents(code, PY_MONITORING_SYS_TRACE_ID, events); +} + static PyObject * call_trace_func(_PyLegacyEventHandler *self, PyObject *arg) { @@ -130,6 +159,12 @@ call_trace_func(_PyLegacyEventHandler *self, PyObject *arg) "Missing frame when calling trace function."); return NULL; } + if (frame->f_trace_opcodes) { + if (_PyEval_SetOpcodeTrace(frame, true) != 0) { + return NULL; + } + } + Py_INCREF(frame); int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, arg); Py_DECREF(frame); @@ -230,11 +265,14 @@ sys_trace_instruction_func( "Missing frame when calling trace function."); return NULL; } - if (!frame->f_trace_opcodes) { + PyThreadState *tstate = _PyThreadState_GET(); + if (!tstate->c_tracefunc || !frame->f_trace_opcodes) { + if (_PyEval_SetOpcodeTrace(frame, false) != 0) { + return NULL; + } Py_RETURN_NONE; } Py_INCREF(frame); - PyThreadState *tstate = _PyThreadState_GET(); int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None); frame->f_lineno = 0; Py_DECREF(frame); @@ -531,9 +569,15 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) (1 << PY_MONITORING_EVENT_PY_UNWIND) | (1 << PY_MONITORING_EVENT_PY_THROW) | (1 << PY_MONITORING_EVENT_STOP_ITERATION) | (1 << PY_MONITORING_EVENT_EXCEPTION_HANDLED); - if (tstate->interp->f_opcode_trace_set) { - events |= (1 << PY_MONITORING_EVENT_INSTRUCTION); + + PyFrameObject* frame = PyEval_GetFrame(); + if (frame->f_trace_opcodes) { + int ret = _PyEval_SetOpcodeTrace(frame, true); + if (ret != 0) { + return ret; + } } } + return _PyMonitoring_SetEvents(PY_MONITORING_SYS_TRACE_ID, events); } diff --git a/Python/pystate.c b/Python/pystate.c index 8970e17..b369a56 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -708,7 +708,6 @@ init_interpreter(PyInterpreterState *interp, /* Fix the self-referential, statically initialized fields. */ interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); } - interp->f_opcode_trace_set = false; interp->_initialized = 1; return _PyStatus_OK(); @@ -958,7 +957,6 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) interp->code_watchers[i] = NULL; } interp->active_code_watchers = 0; - interp->f_opcode_trace_set = false; // XXX Once we have one allocator per interpreter (i.e. // per-interpreter GC) we must ensure that all of the interpreter's // objects have been cleaned up at the point. |