Skip to content

perf(encode): make the encoding bench reflect a real Node.js HTTP request#8668

Merged
BridgeAR merged 2 commits into
masterfrom
BridgeAR/2026-05-27-bench-encoding-realistic-fixture
May 28, 2026
Merged

perf(encode): make the encoding bench reflect a real Node.js HTTP request#8668
BridgeAR merged 2 commits into
masterfrom
BridgeAR/2026-05-27-bench-encoding-realistic-fixture

Conversation

@BridgeAR

Copy link
Copy Markdown
Member

Summary

The old encoding bench was 30 clones of one span with three meta keys
(a/hello/and) and three metrics. Span 1 filled the string cache;
every iteration after that replayed identical state, so anything that
moved per-span work beyond cache filling read as noise.

The new fixture (trace-fixture.js) is a 30-span Express-request shape:
server root, middleware fan, a handful of Postgres / Redis / HTTP-client
spans, two DNS lookups, and one error span carrying a 1.5 KB
error.stack. Hot keys (span.kind, component, runtime-id, env,
version) reuse the same strings across spans, so the cache still warms
after one iteration but the meta-map hot loop and the wire output run
on production-shaped data.

Why

The sirun bench-comparison comment reads this fixture as a baseline
regression in any PR that introduces it -- the new fixture does roughly
5x the encode work per iteration. Landing it on its own absorbs the
step once, so encoder-side PRs that follow can be compared apples to
apples instead of new-fixture-vs-old-fixture.

…quest

The previous fixture was 30 copies of one span with three meta entries and
three metrics, so span 1 warmed the string cache and every later iteration
replayed identical state -- anything that moved per-span work beyond cache
filling read as noise. The new fixture is a 30-span Express-request shape
(server root + middleware fan + Postgres / Redis / HTTP-client / DNS spans)
with one error span carrying a 1.5 KB `error.stack`. Hot keys (`span.kind`,
`component`, `runtime-id`, env, version) reuse the same strings across spans
so the cache still warms after one iteration but the meta-map hot loop and
the wire output run on production-shaped data.
@BridgeAR
BridgeAR requested a review from a team as a code owner May 27, 2026 20:32
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented May 27, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 86.49% (-0.00%)

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

@dd-octo-sts

dd-octo-sts Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 5.96 MB
Deduped: 7 MB
No deduping: 7 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.1 | 82.56 kB | 817.39 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 39.78%. Comparing base (f99bb7a) to head (a5cd63b).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8668      +/-   ##
==========================================
- Coverage   40.95%   39.78%   -1.17%     
==========================================
  Files         286      495     +209     
  Lines       15987    30639   +14652     
  Branches     3532     3532              
==========================================
+ Hits         6548    12191    +5643     
- Misses       9439    18448    +9009     
Flag Coverage Δ
aiguard-macos 33.65% <ø> (-0.08%) ⬇️
apm-integrations-next-11.1.4 20.18% <ø> (?)
apm-integrations-next-12.3.7 20.18% <ø> (?)
apm-integrations-sharedb 32.85% <ø> (?)
appsec-next-latest-12.3.7 27.73% <ø> (?)
appsec-node-serialize 39.46% <ø> (?)
appsec-passport 43.18% <ø> (?)
instrumentations-instrumentation-ai 36.79% <ø> (?)
instrumentations-instrumentation-cookie-parser 29.80% <ø> (?)
instrumentations-instrumentation-couchbase-18 37.07% <ø> (?)
instrumentations-instrumentation-express-multi-version 21.17% <ø> (?)
instrumentations-instrumentation-generic-pool 27.56% <ø> (?)
instrumentations-instrumentation-http-client-options 37.97% <ø> (?)
instrumentations-instrumentation-multer 35.73% <ø> (?)
instrumentations-instrumentation-otel-sdk-trace 25.36% <ø> (?)
instrumentations-instrumentation-passport 39.55% <ø> (?)
instrumentations-instrumentation-promise 27.83% <ø> (?)
instrumentations-instrumentation-promise-js 27.83% <ø> (?)
instrumentations-instrumentation-q 27.86% <ø> (?)
instrumentations-instrumentation-when 27.84% <ø> (?)
master-coverage 39.78% <ø> (?)
openfeature-macos 38.11% <ø> (ø)
openfeature-unit-active 47.70% <ø> (ø)
openfeature-unit-latest 47.70% <ø> (?)
openfeature-unit-maintenance 47.83% <ø> (?)
openfeature-unit-oldest 47.83% <ø> (ø)
platform-core 32.21% <ø> (?)
platform-esbuild 36.77% <ø> (?)
platform-shimmer 40.48% <ø> (?)
platform-unit-guardrails 32.99% <ø> (ø)
platform-webpack 18.65% <ø> (?)
plugins-crypto 24.94% <ø> (?)
plugins-dd-trace-api 33.71% <ø> (?)
plugins-node-serialize 25.37% <ø> (?)
plugins-test-and-upstream-avsc 34.14% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@BridgeAR BridgeAR changed the title bench(encode): make the encoding bench reflect a real Node.js HTTP request perf(encode): make the encoding bench reflect a real Node.js HTTP request May 27, 2026
@pr-commenter

