diff --git a/ddtrace/internal/datadog/profiling/stack/echion/echion/tasks.h b/ddtrace/internal/datadog/profiling/stack/echion/echion/tasks.h index daa45dd4c3b..27a4e032746 100644 --- a/ddtrace/internal/datadog/profiling/stack/echion/echion/tasks.h +++ b/ddtrace/internal/datadog/profiling/stack/echion/echion/tasks.h @@ -183,11 +183,19 @@ class TaskInfo typedef std::unique_ptr Ptr; typedef std::reference_wrapper Ref; + // The address of the Task PyObject* the TaskInfo represents PyObject* origin = NULL; + + // The address of the asyncio Event Loop PyObject* the Task is running on PyObject* loop = NULL; StringTable::Key name; + + // Whether the Task's coroutine (or a coroutine it awaits, transitively) is currently running (on CPU). + // This will not be true if the Task is currently awaiting another Task, and this other Task is on CPU. bool is_on_cpu = false; + + // The Task's "root" coroutine GenInfo::Ptr coro = nullptr; // Information to reconstruct the async stack as best as we can @@ -289,14 +297,15 @@ inline Result TaskInfo::unwind(FrameStack& stack) { // TODO: Check for running task. + uint64_t c1 = 0x1111111111111111ULL; std::stack coro_frames; + uint64_t c2 = 0x2222222222222222ULL; // Unwind the coro chain // Detect cycles in the await chain to prevent infinite loops. // This can happen if the Profiler samples during as the Task is running, // or due to memory corruption/race conditions when reading coroutine pointers. std::unordered_set seen_coros; - std::unordered_set pure_coro_frames; for (auto py_coro = this->coro.get(); py_coro != NULL; py_coro = py_coro->await.get()) { if (seen_coros.find(py_coro) != seen_coros.end()) { break; @@ -304,19 +313,56 @@ TaskInfo::unwind(FrameStack& stack) seen_coros.insert(py_coro); - if (py_coro->frame != NULL) { - coro_frames.push(py_coro->frame); + auto py_coro_frame = py_coro->frame; + if (py_coro_frame != NULL) { + // Inserting only non-NULL frames + coro_frames.push(py_coro_frame); + // if (coro_frames.top() == nullptr) { + // std::cerr << "Pushed a non-null frame to the stack, but the top is null." << std::endl; + // std::abort(); + // } } } + if (c1 != 0x1111111111111111ULL) { + std::cerr << "c1 is not 0x1111111111111111ULL. This should not happen." << std::endl; + std::abort(); + } + if (c2 != 0x2222222222222222ULL) { + std::cerr << "c2 is not 0x2222222222222222ULL. This should not happen." << std::endl; + std::abort(); + } + // Total number of frames added to the Stack size_t count = 0; - // Unwind the coro frames + // Unwind the coro frames (iterate in reverse since we pushed in await-chain order) + size_t stack_index = 0; while (!coro_frames.empty()) { PyObject* frame = coro_frames.top(); + + // if (frame == nullptr) { + // // THIS ACTUALLY HAPPENS, IT SHOULD NOT. + // std::cerr << "Received a nullptr frame from the coroutine chain (before pop). This should not happen." + // << std::endl; + // std::abort(); + // } + coro_frames.pop(); + // if (frame == nullptr) { + // // THIS ACTUALLY HAPPENS, IT SHOULD NOT. + // std::cerr << "Received a nullptr frame from the coroutine chain. This should not happen." << std::endl; + // std::abort(); + // } + + if (frame == nullptr) { + std::cerr << "Received a nullptr frame from the coroutine chain at index " << stack_index + << ". This should not happen." << std::endl; + std::abort(); + } + stack_index++; + auto new_frames = unwind_frame(frame, stack); // If we failed to unwind the Frame, stop unwinding the coroutine chain; otherwise we could diff --git a/setup.py b/setup.py index 4e08266b6b9..c3098a7aa38 100644 --- a/setup.py +++ b/setup.py @@ -1194,6 +1194,11 @@ def get_exts_for(name): STACK_DIR / ".." / "cmake", STACK_DIR / ".." / "dd_wrapper", ], + cmake_args=[ + "-DCMAKE_C_FLAGS=-fno-strict-aliasing -O1", + "-DCMAKE_CXX_FLAGS=-fno-strict-aliasing -O1", + "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF", + ], optional=False, ), )