Skip to content

perf(codegen): cache LibraryTypes per compilation - #11363

Merged
ReubenBond merged 2 commits into
dotnet:mainfrom
koenbeuk:perf/codegen-cache-library-types
Oct 1, 2026
Merged

ReubenBond merged 2 commits into
dotnet:mainfrom
koenbeuk:perf/codegen-cache-library-types

Conversation

@koenbeuk

@koenbeuk koenbeuk commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Part of #11362.

Problem

LibraryTypes.FromCompilation resolves about a hundred well-known types with GetTypeByMetadataName and builds the well-known codec and copier tables. The per-type step for [GenerateSerializer] types (SerializableSourceOutputGenerator.CreateSerializableTypeResult) creates a new instance for every type. Roslyn re-runs that transform for every matched type whenever the compilation changes, so every edit repeats this work once per serializable type. In a profile of a comment-only edit on a 1,280-type assembly, LibraryTypes..ctor accounted for about 30% of generator CPU time.

Change

Cache one LibraryTypes per Compilation in a ConditionalWeakTable.

  • The options argument was already unused. LibraryTypes reads only static constants from CodeGeneratorOptions, so the compilation is the only key.
  • Its only mutable state, the shallow-copyable cache, is a ConcurrentDictionary keyed by symbol, which stays valid for the whole compilation.
  • ConditionalWeakTable doesn't keep a compilation alive. LibraryTypes references the compilation it's keyed on, which the table handles.

Generated output is byte-identical: I compared all 1,349 generated files on the large workload below.

Results

Synthetic grain-abstractions projects built against this branch with dotnet build and the compiler server warm. Generator times come from -p:ReportAnalyzer=true. Each value is the median of 5 runs. Details of the setup are in #11362.

Workload Baseline (main 825aae7) This PR Change
Generator, rebuild Large 5.30s 3.38s −36%
Generator, edit Large 5.13s 3.53s −31%
CoreCompile, rebuild Large 8.15s 6.21s −24%
CoreCompile, edit Large 8.15s 6.39s −22%
Generator, rebuild Small 0.78s 0.72s −8%
Generator, edit Small 0.73s 0.49s −33%
  • Large: 1,280 [GenerateSerializer] types, 64 grain interfaces, 433 grain methods.
  • Small: 160 types, 8 interfaces, 97 methods.
  • Edit: a comment appended to a file that declares no Orleans types.

Measured on an AMD Ryzen 9 7900X (24 logical cores), Windows 11, .NET SDK 10.0.401.

🤖 Generated with Claude Code

Microsoft Reviewers: Open in CodeFlow

LibraryTypes resolves roughly a hundred well-known types and builds the
codec and copier tables. The per-type serializable pipeline step created
a new instance for every [GenerateSerializer] type, and Roslyn re-runs
that step for every type on every compilation, so each edit repeated
this work once per type.

LibraryTypes only depends on the compilation (the options argument was
unused) and its only mutable state is a thread-safe cache that is valid
for the whole compilation, so share one instance per compilation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@koenbeuk
koenbeuk requested a review from ReubenBond as a code owner October 1, 2026 00:40
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage

Metric Pull request
Lines 82.86% (115,413 / 139,283)
Branches 72.18% (33,497 / 46,407)

Report-only conclusion: current-main baseline stale.

The newest successful coverage run tested 6bf11ad, not current main 825aae7.

Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities.

The comparison remains report-only while normal line and branch variance is calibrated.

Coverage details

@ReubenBond
ReubenBond merged commit ef8c404 into dotnet:main Oct 1, 2026
73 checks passed
@ReubenBond

Copy link
Copy Markdown
Member

Nice work, @koenbeuk! Thank you

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.

2 participants