perf: halve the generator's time and allocations per pass - #335
Merged
Merged
Conversation
glennawatson
force-pushed
the
perf/generator-allocations
branch
from
September 26, 2026 09:07
0db9d48 to
aa44c88
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #335 +/- ##
============================================
+ Coverage 55.47% 100.00% +44.52%
============================================
Files 7 20 +13
Lines 530 976 +446
Branches 60 171 +111
============================================
+ Hits 294 976 +682
+ Misses 224 0 -224
+ Partials 12 0 -12 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Summary
The generator does about half the work per build and IDE edit, and the code it writes compiles for every thread safety mode.
resolver.Register<T>(() => ...), are now rejected from syntax before any binding.SourceWriter. Registrations are laid out one dependency per line, and a missing dependency throws through one helper per file. Lazy singletons share the method's single closure instead of adding one each. With no registrations, no registrations file is emitted.RegisterLazySingleton<TInterface, TConcrete>(LazyThreadSafetyMode.X)compiles. The mode used to be written as a bare member name. Modes and contracts held in fields are now fully qualified..editorconfig. Findings are fixed in code, not suppressed.GcVerbosetraces. Results and how to read the traces are insrc/benchmarks/README.md.ACCEPT_SNAPSHOTS=1to accept changes. The fixed marker source is stored once instead of by every test, and a test keeps every snapshot path within the Windows path limit on CI..gitattributeschecks every text file out with LF on every platform, as the analyzers require.Microsoft.CodeAnalysis.CSharpstays at 4.14 as the oldest supported compiler. Third-party actions and the sharedactions-commonworkflows are pinned to commit SHAs.Why
A
CreateSyntaxProvidertransform re-runs for every matching call whenever the compilation changes, so every keystroke re-bound every call namedRegisterin the project, lambdas included. The trace put 86% of an unrelated edit's cost there. Separately, snapshot tests never checked that the generated code compiles, which hid the thread safety mode bug.Breaking changes
None. Registration order, resolution behaviour and exception messages are unchanged. The generated registrations file has a new layout.
How this was verified
Notes for the reviewer
Generator.cs,RoslynHelpers.IsRegistrationInvocationandMetadataExtractor.cs, thenCodeGeneration/CodeGenerator.cs..verified.cs/.verified.txtsnapshots (existing registration snapshots are unchanged apart from the new layout);SetupIOCis already a direct call. Intercepting the markers would change when registration happens and on which resolver.actions-commonis pinned to amaincommit. It has no release tags, so each of those pins carries a# maincomment.Checklist