pr-commenter Bot commented May 27, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-05-27 21:13:28

Comparing candidate commit a5cd63b in PR branch BridgeAR/2026-05-27-bench-encoding-realistic-fixture with baseline commit f99bb7a in branch master.

Found 0 performance improvements and 58 performance regressions! Performance is the same for 1434 metrics, 101 unstable metrics.

scenario:encoders-0.4-20

  • 🟥 cpu_user_time [+599.388ms; +630.556ms] or [+134.640%; +141.641%]
  • 🟥 execution_time [+1.528s; +1.549s] or [+201.357%; +204.013%]
  • 🟥 instructions [+4.0G instructions; +4.1G instructions] or [+138.901%; +140.177%]
  • 🟥 max_rss_usage [+59.013MB; +63.732MB] or [+30.964%; +33.440%]

scenario:encoders-0.4-22

  • 🟥 cpu_user_time [+560.678ms; +592.401ms] or [+135.313%; +142.969%]
  • 🟥 execution_time [+1.505s; +1.516s] or [+204.754%; +206.252%]
  • 🟥 instructions [+3.7G instructions; +3.8G instructions] or [+143.605%; +144.917%]
  • 🟥 max_rss_usage [+54.580MB; +60.383MB] or [+26.611%; +29.440%]

scenario:encoders-0.4-24

  • 🟥 execution_time [+1.519s; +1.537s] or [+208.137%; +210.729%]
  • 🟥 instructions [+3.8G instructions; +3.8G instructions] or [+151.359%; +153.115%]
  • 🟥 max_rss_usage [+55.391MB; +59.515MB] or [+26.368%; +28.331%]

scenario:encoders-0.4-events-legacy-20

  • 🟥 cpu_user_time [+1.075s; +1.138s] or [+62.004%; +65.681%]
  • 🟥 execution_time [+2.875s; +2.918s] or [+86.788%; +88.100%]
  • 🟥 instructions [+6.4G instructions; +6.4G instructions] or [+58.051%; +58.470%]
  • 🟥 max_rss_usage [+112.347MB; +114.461MB] or [+39.450%; +40.192%]

scenario:encoders-0.4-events-legacy-22

  • 🟥 cpu_user_time [+0.989s; +1.053s] or [+57.715%; +61.416%]
  • 🟥 execution_time [+2.843s; +2.901s] or [+86.356%; +88.116%]
  • 🟥 instructions [+6.1G instructions; +6.1G instructions] or [+56.740%; +57.097%]

scenario:encoders-0.4-events-legacy-24

  • 🟥 cpu_user_time [+1.029s; +1.095s] or [+61.400%; +65.309%]
  • 🟥 execution_time [+2.841s; +2.902s] or [+86.919%; +88.801%]
  • 🟥 instructions [+6.0G instructions; +6.0G instructions] or [+56.517%; +56.998%]
  • 🟥 max_rss_usage [+115.145MB; +116.635MB] or [+38.777%; +39.278%]

scenario:encoders-0.4-events-native-20

  • 🟥 cpu_user_time [+1.026s; +1.103s] or [+49.026%; +52.679%]
  • 🟥 execution_time [+3.241s; +3.349s] or [+63.298%; +65.406%]
  • 🟥 instructions [+7.1G instructions; +7.2G instructions] or [+53.010%; +53.937%]
  • 🟥 max_rss_usage [+102.185MB; +103.641MB] or [+26.926%; +27.310%]

scenario:encoders-0.4-events-native-22

  • 🟥 cpu_user_time [+957.978ms; +1025.941ms] or [+48.112%; +51.525%]
  • 🟥 execution_time [+3.207s; +3.351s] or [+63.755%; +66.613%]
  • 🟥 instructions [+6.8G instructions; +7.0G instructions] or [+54.900%; +55.933%]
  • 🟥 max_rss_usage [+99.687MB; +101.048MB] or [+25.489%; +25.837%]

scenario:encoders-0.4-events-native-24

  • 🟥 cpu_user_time [+1.006s; +1.105s] or [+50.880%; +55.876%]
  • 🟥 execution_time [+3.203s; +3.362s] or [+63.701%; +66.852%]
  • 🟥 instructions [+6.8G instructions; +6.9G instructions] or [+55.514%; +56.162%]
  • 🟥 max_rss_usage [+100.276MB; +102.738MB] or [+25.493%; +26.119%]

scenario:encoders-0.5-20

  • 🟥 cpu_user_time [+127.593ms; +142.920ms] or [+51.241%; +57.396%]
  • 🟥 execution_time [+245.815ms; +252.940ms] or [+76.238%; +78.448%]
  • 🟥 instructions [+1.4G instructions; +1.4G instructions] or [+88.563%; +90.699%]
  • 🟥 max_rss_usage [+13.132MB; +22.182MB] or [+10.364%; +17.507%]

