Repository navigation
perf: cache source member attribute metadata during compilationPerf/compilation scoped attribute cache - #1022
Conversation
|
HI, @vb-kalei. |
|
This is an improved version #1021 or fully independent PR? |
|
@DocSvartz |
|
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. |
|
@vb-kalei Thanks! |
|
@DocSvartz Thanks for merging! |
Updated [Mapster](https://github.com/MapsterMapper/Mapster) from 10.0.12 to 10.0.13. <details> <summary>Release notes</summary> _Sourced from [Mapster's releases](https://github.com/MapsterMapper/Mapster/releases)._ ## 10.0.13 ## What's Changed * Improvements for Mapster Tool by @DocSvartz in MapsterMapper/Mapster#1016 * Fix Issue #1017 and refactoring Mapster.Tool for ease of testing by @DocSvartz in MapsterMapper/Mapster#1019 * perf: index current members when filtering hidden members by @vb-kalei in MapsterMapper/Mapster#1023 * perf: cache source member attribute metadata during compilationPerf/compilation scoped attribute cache by @vb-kalei in MapsterMapper/Mapster#1022 ## New Contributors * @vb-kalei made their first contribution in MapsterMapper/Mapster#1023 **Full Changelog**: MapsterMapper/Mapster@v10.0.12...v10.0.13 ## 10.0.13-pre02 ## What's Changed * Improvements for Mapster Tool by @DocSvartz in MapsterMapper/Mapster#1016 **Full Changelog**: MapsterMapper/Mapster@v10.0.12...v10.0.13-pre02 Commits viewable in [compare view](MapsterMapper/Mapster@v10.0.12...v10.0.13). </details> Updated [Mapster.DependencyInjection](https://github.com/MapsterMapper/Mapster) from 10.0.12 to 10.0.13. <details> <summary>Release notes</summary> _Sourced from [Mapster.DependencyInjection's releases](https://github.com/MapsterMapper/Mapster/releases)._ ## 10.0.13 ## What's Changed * Improvements for Mapster Tool by @DocSvartz in MapsterMapper/Mapster#1016 * Fix Issue #1017 and refactoring Mapster.Tool for ease of testing by @DocSvartz in MapsterMapper/Mapster#1019 * perf: index current members when filtering hidden members by @vb-kalei in MapsterMapper/Mapster#1023 * perf: cache source member attribute metadata during compilationPerf/compilation scoped attribute cache by @vb-kalei in MapsterMapper/Mapster#1022 ## New Contributors * @vb-kalei made their first contribution in MapsterMapper/Mapster#1023 **Full Changelog**: MapsterMapper/Mapster@v10.0.12...v10.0.13 ## 10.0.13-pre02 ## What's Changed * Improvements for Mapster Tool by @DocSvartz in MapsterMapper/Mapster#1016 **Full Changelog**: MapsterMapper/Mapster@v10.0.12...v10.0.13-pre02 Commits viewable in [compare view](MapsterMapper/Mapster@v10.0.12...v10.0.13). </details> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
Hi, @vb-kalei, @andrerav, @stagep In version 10.1, there will be a global cache (a cache at the level of the configuration instance itself), since the process of converting a Type into an IMemberModelEx[] is a preparatory step. This process ( Type -> IMemberModelEx[] ) works only with data created at compile time that does not depend on the mapping configuration, With the exception of one setting - The cache creation process takes place for all members of a type. |
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.