Skip to content

SymDB: restore benchmarks#5798

Open
p-datadog wants to merge 11 commits into
masterfrom
revert-5795-symdb-benchmarks
Open

SymDB: restore benchmarks#5798
p-datadog wants to merge 11 commits into
masterfrom
revert-5795-symdb-benchmarks

Conversation

@p-datadog

@p-datadog p-datadog commented May 20, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Restores the SymDB benchmark scripts (symbol_database_background_impact.rb, symbol_database_baseline_matrix.rb, symbol_database_extraction.rb), their benchmarks/README.md entries, and the validate_benchmarks_spec.rb coverage that were removed by #5795.

The benchmarks/execution.yml change from the original revert is not included here — the scripts are restored on disk, but they are not yet wired into the microbenchmarks CI job.

Motivation:

Revert requested.

Change log entry

None.

Follow-up required before these benchmarks can be enabled in CI

  1. Fix the JSON output shape of each script. The microbenchmarks analyzer's benchmark_ips.py converter expects [{item: "...", samples: [<numbers>]}]; the current scripts emit nested-dict structures (extraction stats, RPS-drop curves by load tier, baseline vs treatment ops/sec) and crash the converter with TypeError: string indices must be integers — this is the same failure that benchmarks: remove SymDB benchmarks  #5795 was created to work around. Rework emit in each script so every tracked measurement becomes its own item with per-rep samples, and update validate_benchmarks_spec.rb to assert the new shape.
  2. Once (1) is on master, a follow-up PR can re-add the three filenames to the &other group in benchmarks/execution.yml. This second step must land after (1) is on master, because the microbenchmarks job uses the candidate branch's execution.yml to drive both the candidate and baseline runs — listing the scripts before they exist on master causes the baseline-side bundle exec ruby benchmarks/symbol_database_*.rb invocations to fail with LoadError.

Additional Notes:

None.

How to test the change?

bundle exec rspec spec/datadog/symbol_database/validate_benchmarks_spec.rb

@p-datadog
p-datadog requested a review from a team as a code owner May 20, 2026 21:15
@p-datadog p-datadog added the AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos label May 20, 2026
@dd-octo-sts dd-octo-sts Bot added the dev/testing Involves testing processes (e.g. RSpec) label May 20, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1445da9a6f

ℹ️ 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".

Comment thread benchmarks/symbol_database_baseline_matrix.rb Outdated
@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented May 20, 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: 89.98% (+0.12%)

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

@eregon

eregon commented May 21, 2026

Copy link
Copy Markdown
Member

Is it just a plain revert?
If so I guess it doesn't fix the issues mentioned in #5795 and indeed we see CI is red.
Is anyone planning to fix them?

@p-datadog

Copy link
Copy Markdown
Member Author

Yes this needs a fix.

@p-datadog
p-datadog marked this pull request as draft May 21, 2026 13:13
@p-datadog p-datadog changed the title Revert "benchmarks: remove SymDB benchmarks (#5795)" SymDB: restore benchmarks Jun 9, 2026
p-ddsign added 5 commits June 10, 2026 16:24
Adds stderr trace lines around each phase of run() and inside run_arm's
bg-thread stop logic. Local validate run is 3.09s; CI hits the 10s
expect_in_fork timeout. The traces will identify which phase grows on CI.

To revert: this commit only modifies symbol_database_baseline_matrix.rb.
expect_in_fork captures stderr into a tempfile and discards it on
success. The baseline_matrix bench's per-phase trace (added in the
previous commit) is therefore invisible in CI logs when the spec passes.

This commit overrides fork_expectations to print the captured stderr
before asserting, and bumps timeout_seconds to 60 so a slow runner
doesn't truncate the trace.

Revert with the previous diagnostic commit once CI timing is understood.
Revert "DIAGNOSTIC: surface bench fork stderr + bump timeout to 60s"
Revert "DIAGNOSTIC: trace timing in baseline_matrix to locate CI >10s phase"

Diagnostic data collected; replacing with the real fix in the next commit.
The baseline_matrix benchmark's validate-mode run was approaching the
10s expect_in_fork timeout on slow CI runners. Diagnostic traces over
two CI runs measured 6.4s and 8.7s wall, with the entire variance and
~80% of the time coming from work that is only meaningful in real
measurement mode:

  - calibrate_cpu_chunk runs 8 cpu_chunks (~580ms on CI) to find the
    per-host wall duration. Validate mode doesn't measure anything, so
    return a placeholder 0.01s instead.

  - 3.times { GC.start } between arms (8 invocations × 0.5-0.9s each
    on CI = 4-6s) stabilizes heap state between measured runs. Validate
    mode skips this entirely.

  - bg.join(0.5) caps how long we wait for the bg extract_all thread
    after the measurement window. Three with_extractor arms × ~0.48s on
    CI = ~1.5s. Shrink to 0.05 in validate mode since the bg thread is
    doing token work on 10 classes.

Local validate-mode wall: 2.08s → 1.13s.
The full bench's measurement behavior in real mode is unchanged.
@p-datadog
p-datadog force-pushed the revert-5795-symdb-benchmarks branch from 2221d95 to 324271e Compare June 10, 2026 20:24
@pr-commenter

pr-commenter Bot commented Jun 11, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-06-23 18:16:13

