Memoize per-test class analysis in a module-wide cache#11969
Conversation
Jacoco's Analyzer re-parsed each covered class once per test, dominating line-coverage report cost. Cache the covered lines per (class id, probe set), shared across tests, so a class covered identically by many tests is analyzed only once. Recording path is unchanged, so Jacoco's aggregate coverage is preserved by its native probe writes (no probe-array swap). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Test Environment - nebula-release-pluginJob Status: 🟢 success
Baseline: median of |
Test Environment - netflix-zuulJob Status: 🟢 success
Baseline: median of |
Test Environment - reactive-streams-jvmJob Status: 🟢 success
Baseline: median of |
Test Environment - heliboardJob Status: 🟢 success
Baseline: median of |
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
Test Environment - sonar-kotlinJob Status: 🟢 success
Baseline: median of |
Test Environment - jolokiaJob Status: 🟢 success
Baseline: median of |
Test Environment - okhttpJob Status: 🟢 success
Baseline: median of |
Test Environment - spring_bootJob Status: 🟢 success
Baseline: median of |
Test Environment - sonar-javaJob Status: 🟢 success
Baseline: median of |
Test Environment - pass4sJob Status: 🟢 success
Baseline: median of |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c60b08fac1
ℹ️ 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".
Addresses Codex review of the memoization cache: - Bit-pack the probe activations into a BitSet in the key (~8x smaller than the test's boolean[], exact equality). - Cap the cache by approximate retained bytes rather than entry count, so a class with many probes covered by many distinct probe sets can't retain unbounded memory for the module lifetime. - Reserve an entry's weight atomically before insertion (release on over-limit or lost putIfAbsent race) so concurrent inserts can't overshoot the bound. - Count fixed per-entry overhead (key + both BitSets + map node), not just the packed bits, so the byte bound is a real ceiling. - Snapshot the per-test probe array once and use that same snapshot for both the cache key and the JaCoCo analysis, so a late probe recorded by a background thread during report() can't be analyzed into coveredLines yet stored under the earlier key, poisoning the entry for later tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Test Environment - sbt-scalatestJob Status: 🟢 success
Baseline: median of |
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
There was a problem hiding this comment.
More details
Memoization is sound. The cache keys correctly identify class+probe pairs using bit-packed probes, concurrent insertion respects the 64MB memory bound through atomic byte counting, and probe snapshotting prevents late writes from poisoning entries. No regressions to coverage reporting or probe recording.
📊 Validated against 12 scenarios · Open Bits AI session
🤖 Datadog Autotest · Commit 682893b · What is Autotest? · Any feedback? Reach out in #autotest
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
|
4719f5a
into
master
What Does This Do
Memoizes per-test line-coverage class analysis in a module-wide cache.
When line-level coverage is enabled, JaCoCo's
Analyzerre-parses and re-analyzes each covered class's bytecode once per test that covers it, which dominates the report-time cost. This caches the covered lines per(class id, probe set), shared across tests, so a class covered identically by many tests is analyzed only once.Motivation
Reduce the runtime overhead of line-level per-test code coverage (Test Optimization). Report-time re-analysis was the dominant hotspot; in the test-environment, marginal line-coverage overhead drops meaningfully on suites with headroom (e.g. nebula, spring-boot, okhttp).
The probe recording and instrumentation paths are unchanged, so JaCoCo's aggregate coverage (total %/report uploads, used to back-fill coverage for TIA/ITR-skipped tests) is preserved by its native probe writes.
Additional Notes
Scoped to the report path only:
LineCoverageStore.analyzeClassplus two getters onExecutionDataAdapter. No changes to instrumentation, probe recording, or the coverage API.The cache is memory-safe: keys bit-pack the probe activations (exact equality), the cache is bounded by approximate retained bytes (not entry count), and each analysis uses a single probe-array snapshot for both the key and the JaCoCo analysis so concurrent late writes can't poison an entry. Coverage stays correct beyond the size bound — the class is simply analyzed each time.
Contributor Checklist
type:and (comp:orinst:) labels in addition to any other useful labelsclose,fix, or any linking keywords when referencing an issueUse
solvesinstead, and assign the PR milestone to the issueJira ticket: SDTEST-3847