scenario:encoders-0.5-22

  • 🟥 cpu_user_time [+130.008ms; +144.619ms] or [+52.532%; +58.436%]
  • 🟥 execution_time [+244.761ms; +253.767ms] or [+75.174%; +77.940%]
  • 🟥 instructions [+1.3G instructions; +1.4G instructions] or [+86.432%; +88.761%]
  • 🟥 max_rss_usage [+18.025MB; +27.094MB] or [+13.447%; +20.213%]

scenario:encoders-0.5-24

  • 🟥 cpu_user_time [+142.578ms; +162.282ms] or [+63.273%; +72.018%]
  • 🟥 execution_time [+255.488ms; +269.168ms] or [+83.953%; +88.448%]
  • 🟥 instructions [+1.5G instructions; +1.6G instructions] or [+106.752%; +114.932%]
  • 🟥 max_rss_usage [+21.106MB; +30.687MB] or [+15.030%; +21.853%]

scenario:encoders-0.5-events-legacy-20

  • 🟥 cpu_user_time [+199.447ms; +216.430ms] or [+20.804%; +22.576%]
  • 🟥 execution_time [+326.642ms; +340.672ms] or [+31.219%; +32.560%]
  • 🟥 instructions [+1.5G instructions; +1.6G instructions] or [+22.965%; +23.473%]
  • 🟥 max_rss_usage [+46.394MB; +52.414MB] or [+38.767%; +43.797%]

scenario:encoders-0.5-events-legacy-22

  • 🟥 cpu_user_time [+227.000ms; +242.702ms] or [+23.851%; +25.501%]
  • 🟥 execution_time [+357.563ms; +367.206ms] or [+34.372%; +35.299%]
  • 🟥 instructions [+1.6G instructions; +1.6G instructions] or [+23.230%; +23.533%]
  • 🟥 max_rss_usage [+37.355MB; +46.236MB] or [+29.402%; +36.393%]

scenario:encoders-0.5-events-legacy-24

  • 🟥 cpu_user_time [+244.720ms; +258.656ms] or [+26.475%; +27.983%]
  • 🟥 execution_time [+370.102ms; +381.935ms] or [+36.291%; +37.451%]
  • 🟥 instructions [+1.7G instructions; +1.8G instructions] or [+26.211%; +28.062%]
  • 🟥 max_rss_usage [+24.519MB; +32.247MB] or [+19.524%; +25.677%]

The previous fixture's trace was built once and reused for 5000 encodes
unchanged: the encoder's string cache, magnitude-branch predictor, and
per-span ID reads all settled to a single state and held it, so any
optimisation that depended on hot-vs-cold variance read as noise.
`tickTrace(trace, iteration)` now runs before each encode and rewrites
every per-request dynamic field in place (timestamps, durations, ID
buffer low halves, `db.row_count`, root-span route / URL / resource /
status / client IP, and error type / message / stack). Hot strings
reused across spans stay constant so the cache still warms after one
iteration.

The `+ iteration * 4096` step on `span.start` is the smallest increment
visible past the IEEE-754 double's ULP at the ~1.7e18 nano-timestamp
magnitude (256 nanos). A real fix for that precision loss needs the
span to carry `start` as `BigInt`, which is a separate change on the
tracer side, not here.
@BridgeAR
BridgeAR merged commit 8cb2b77 into master May 28, 2026
823 of 824 checks passed
@BridgeAR
BridgeAR deleted the BridgeAR/2026-05-27-bench-encoding-realistic-fixture branch May 28, 2026 15:02
dd-octo-sts Bot pushed a commit that referenced this pull request May 29, 2026
…quest (#8668)

* bench(encode): make the encoding bench reflect a real Node.js HTTP request

The previous fixture was 30 copies of one span with three meta entries and
three metrics, so span 1 warmed the string cache and every later iteration
replayed identical state -- anything that moved per-span work beyond cache
filling read as noise. The new fixture is a 30-span Express-request shape
(server root + middleware fan + Postgres / Redis / HTTP-client / DNS spans)
with one error span carrying a 1.5 KB `error.stack`. Hot keys (`span.kind`,
`component`, `runtime-id`, env, version) reuse the same strings across spans
so the cache still warms after one iteration but the meta-map hot loop and
the wire output run on production-shaped data.

* bench(encode): vary every per-request field across iterations

The previous fixture's trace was built once and reused for 5000 encodes
unchanged: the encoder's string cache, magnitude-branch predictor, and
per-span ID reads all settled to a single state and held it, so any
optimisation that depended on hot-vs-cold variance read as noise.
`tickTrace(trace, iteration)` now runs before each encode and rewrites
every per-request dynamic field in place (timestamps, durations, ID
buffer low halves, `db.row_count`, root-span route / URL / resource /
status / client IP, and error type / message / stack). Hot strings
reused across spans stay constant so the cache still warms after one
iteration.

The `+ iteration * 4096` step on `span.start` is the smallest increment
visible past the IEEE-754 double's ULP at the ~1.7e18 nano-timestamp
magnitude (256 nanos). A real fix for that precision loss needs the
span to carry `start` as `BigInt`, which is a separate change on the
tracer side, not here.
This was referenced May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants