Skip to content

Commit 74a9e70

Browse files
fix(profiling): correctly detect on-cpu tasks
1 parent 559d111 commit 74a9e70

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

ddtrace/internal/datadog/profiling/stack_v2/echion/echion/long.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <Python.h>
77
#if PY_VERSION_HEX >= 0x030c0000
8+
#define Py_BUILD_CORE
89
#include <internal/pycore_long.h>
910
// Note: Even if use the right PYLONG_BITS_IN_DIGIT that is specified in the
1011
// Python we use to build echion, it can be different from the Python that is

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#pragma once
66

7+
#include <optional>
8+
79
#define PY_SSIZE_T_CLEAN
810
#include <Python.h>
911
#include <weakrefobject.h>
@@ -176,6 +178,7 @@ class TaskInfo
176178

177179
// Information to reconstruct the async stack as best as we can
178180
TaskInfo::Ptr waiter = nullptr;
181+
std::optional<bool> is_on_cpu_ = std::nullopt;
179182

180183
[[nodiscard]] static Result<TaskInfo::Ptr> create(TaskObj*);
181184
TaskInfo(PyObject* origin, PyObject* loop, GenInfo::Ptr coro, StringTable::Key name, TaskInfo::Ptr waiter)
@@ -189,6 +192,25 @@ class TaskInfo
189192

190193
[[nodiscard]] static Result<TaskInfo::Ptr> current(PyObject*);
191194
inline size_t unwind(FrameStack&);
195+
196+
// Check if any coroutine in the chain is currently running (on CPU)
197+
inline bool is_on_cpu()
198+
{
199+
if (is_on_cpu_.has_value()) {
200+
return *is_on_cpu_;
201+
}
202+
203+
for (auto coroutine = this->coro.get(); coroutine != nullptr; coroutine = coroutine->await.get())
204+
{
205+
if (coroutine->is_running) {
206+
is_on_cpu_ = true;
207+
return true;
208+
}
209+
}
210+
211+
is_on_cpu_.emplace(false);
212+
return false;
213+
}
192214
};
193215

194216
inline std::unordered_map<PyObject*, PyObject*> task_link_map;

ddtrace/internal/datadog/profiling/stack_v2/echion/echion/threads.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,19 @@ ThreadInfo::unwind_tasks()
252252
}
253253
}
254254

255+
// Only one Task can be on CPU at a time.
256+
// Since determining if a task is on CPU is somewhat costly, we
257+
// stop checking if Tasks are on CPU after seeing the first one.
258+
bool on_cpu_task_seen = false;
255259
for (auto& leaf_task : leaf_tasks) {
256-
bool on_cpu = leaf_task.get().coro->is_running;
260+
bool on_cpu = false;
261+
if (!on_cpu_task_seen) {
262+
on_cpu = leaf_task.get().is_on_cpu();
263+
if (on_cpu) {
264+
on_cpu_task_seen = true;
265+
}
266+
}
267+
257268
auto stack_info = std::make_unique<StackInfo>(leaf_task.get().name, on_cpu);
258269
auto& stack = stack_info->stack;
259270
for (auto current_task = leaf_task;;) {

0 commit comments

Comments
 (0)