Skip to content

Fix Safari dormant overhead in Live Debugger instrumentation - #438

Open
watson wants to merge 1 commit into
watson/DEBUG-5787/add-benchfrom
watson/DEBUG-5793/fix-safari
Open

Fix Safari dormant overhead in Live Debugger instrumentation#438
watson wants to merge 1 commit into
watson/DEBUG-5787/add-benchfrom
watson/DEBUG-5793/fix-safari

Conversation

@watson

@watson watson commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What and why?

The Live Debugger runtime benchmark surfaced a large dormant-probe overhead on Safari: a tiny instrumented function cost ~8.9 ns/call (~1,100% over baseline) versus ~0 ns on Chrome and ~1.6 ns on Firefox. The root cause is that the transform hoisted each function's captured parameters into a per-call arrow closure (const $dd_eN = () => ({...})). A nested closure that captures parameters forces JavaScriptCore — Safari and all iOS browsers, since they're all WebKit — to heap-allocate the function's scope on every invocation, even when probes are dormant and the closure is never created or called. V8 and SpiderMonkey sink that allocation; JavaScriptCore does not, so it dominated the dormant overhead. Because every instrumented iOS app pays this cost on every call, it's worth eliminating.

How?

Inline the captured-arguments object literal ({a, b}) directly at each probe-guarded call site instead of hoisting it into a per-call closure. The object now lives inside the if (probe) / probe ? guards, so dormant calls allocate nothing; gating the closure behind the probe check was confirmed insufficient because the captured scope is still allocated. The active path is unchanged — the same arguments object is built the same number of times when a probe fires. Verified with the runtime benchmark: Safari per-call dormant overhead drops ~73% (8.9 → 2.4 ns) and the Hot workload from ~10 to ~7 ns, with no change on Chrome or Firefox. Transform unit-test snapshots and the plugin README/EXAMPLES output catalog are updated to match the new generated shape.

watson commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@datadog-official

datadog-official Bot commented Jun 24, 2026

Copy link
Copy Markdown

Tests

All CI checks and tests passed.

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 6744df0 | Docs | View more details | Give us feedback!

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown

Live Debugger Runtime Benchmark

SDK-loaded dormant-probe runtime overhead, measured against an uninstrumented bundle in the same browser session.

Browser Workload Quality Per-call overhead upper
chrome Hot clean <= 2.95 ns
chrome Tiny clean <= 0.02 ns
firefox Hot clean <= 7.77 ns
firefox Tiny clean <= 0.27 ns
safari Hot clean <= 4.46 ns
safari Tiny clean <= 1.10 ns
Full diagnostics
browser  workload  quality  per-call overhead upper  overhead upper          95% CI        A/A diag        block CI  acf(1)   baseline  instrumented                         samples
-------  --------  -------  -----------------------  --------------  --------------  --------------  --------------  ------  ---------  ------------  ------------------------------
chrome   Hot       clean                 <= 2.95 ns        <= 6.83%   2.94..2.95 ns  -0.01..0.01 ns   2.94..2.95 ns   -0.00  51.225 ms     54.720 ms   102 (trim 20%, outliers 9.8%)
chrome   Tiny      clean                 <= 0.02 ns        <= 0.35%  -0.02..0.02 ns  -0.05..0.02 ns  -0.02..0.02 ns   -0.04  55.290 ms     55.310 ms  102 (trim 20%, outliers 12.7%)
firefox  Hot       clean                 <= 7.77 ns       <= 36.50%   7.76..7.77 ns  -0.01..0.00 ns   7.76..7.77 ns   -0.40  40.450 ms     55.200 ms   102 (trim 20%, outliers 8.8%)
firefox  Tiny      clean                 <= 0.27 ns        <= 2.29%   0.27..0.27 ns  -0.00..0.00 ns   0.27..0.27 ns    0.08  50.780 ms     51.940 ms   102 (trim 20%, outliers 5.9%)
safari   Hot       clean                 <= 4.46 ns       <= 21.18%   4.45..4.46 ns  -0.00..0.00 ns   4.45..4.46 ns    0.17  45.460 ms     55.040 ms   102 (trim 20%, outliers 3.9%)
safari   Tiny      clean                 <= 1.10 ns       <= 33.55%   1.09..1.10 ns  -0.00..0.00 ns   1.09..1.10 ns   -0.13  41.180 ms     55.000 ms   102 (trim 20%, outliers 7.8%)

Raw samples are in the live-debugger-runtime-bench-results artifact.

The transform hoisted each instrumented function's captured parameters into a per-call arrow
closure (`const $dd_eN = () => ({...})`). A nested closure that captures parameters forces
JavaScriptCore (Safari and all iOS browsers) to heap-allocate the function's scope on every
invocation -- even when probes are dormant and the closure is never created or called. V8 and
SpiderMonkey sink that allocation; JavaScriptCore does not, so it dominated the dormant runtime
overhead.

The runtime benchmark measured ~8.9 ns/call of dormant overhead on Safari for a tiny function
(vs ~0 on Chrome and ~1.6 on Firefox). Gating the closure behind the probe check does not help,
because the captured scope is still allocated on every call.

Instead, inline the captured-arguments object literal (`{a, b}`) directly at each probe-guarded
call site. The object now lives inside the `if (probe)` / `probe ? ` guards, so dormant calls
allocate nothing. The active path is unchanged: the same arguments object is built the same number
of times when a probe fires.

Safari per-call dormant overhead drops ~73% (8.9 -> 2.4 ns); the Hot workload drops from ~10 to
~7 ns. Chrome and Firefox are unchanged. Transform snapshots and the README/EXAMPLES output
catalog are updated to match the new shape.
@watson
watson force-pushed the watson/DEBUG-5793/fix-safari branch from 937be82 to 6744df0 Compare August 26, 2026 11:54
@watson
watson marked this pull request as ready for review August 27, 2026 09:21
@watson
watson requested review from a team as code owners August 27, 2026 09:21
@watson
watson requested review from ruimartin and removed request for a team August 27, 2026 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant