Skip to content

Commit 53d9d1b

Browse files
fix(profiling): use official PyGen_yf from CPython 3.13
1 parent 61061a2 commit 53d9d1b

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

ddtrace/internal/datadog/profiling/stack_v2/echion/echion/cpython/tasks.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,37 @@ extern "C"
171171
#define RESUME_QUICK INSTRUMENTED_RESUME
172172
#endif
173173

174-
#if PY_VERSION_HEX >= 0x030b0000
174+
#if PY_VERSION_HEX >= 0x030d0000
175+
176+
inline PyObject* PyGen_yf(PyGenObject* gen, PyObject* frame_addr)
177+
{
178+
if (gen->gi_frame_state != FRAME_SUSPENDED_YIELD_FROM) {
179+
return nullptr;
180+
}
181+
182+
_PyInterpreterFrame frame;
183+
if (copy_type(frame_addr, frame)) {
184+
return nullptr;
185+
}
186+
187+
if (frame.stacktop < 1 || frame.stacktop > (1 << 20)) {
188+
return nullptr;
189+
}
190+
191+
auto localsplus = std::make_unique<PyObject*[]>(frame.stacktop);
192+
193+
// Calculate the remote address of the localsplus array
194+
auto remote_localsplus = reinterpret_cast<PyObject**>(reinterpret_cast<uintptr_t>(frame_addr) +
195+
offsetof(_PyInterpreterFrame, localsplus));
196+
if (copy_generic(remote_localsplus, localsplus.get(), (frame.stacktop) * sizeof(PyObject*))) {
197+
return nullptr;
198+
}
199+
200+
return localsplus[frame.stacktop - 1];
201+
}
202+
203+
#elif PY_VERSION_HEX >= 0x030b0000
204+
175205
inline PyObject* PyGen_yf(PyGenObject* gen, PyObject* frame_addr)
176206
{
177207
PyObject* yf = NULL;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fixes:
2+
- |
3+
profiling: This improves stack unwinding for asyncio workloads running Python 3.13+ by replicating
4+
the official PyGen_yf function from CPython 3.13. Previously, the sampler would use the version from an older
5+
version of CPython, which could lead to incomplete asyncio stacks.

0 commit comments

Comments
 (0)