Comparing candidate commit bbf03fa in PR branch revert-5795-symdb-benchmarks with baseline commit f9044e8 in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 48 metrics, 1 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

The bg-thread block calls bg.join (line 219) and bg.join (line 221 after
bg.kill), not bg.value. Two comments referenced bg.value:

  - line 188: "propagates out via bg.value below"
  - line 217: "10 arms × bg.value across the matrix"

Thread#join re-raises an exception that terminated the thread in the
calling thread, same as Thread#value. Behavior is correct; only the
comments were stale.
@p-datadog
p-datadog marked this pull request as ready for review June 15, 2026 22:13
@p-datadog
p-datadog requested a review from Copilot June 15, 2026 22:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Restores the Symbol Database (SymDB) microbenchmark scripts and their “bitrot” validation coverage that were previously removed, so the benchmarks exist on disk again and are runnable under RSpec (even though they are not yet re-enabled in the microbenchmarks CI job).

Changes:

  • Re-adds three SymDB benchmark scripts under benchmarks/.
  • Re-introduces an RSpec “validate benchmarks” spec for SymDB to ensure the scripts load and run.
  • Updates benchmarks/README.md to document the SymDB benchmark prefix and its validation spec.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
spec/datadog/symbol_database/validate_benchmarks_spec.rb Adds coverage that loads/runs the SymDB benchmark scripts under VALIDATE_BENCHMARK=true.
benchmarks/symbol_database_extraction.rb Restores the extraction benchmark script (wall/CPU/memory sampling).
benchmarks/symbol_database_baseline_matrix.rb Restores the baseline matrix benchmark script (baseline CPU tiers vs ops/sec impact).
benchmarks/symbol_database_background_impact.rb Restores the background extraction impact benchmark script (latency/throughput ratios).
benchmarks/README.md Documents the symbol_database_ benchmark prefix and its validation spec.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +219 to +222
unless bg.join(VALIDATE_BENCHMARK_MODE ? 0.05 : 0.5)
bg.kill
bg.join
end
Comment on lines +186 to +188
# extract_all until the main thread signals stop. Any exception
# propagates out via bg.join below — Thread#join re-raises in the
# caller when the thread terminated with an exception.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9634204a56

ℹ️ 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".

loop do
iter_wall_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
iter_times_start = Process.times
scopes = extractor.extract_all

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Benchmark the streaming extraction path

When this benchmark is used to validate the SymDB memory-overhead requirement, calling extract_all without a block measures the legacy path that materializes and retains the full Array<Scope>; during repeated iterations the previous array can remain live while the next one is built. The production upload path explicitly uses the block form (lib/datadog/symbol_database/component.rb:491-494) to avoid materializing the full array, so these RSS numbers can flag or hide regressions in a path customers do not exercise. Use the streaming form here and count yielded scopes instead of storing the whole result.

Useful? React with 👍 / 👎.

Adds STDERR.puts diagnostics around the TracePoint(:class) hook in
install_hot_load_hook to investigate the Ruby 2.6-only flake of
spec/datadog/symbol_database/component_spec.rb "does not propagate
exceptions when logger.debug itself raises".

Logs at:
- hook install: pid, existing TracePoint count, thread
- hook fired: mod name, thread, report_on_exception, TracePoint count
- outer rescue entry: caught class + message + thread
- pre-debug: thread + logger types
- inner rescue entry: caught class + message + backtrace + TracePoint count
- outer rescue done: thread (proves outer handler completed normally)

No semantic change. To be reverted once we see CI output.

Co-Authored-By: Claude <[email protected]>
@dd-octo-sts dd-octo-sts Bot added the debugger Live Debugger (+Dynamic Instrumentation, +Symbol Database) label Jun 15, 2026
@dd-octo-sts

dd-octo-sts Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Typing analysis

This PR does not change typing compared to the base branch.

The `install_hot_load_hook` method still carried the `DIAG (REVERT)`
debugging instrumentation added in 1c514f5; the later "delete ai slop"
commit cleaned the benchmark scripts but missed this file. The
instrumentation ran `ObjectSpace.each_object(TracePoint).count` — a
full-heap scan that holds the GVL — plus `STDERR.puts`, inside the `:class`
TracePoint block, so it executed on every class definition in the process.

This caused both failing checks:

- Test (macos-15, 3.2): under the full suite, constant class loads from
  background threads each triggered the heap scan, starving the component's
  scheduler thread on the GVL. The hot-load extraction did not complete
  within the spec's wait window, so `extracted_modules` was empty and
  "extracts a class defined after the initial upload completes" failed with
  `expected [] to include "SymdbHotLoadSpecNewClass"`.

- End-to-end uds-rails 2: the Rails weblog boot loads thousands of classes,
  each paying the per-load heap scan, stalling startup until the runner was
  canceled (~18 min with no progress after "Starting containers").

Removing the instrumentation restores `install_hot_load_hook` to its master
state (verified byte-identical). No behavioral code changed.

Verified locally: spec/datadog/symbol_database/component_spec.rb passes
(52 examples, 0 failures); the previously-failing example passes 3/3 runs.
The macos contention scenario requires the full suite on a macOS runner and
was not reproduced locally; the fix is justified by removal of the
per-class-load GVL-holding heap scan.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos debugger Live Debugger (+Dynamic Instrumentation, +Symbol Database) dev/testing Involves testing processes (e.g. RSpec)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants