perf: cache source member attribute metadata during compilationPerf/compilation scoped attribute cache - #1022
Open
vb-kalei wants to merge 1 commit into
Conversation
Contributor
|
HI, @vb-kalei. |
Contributor
|
This is an improved version #1021 or fully independent PR? |
Author
|
@DocSvartz |
Contributor
|
Ok, I'll need to check that this doesn't conflict with the changes for 10.1. Then it will go into the next version. |
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.
This is an AI-assisted performance optimization that speeded up mapper compilation times in our project by 30%.
The documentation of the changes is also AI generated, I hope it would be useful:
Motivation
During compilation, source member matching repeatedly checks
AdaptIgnoreAttribute, checksAdaptMemberAttributefor eligibility, and checksAdaptMemberAttributeagain for name resolution. Repeated enumeration creates newPropertyModelandFieldModelwrappers, so caching on individual wrappers would not share metadata between scans.Historical application profiling motivated this change, but is not upstream benchmark evidence. Reported reflection CPU shares changed from 27.37% to 8.90%, with total attributed samples changing from 8,578 to 3,275. Inclusive samples overlap; these are not elapsed timings or call counts.
A separate application's unchanged three-configuration compilation workload reported mean elapsed times of 17.765 seconds with the prototype versus 27.200 seconds with injection bypassed. This involved only two on and three off runs, grouped rather than fully interleaved, Debug builds, fresh processes, no debugger/profiler, and both variants already included the independent hidden-member fix. Cache-off retained cache infrastructure and cleanup overhead. These observations have not been reproduced here and are motivation only, not a general 34.7% improvement claim.
Design and ownership
TypeAdapterConfig.CreateMapExpressioncreates aCompileContextowning an internalAttributeMetadataCache.CompileArgumentobjects share that context. Separate Map, MapToTarget, and Projection roots have independent contexts. A configuration fork can share metadata within a root without sharing eligibility or naming decisions.MemberInfo, using its equality semantics, not by name or metadata token alone. Tests cover closed generic, hidden, inherited, and differing reflected-type property identities.PropertyModel/FieldModeltypes are unchanged. Internal overloads optionally receive the cache. There are no new public APIs or configuration switches.ValueAccessingStrategy.PropertyOrFieldFnopts source enumeration in. This is the repeated-scan path motivating the change. Destination enumeration, flattening, unflattening, parameter models, and unrelated reflection remain outside the cache.finallycallsCompleteon success and failure. It clears entries and permanently disables population. Models retained by callbacks, and contexts retained throughCompileException.Argument, subsequently fall back to reflection.CompileContextthread-safe. There is no static, thread-static, global, or AsyncLocal cache.Regression coverage
The application regression tests were migrated to MSTest/Shouldly using the existing friend assembly instead of NUnit and private-field reflection. The new fixture contains 17 executed test cases covering:
Retention assertions use weak references and forced collection outside non-inlined setup helpers, not allocated-byte counts, private dictionary field names, or timing thresholds. They prove these specific ownership properties, not absence of every possible application memory leak.
Validation
Environment: Windows, .NET SDK 10.0.401; installed .NET runtime families 10, 9, and 8, plus .NET Framework 4.8. Base: development commit
4a8aaa415d434ff86b0182617ad2062ab1794a19.