Skip to content

Analyzers: Build MUD0002 component descriptors only on cache misses - #13844

Merged
danielchalmers merged 2 commits into
devfrom
perf/analyzer-descriptor-cache-miss
Sep 14, 2026
Merged

danielchalmers merged 2 commits into
devfrom
perf/analyzer-descriptor-cache-miss

Conversation

@danielchalmers

@danielchalmers danielchalmers commented Sep 14, 2026 •

Copy link
Copy Markdown
Member

First of four stacked PRs that speed up the MUD0002 analyzer added in #13831 and #13841.

_componentDescriptors.GetOrAdd(type, ComponentDescriptor.GetComponentDescriptor(...)) built the descriptor before the lookup, so every OpenComponent walked the component's members and scanned the migration catalog, even when the descriptor was already cached.
This passes a cached Func to GetOrAdd instead, so a cache hit does no work and allocates nothing.
netstandard2.0 has no GetOrAdd<TArg> overload, hence the stored delegate.
Concurrent misses can still build a descriptor twice; GetOrAdd keeps the first, as before.

Scenario Before After Paired change, median [IQR]
MudBlazor.Docs build, analyzer time 649 ms 414 ms −293 ms [−359, −132]
MudBlazor.Docs build, analyzer allocations 103.5 MB 69.9 MB −32.7 MB [−34.8, −30.0]
MudBlazor.Docs editor analysis, analyzer time 58.1 ms 51.6 ms −6.1 ms [−10.6, −4.2]
MudBlazor build, analyzer time 51.0 ms 44.7 ms −5.0 ms [−9.9, −2.5]
20 files × 200 components over 16 types 164 ms, 67.4 MB 7.4 ms, 6.2 MB −153 ms, −61.1 MB

Descriptors built while analyzing MudBlazor.Docs drop from 8,176 (one per lookup) to 1,755.
Most of the remaining 1,755 come from inferred generic components, which the third PR in this stack addresses.

How this was measured
  • Inputs are already-built compilations: MudBlazor.Docs (1,189 trees including 1,037 Razor pages) and MudBlazor net10.0 (893 trees), recreated from their own compiler command lines with source-generator output emitted, plus synthetic Razor-shaped files.
  • Each run creates a fresh CompilationWithAnalyzers, so no cached results are reused.
  • Each variant's analyzer DLL is loaded side by side; runs alternate between variants and each change is paired against the previous PR within the same round.
  • Serial analyzer driver, 20 runs after 3 warmups (6 runs for whole-project builds).
  • Analyzer time is Roslyn's per-analyzer execution time.
  • Allocations are GC.GetTotalAllocatedBytes(precise: true) across all threads, minus a no-op analyzer that registers the same actions.
  • "Editor analysis" is semantic diagnostics for MudBlazor.Docs' 12 largest generated Razor documents, one document at a time.
  • Descriptor counts come from temporary counters that are not part of this PR.
  • Windows 11, .NET 10.0.12, Roslyn 5.9 host, analyzer built against its Roslyn 4.7.0 floor, measured on 13e4c48.

@danielchalmers danielchalmers added the performance Related to time/memory/CPU/allocation performance characteristics label Sep 14, 2026
@danielchalmers
danielchalmers added this pull request to stack #13848 September 14, 2026 15:05
@mudbot mudbot Bot added the build CI/CD, packaging, tooling, repository automation, agent instructions label Sep 14, 2026
@danielchalmers danielchalmers removed the build CI/CD, packaging, tooling, repository automation, agent instructions label Sep 14, 2026
@danielchalmers
danielchalmers merged commit 49a365e into dev Sep 14, 2026
11 checks passed
@danielchalmers
danielchalmers deleted the perf/analyzer-descriptor-cache-miss branch September 14, 2026 15:15
This was referenced Sep 27, 2026
This was referenced Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Related to time/memory/CPU/allocation performance characteristics

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant