refactor(profiling): drop bytecode-lib dependency from _asyncio.py#17995
refactor(profiling): drop bytecode-lib dependency from _asyncio.py#17995vlad-scherbich wants to merge 16 commits into
_asyncio.py#17995Conversation
🎉 All green!❄️ No new flaky tests detected 🔗 Commit SHA: ebb1828 | Docs | Datadog PR Page | Give us feedback! |
BenchmarksBenchmark execution time: 2026-05-10 20:21:06 Comparing candidate commit a982199 in PR branch Found 0 performance improvements and 5 performance regressions! Performance is the same for 592 metrics, 4 unstable metrics. scenario:iast_aspects-re_expand_aspect
scenario:iastaspects-lower_aspect
scenario:iastaspectsospath-ospathbasename_aspect
scenario:span-start
scenario:telemetryaddmetric-1-count-metric-1-times
|
a982199 to
87bd294
Compare
Codeowners resolved as |
|
@hatgpt-codex-connector please review |
There was a problem hiding this comment.
Pull request overview
This PR updates the asyncio profiling integration to avoid ddtrace.internal.wrapping.wrap() (and its third-party bytecode dependency) by introducing a local _wrap() helper that uses functools.wraps + setattr, including explicit alias mirroring for asyncio.* / asyncio.tasks.* bindings.
Changes:
- Replaced bytecode-based wrapping in
ddtrace/profiling/_asyncio.pywith an in-module_wrap()helper and added alias mirroring where needed. - Added a comprehensive new subprocess-based test suite covering alias identity, metadata preservation, callback firing, and argument/kwarg substitution behaviors.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
ddtrace/profiling/_asyncio.py |
Introduces _wrap() and migrates asyncio/uvloop hook points off bytecode-based wrapping, with alias mirroring for selected APIs. |
tests/profiling/collector/test_asyncio_wrapping.py |
Adds subprocess-isolated behavioral tests validating wrapping invariants and callback firing across asyncio APIs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
02c593b to
9133537
Compare
|
@chatgpt-codex-connector please review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9133537072
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…-cached references (uvloop)
…tity-preservation tests
…ty-preserving wrap
…s_available in helper
2e404db to
348bb66
Compare
_asyncio.py
https://datadoghq.atlassian.net/browse/PROF-14616
Description
ddtrace/profiling/_asyncio.pypreviously hooked into asyncio internals viaddtrace.internal.wrapping.wrap, which rewrites the target's__code__using the third-partybytecodelibrary.This PR replaces that with a small in-module
_wrap()helper that clones a template trampoline's__code__viaCodeType.replace()and grafts it onto the original function. It is the same identity-preserving trick the previousbytecode.wrap()used, but without the dependency!Why
bytecodedependency during migration to v3.15 (@gab is working on the tracing-side implementation), because it blocks the entire minor version release until it become compatibleScope
This PR affects profiling consumers only.
ddtrace.internal.wrapping.wrapitself is unchanged — the tracing path still genuinely needs bytecode for async/generator function wrapping with stack-effect preservation. The other (legitimate)bytecodeconsumers (ddtrace/debugging/_expressions.py,ddtrace/internal/assembly.py,ddtrace/internal/bytecode_injection/__init__.py) are untouched.Testing
tests/profiling/collector/test_asyncio_wrapping.py(16 tests).Performance
TL;DR:
Microbenchmarked on Python 3.14.3 / macOS arm64.
Three-way:
N = 12 trials per variant; each trial:
create_task: 200,000 iterations per timinggather3/shield: 2,000 iterations per timingRisks
bytecode-dependency implementation.