Skip to content

Commit 6bc6ff1

Browse files
authored
fix(profiler): version gate python 3.11 changes to stack collector (#4448)
From #4125, two sections in the stack collector were modified to reflect Python 3.11 changes. However, those changes are not the exact same logic as the former code, including version gating and exception representation. I'm specifically applying these changes only if Python 3.11 or higher are being run. Otherwise, it is being reverted to what it was prior to #4125. While I'm unsure what is exactly causing the issue, we saw an issue (only when the profiler was activated) when running dogweb CI where tests involving sqlalchemy failed on setup with sessions becoming immediately inactive before any queries were run. Furthermore, we saw failures in asyncpg framework tests and major memory/CPU usage spikes when #4125 was merged into 1.x, both of which went away with this fix.
1 parent 61f0177 commit 6bc6ff1

File tree

1 file changed

+16
-12
lines changed

1 file changed

+16
-12
lines changed

ddtrace/profiling/collector/stack.pyx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -240,22 +240,26 @@ cdef collect_threads(thread_id_ignore_list, thread_time, thread_span_links) with
240240
tstate = PyInterpreterState_ThreadHead(interp)
241241
while tstate:
242242
# The frame can be NULL
243-
# Python 3.9 added helper function to public C API to access PyFrameObject from tstate,
244243
# Python 3.11 moved PyFrameObject to internal C API and cannot be directly accessed from tstate
245-
IF PY_MINOR_VERSION >= 9:
244+
IF PY_MINOR_VERSION >= 11:
246245
frame = PyThreadState_GetFrame(tstate)
246+
if frame:
247+
running_threads[tstate.thread_id] = <object>frame
248+
exc_info = _PyErr_GetTopmostException(tstate)
249+
if exc_info and exc_info.exc_value:
250+
# Python 3.11 removed exc_type, exc_traceback from exception representations,
251+
# can instead derive exc_type and exc_traceback from remaining exc_value field
252+
exc_type = Py_TYPE(exc_info.exc_value)
253+
exc_tb = PyException_GetTraceback(exc_info.exc_value)
254+
if exc_type and exc_tb:
255+
current_exceptions[tstate.thread_id] = (<object>exc_type, <object>exc_tb)
247256
ELSE:
248257
frame = tstate.frame
249-
if frame:
250-
running_threads[tstate.thread_id] = <object>frame
251-
exc_info = _PyErr_GetTopmostException(tstate)
252-
if exc_info and exc_info.exc_value:
253-
# Python 3.11 removed exc_type, exc_traceback from exception representations, can instead
254-
# derive exc_type and exc_traceback from remaining exc_value field
255-
exc_type = Py_TYPE(exc_info.exc_value)
256-
exc_tb = PyException_GetTraceback(exc_info.exc_value)
257-
if exc_type and exc_tb:
258-
current_exceptions[tstate.thread_id] = (<object>exc_type, <object>exc_tb)
258+
if frame:
259+
running_threads[tstate.thread_id] = <object>frame
260+
exc_info = _PyErr_GetTopmostException(tstate)
261+
if exc_info and exc_info.exc_type and exc_info.exc_traceback:
262+
current_exceptions[tstate.thread_id] = (<object>exc_info.exc_type, <object>exc_info.exc_traceback)
259263
tstate = PyThreadState_Next(tstate)
260264

261265
interp = PyInterpreterState_Next(interp)

0 commit comments

Comments
 (0)