DI: support per-method iseqs for line probes on pre-loaded files#5501
Conversation
BenchmarksBenchmark execution time: 2026-04-25 22:48:20 Comparing candidate commit 24f87ca in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 45 metrics, 1 unstable metrics.
|
9012b29 to
dee647b
Compare
Typing analysisNote: Ignored files are excluded from the next sections.
|
* origin/di-per-method-iseq: (23 commits) Improve DITargetNotInRegistry error messages Update remote config test for new error message format Fix throwable integration test to include stacktrace Add integration test for line probe via per-method iseq Support per-method iseqs for line probes on pre-loaded files Fix Steep: allow nil for @current_components Fix StandardRB: add parens to ternary, remove extra blank line Fix backfill_registry test failures Disable GC during backfill integration test to prevent iseq collection Fix backfill_registry tests on Ruby < 3.1 (iseq_type unavailable) Initialize @current_components to suppress Ruby 2.6/2.7 warning Return nil explicitly from backfill_registry Remove respond_to?(:all_iseqs) guard from backfill_registry Add tests for calling backfill_registry twice Fix inaccurate comment: first_lineno == 0 heuristic matches iseq_type Document iseq_type Ruby 3.1 dependency and two-strategy backfill Review fixes: doc comments, error handling test coverage, spec_helper require Guard rb_iseq_type behind have_func for Ruby < 3.1 compat Add DI.iseq_type C extension; use type instead of first_lineno in backfill Stub backfill_registry in pre-existing tests ...
* origin/di-per-method-iseq: (23 commits) Improve DITargetNotInRegistry error messages Update remote config test for new error message format Fix throwable integration test to include stacktrace Add integration test for line probe via per-method iseq Support per-method iseqs for line probes on pre-loaded files Fix Steep: allow nil for @current_components Fix StandardRB: add parens to ternary, remove extra blank line Fix backfill_registry test failures Disable GC during backfill integration test to prevent iseq collection Fix backfill_registry tests on Ruby < 3.1 (iseq_type unavailable) Initialize @current_components to suppress Ruby 2.6/2.7 warning Return nil explicitly from backfill_registry Remove respond_to?(:all_iseqs) guard from backfill_registry Add tests for calling backfill_registry twice Fix inaccurate comment: first_lineno == 0 heuristic matches iseq_type Document iseq_type Ruby 3.1 dependency and two-strategy backfill Review fixes: doc comments, error handling test coverage, spec_helper require Guard rb_iseq_type behind have_func for Ruby < 3.1 compat Add DI.iseq_type C extension; use type instead of first_lineno in backfill Stub backfill_registry in pre-existing tests ...
dee647b to
4107334
Compare
🎉 All green!❄️ No new flaky tests detected 🎯 Code Coverage (details) 🔗 Commit SHA: 24f87ca | Docs | Datadog PR Page | Give us feedback! |
873a846 to
af1e513
Compare
c8f8bf9 to
31c6a23
Compare
22e7d9c to
bc3339c
Compare
|
@codex review |
The backfill_registry docstring said "per-method iseqs require instrumenter changes and will be supported in a follow-up." This PR is that follow-up — the comment is now stale. Co-Authored-By: Claude <[email protected]>
…ent section The section said "Code loaded before the tracer initializes cannot be instrumented with line probes." After #5496 (whole-file iseq backfill) and this PR (per-method iseq fallback), that limitation no longer exists. Remove the section entirely rather than rewrite it. Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
21af9d4 to
dc8db65
Compare
Address review comment: compile_file-produced :top iseqs with first_lineno != 0 fell through the whole_file check into per_method_registry. Probes targeting these iseqs fail because targeted TracePoints are bound to the specific iseq object. - Fixed in lib/datadog/di/code_tracker.rb:90 (type guard in else branch) - Added test in spec/datadog/di/code_tracker_spec.rb Co-Authored-By: Claude <[email protected]>
Address review comment: iseq_for_line matched any trace point event at the target line, including :call. Since the instrumenter subscribes to [:line, :return, :b_return], a :call-only line would cause TracePoint#enable to raise. Now filters to executable event types so the probe goes to pending state instead of erroring. - Fixed in lib/datadog/di/code_tracker.rb:275 (event type filter) - Added tests in spec/datadog/di/code_tracker_spec.rb Co-Authored-By: Claude <[email protected]>
The second entry (with jruby) overwrote the first. Keep only the entry without jruby, matching the reviewer's suggestion and the format of adjacent entries. Co-Authored-By: Claude <[email protected]>
- Comment 1 (compile_file guard): replace MRI jargon and "known limitation" with concrete user impact (probe silently produces no snapshots) and practical likelihood on Ruby < 3.1 - Comment 2 (event filter): clarify that the `def` line example refers to the defined method's own iseq, not the enclosing scope Co-Authored-By: Claude <[email protected]>
State the consequence explicitly: probe installs but silently never fires. Replace vague pronoun and jargon with concrete referents. Co-Authored-By: Claude <[email protected]>
RubyVM::InstructionSequence is needed to find the API docs. "Compiles source to bytecode without executing it" explains what they do without assuming MRI internals knowledge. Co-Authored-By: Claude <[email protected]>
|
@codex verify that integration tests properly require that iseqs are garbage collected and that this is clearly stated in code comments |
Summary
Testing
|
|
@codex read the documentation changes in this PR, then improve the documentation: 1- make customer-targeted docs clearly describe any limitations per ruby version 2- shorten added sections to 1/3 of their current size 3- ensure there is an understandable overview of how the system works (for the development guide) and what the customer-visible behavior is (for user guide). delete low level details |
Summary
Testing
|
|
None of the AIs are able to write sensible docs for this PR, I'll tackle that some other time. |
b801292 to
0cffbb4
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b801292f82
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Strech
left a comment
There was a problem hiding this comment.
I would suggest converting doubles in tests into instance_double to avoid over-stabbing
Address review comment: when multiple per-method iseqs contain the same target line (e.g. a method and an inline block sharing a line), picking the first match would silently bind the probe to only one context. Changed .find to .select with a multi-match guard that raises MultiplePathsMatch so the probe is recorded as failed with a clear error message. Also changed resolve_path_suffix to raise MultiplePathsMatch (instead of returning nil) when multiple paths match, consistent with iseqs_for_path_suffix behavior. - Fixed in lib/datadog/di/code_tracker.rb:292 (ambiguous iseq guard) - Fixed in lib/datadog/di/code_tracker.rb:361 (ambiguous path suffix) Co-Authored-By: Claude <[email protected]>
Address review comments: - Convert all iseq double() to instance_double(RubyVM::InstructionSequence) to verify stubs against the real interface (per @Strech suggestion) - Add test for ambiguous multi-iseq line match raising MultiplePathsMatch - Add test for ambiguous per-method path suffix raising MultiplePathsMatch Co-Authored-By: Claude <[email protected]>
|
Good suggestion — converted all iseq |
What does this PR do?
When a file's whole-file (:top) iseq has been garbage collected, the backfill now stores surviving per-method iseqs and the instrumenter can use them to target line probes.
Motivation:
86% of files loaded before DI starts have their whole-file iseq GC'd but still have surviving per-method iseqs (measured on a Rails app with 146 gems: 1987 of 2309 missing files had 22739 surviving method iseqs). Previously these files were completely untargetable by line probes.
Change log entry
Yes. Live Debugger line probes can now target third-party and Ruby standard library code loaded before datadog gem is loaded.
Additional Notes:
backfill_registrynow stores per-method iseqs in a separateper_method_registrykeyed by pathiseq_for_line(suffix, line)method checks whole-file iseq first, falls back to per-method iseqs by checkingtrace_pointsfor the target lineiseq_for_linewhen available, falls back toiseqs_for_path_suffixfor compatibility with older code trackersHow to test the change?
Unit tests added + manual testing via gobo targeting stdlib with partial iseqs:
The screenshot shows
Set#addcaptured with argument1. The gobo demo callsSet.new([1, 2, 3])thens.add(4)ands.add(2), butSet.newinternally callsaddfor each element (1, 2, 3), so the probe fires onadd(1)first. Due to the DI rate limit (one snapshot per second by default), only the first invocation is captured.