Skip to content

perf(analyzers): cache test framework discovery per compilation - #98

Merged
samtrion merged 1 commit into
mainfrom
perf/analyzer-framework-discovery-cache
Aug 1, 2026
Merged

perf(analyzers): cache test framework discovery per compilation#98
samtrion merged 1 commit into
mainfrom
perf/analyzer-framework-discovery-cache

Conversation

@samtrion

@samtrion samtrion commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • FindAwakeFrameworks in TestSurfaceAnalysis re-ran TestMethodDiscovery.FindTestMethods — a full syntax-tree walk — for every other registered test framework on every analyzer Execute call, with no caching between analyzer instances.
  • On a project that is "awake" on N test frameworks at once (dual xUnit versions being the ordinary, documented case, not an exotic one), each of the N framework analyzers independently redid the discovery walk for the other N-1 frameworks, scaling to roughly N times more discovery walks than necessary, none of them shared.
  • Fixed by memoizing FindTestMethods results per (Compilation, probe type), using the same ConditionalWeakTable<Compilation, ConcurrentDictionary<Type, ImmutableArray<IMethodSymbol>>> pattern already used for the tests-without-production-reference cache a few lines above. Each framework's discovery now runs at most once per compilation regardless of how many analyzer instances query it. This is a pure performance fix; behavior is unchanged.

Test plan

  • Added TestSurfaceAnalysisTestMethodCacheTests covering: cache hit across repeated calls for the same compilation and framework, independent results per framework, independent results per compilation, and the two-framework scenario the fix targets (a later analyzer reusing an earlier one's discovery walk instead of repeating it).
  • dotnet test ./Frameshift.slnx passes across all target frameworks (29392 tests, 0 failed).
  • dotnet csharpier format . run; working tree clean of formatting diffs.

FindAwakeFrameworks re-ran TestMethodDiscovery.FindTestMethods, a full
syntax-tree walk, for every other registered test framework on every
Execute call, with no caching between analyzer instances. A project
awake on N frameworks at once (dual xUnit versions being the ordinary
case, not an exotic one) therefore paid for roughly N times more
discovery walks than necessary, none of them shared across the
analyzers that all asked the same question about the same
compilation.

Memoize FindTestMethods results per (Compilation, probe type) using
the same ConditionalWeakTable<Compilation, ConcurrentDictionary<Type,
ImmutableArray<IMethodSymbol>>> pattern already used for the
tests-without-production-reference cache. Each framework's discovery
now runs at most once per compilation, however many awake frameworks
end up asking for it. The outer table is keyed by Compilation and
evicted by the garbage collector together with it; the inner
ConcurrentDictionary keeps two racing analyzers from computing the
same entry twice. Behavior is unchanged, this is a pure performance
fix.

Adds unit tests covering the new cache: a hit across repeated calls
for the same compilation and framework, independent results per
framework, independent results per compilation, and the two-framework
scenario the fix targets, where a later analyzer reuses an earlier
one's discovery walk instead of repeating it.
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • state:ready for merge

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9305fe2b-bdae-4968-a266-74ae107a8d62

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.26%. Comparing base (fd0e4ae) to head (862b5bd).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #98   +/-   ##
=======================================
  Coverage   95.26%   95.26%           
=======================================
  Files          88       88           
  Lines        5850     5854    +4     
  Branches     1273     1274    +1     
=======================================
+ Hits         5573     5577    +4     
  Misses        122      122           
  Partials      155      155           

☔ View full report in Codecov by Harness.
📢 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.

@samtrion
samtrion merged commit 36768f2 into main Aug 1, 2026
12 checks passed
@samtrion
samtrion deleted the perf/analyzer-framework-discovery-cache branch August 1, 2026 22:43
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