perf(codegen): cache LibraryTypes per compilation - #11363
Merged
ReubenBond merged 2 commits intoOct 1, 2026
Merged
Conversation
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>
Contributor
Code coverage
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
approved these changes
Oct 1, 2026
Member
|
Nice work, @koenbeuk! Thank you |
This was referenced Oct 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #11362.
Problem
LibraryTypes.FromCompilationresolves about a hundred well-known types withGetTypeByMetadataNameand 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..ctoraccounted for about 30% of generator CPU time.Change
Cache one
LibraryTypesperCompilationin aConditionalWeakTable.optionsargument was already unused.LibraryTypesreads only static constants fromCodeGeneratorOptions, so the compilation is the only key.ConcurrentDictionarykeyed by symbol, which stays valid for the whole compilation.ConditionalWeakTabledoesn't keep a compilation alive.LibraryTypesreferences 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 buildand 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.main825aae7)[GenerateSerializer]types, 64 grain interfaces, 433 grain methods.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