Skip to content

refactor(profiling): replace bytecode wrapping with sys.monitoring (PROF-14200) - #18389

Closed
vlad-scherbich wants to merge 3 commits into
vlad/ddtracepy-315-profiling-onlyfrom
vlad/ddtracepy-315-profiling-asyncio-monitoring
Closed

refactor(profiling): replace bytecode wrapping with sys.monitoring (PROF-14200)#18389
vlad-scherbich wants to merge 3 commits into
vlad/ddtracepy-315-profiling-onlyfrom
vlad/ddtracepy-315-profiling-asyncio-monitoring

Conversation

@vlad-scherbich

@vlad-scherbich vlad-scherbich commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

← Prev PR: #17624

3.14 vs 3.15 (table view)

3.14 vs 3.15 (flame graph): python

3.14 vs 3.15 (flame graph): native

Description

Refactors ddtrace/profiling/_asyncio.py to replace the functools.partial + wrap() monkey-patching mechanism with direct attribute replacement throughout, and introduces a sys.monitoring PY_RETURN hook layer on Python 3.15+ for task-creation hooks.

Context: The existing wrap() approach intercepts calls by replacing a function in its owning namespace with a partial-applied closure. Direct attribute replacement (_original = f; def _patched(...): ...; module.f = _patched) achieves identical runtime behavior with less indirection and no dependency on get_argument_value.

sys.monitoring for task-creation hooks (Python 3.15+):
asyncio.create_task and TaskGroup.create_task return the new Task object, which we need in order to call stack.link_tasks(parent, task). sys.monitoring CALL/PY_START events don't expose callee arguments, but PY_RETURN gives us the return value directly — making it a natural fit for these two sites. On older Python the same sites fall back to standard attribute replacement.

Changes

  • set_event_loop, _GatheringFuture.__init__, _wait, as_completed (asyncio) and new_event_loop, set_event_loop (uvloop): converted from wrap() closures to direct _original_X / _patched_X attribute replacement
  • create_task, TaskGroup.create_task: sys.monitoring PY_RETURN hook on Python 3.15+; direct attribute replacement on older versions
  • New helpers: _register_return_hook(), _unregister_all_return_hooks(), _py_return_dispatch(), _py_return_handlers dict, _monitoring_tool_id
  • Drops functools.partial, get_argument_value, and wrap imports
  • sys.monitoring path is gated at >= (3, 15) — not rolled out to 3.12–3.14 yet (see TODO in code for follow-up)

Testing

CI: tests/profiling/collector/test_asyncio.py, tests/profiling/test_scheduler.py

Manual A/B validation

py3.14 (baseline) vs py3.15 on movies-ab service — covers experiment window from branch start to present:

Risks

Low. The behavioral contract is unchanged — the same events trigger the same link_tasks / weak_link_tasks / track_asyncio_loop calls. The main risk is a subtle argument-passing error in the direct-replacement wrappers; these are covered by the asyncio profiling tests.

Additional Notes

  • sys.monitoring tool IDs 4–5 are used (free custom slots; 0–3 are reserved for debugger, coverage, profiler, optimizer). Tool 5 is tried first to minimize conflicts.
  • One-line fix to _memalloc_tb.cpp is bundled in this branch.

@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Pipelines  Tests

Fix all issues with BitsAI

⚠️ Warnings

🚦 16 Pipeline jobs failed

Changelog | Validate changelog   View in Datadog   GitHub Actions

DataDog/apm-reliability/dd-trace-py | build linux cp315: [amd64, cp315-cp315, v85383325-751efc0-musllinux_1_2_x86_64]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-py | build linux cp315: [amd64, cp315-cp315, v85383392-751efc0-manylinux2014_x86_64]   View in Datadog   GitLab

View all 16 failed jobs.

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 670d7db | Docs | Datadog PR Page | Give us feedback!

@pr-commenter

pr-commenter Bot commented Jun 1, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-06-01 21:06:16

Comparing candidate commit 0af646f in PR branch vlad/ddtracepy-315-profiling-asyncio-monitoring with baseline commit 653e008 in branch main.

Found 0 performance improvements and 3 performance regressions! Performance is the same for 597 metrics, 9 unstable metrics.

scenario:iastaspects-stringio_aspect

  • 🟥 execution_time [+569.224µs; +613.534µs] or [+14.520%; +15.651%]

scenario:iastaspectsospath-ospathbasename_aspect

  • 🟥 execution_time [+107.851µs; +112.955µs] or [+24.894%; +26.072%]

scenario:span-start

  • 🟥 execution_time [+1.358ms; +1.569ms] or [+8.564%; +9.893%]

@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-asyncio-monitoring branch from 0af646f to e5a713d Compare June 2, 2026 20:50
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Jun 2, 2026

Copy link
Copy Markdown

Codeowners resolved as

ddtrace/profiling/_asyncio.py                                           @DataDog/profiling-python
ddtrace/profiling/collector/_memalloc_tb.cpp                            @DataDog/profiling-python

@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-only branch 2 times, most recently from fb4efb9 to 9564e7a Compare June 3, 2026 14:32
@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-asyncio-monitoring branch from e5a713d to 49b7af0 Compare June 4, 2026 18:04
@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-only branch from 217187a to e1f83fe Compare June 5, 2026 19:51
@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-asyncio-monitoring branch from 49b7af0 to 311f1cf Compare June 5, 2026 19:51
@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-only branch from e1f83fe to 905a3d8 Compare June 5, 2026 20:21
@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-asyncio-monitoring branch from 311f1cf to 2f7c86f Compare June 5, 2026 20:23
vlad-scherbich and others added 3 commits June 8, 2026 08:39
…direct patching in _asyncio.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…5+ only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-only branch from 905a3d8 to 49c1ffe Compare June 8, 2026 12:41
@vlad-scherbich
vlad-scherbich force-pushed the vlad/ddtracepy-315-profiling-asyncio-monitoring branch from 2f7c86f to 670d7db Compare June 8, 2026 12:41
@github-actions github-actions Bot added the stale label Jul 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically closed after a period of inactivity.
After this much time, it will likely be easier to open a new pull request with the
same changes than to update this one from the base branch. Please comment or reopen
if you think this pull request was closed in error.

@github-actions github-actions Bot closed this Jul 12, 2026
@vlad-scherbich vlad-scherbich changed the title refactor(profiling): replace bytecode wrapping with sys.monitoring + … refactor(profiling): replace bytecode wrapping with sys.monitoring PROF-14200 Jul 17, 2026
@vlad-scherbich vlad-scherbich changed the title refactor(profiling): replace bytecode wrapping with sys.monitoring PROF-14200 refactor(profiling): replace bytecode wrapping with sys.monitoring (PROF-14200) Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant