[bgen] Cache attribute lookups to reduce memory allocations#25782
[bgen] Cache attribute lookups to reduce memory allocations#25782rolfbjarne wants to merge 10 commits into
Conversation
GetCustomAttributes<T> was being called repeatedly on the same providers. Each call would re-invoke GetCustomAttributesData, iterate all attributes, and re-instantiate matching ones. Cache results in a Dictionary<(ICustomAttributeProvider, Type), object> so subsequent queries for the same provider+type return instantly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a Dictionary<(ICustomAttributeProvider, Type), bool> cache for HasAttribute<T> queries. This method is called thousands of times per platform with the same arguments. Caching the boolean result avoids repeated GetCustomAttributesData() + type comparison work. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tory Cache no-version/no-message IntroducedAttribute and UnavailableAttribute instances as static singletons (one per platform). Return cached instances from CreateNoVersionSupportedAttribute, CreateUnsupportedAttribute, and CloneFromOtherPlatform when applicable, avoiding repeated heap allocations for identical platform attributes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cache GetAllParentAttributes results per MemberInfo context. Since callers only read from the returned list (never mutate it), the cached list can be safely shared across multiple callers with the same context. This avoids re-walking the parent chain and re-querying attributes for the same member on repeated calls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…in AttributeFactory - Cache Type[] arrays for attribute constructors to avoid repeated allocations - Cache ConstructorInfo lookups per (type, argTypes) to avoid repeated reflection - Cache Version objects in AvailabilityBaseAttribute to avoid creating new instances for the same version values Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cache the ExportAttribute lookups for property getters and setters to avoid repeated attribute queries on the same PropertyInfo. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
This PR improves bgen performance by adding several reflection/attribute-related caches to reduce repeated allocations and GC pressure during binding generation.
Changes:
- Cache
ExportAttributelookups for property getters/setters and cache parent availability attribute traversal inGenerator. - Cache
GetCustomAttributes<T>andHasAttribute<T>results inAttributeManagerto avoid repeated reflection and attribute conversion. - Add constructor/argument caching in
AttributeFactory/AttributeFactory.ConstructorArgumentsand reuse singleton availability attributes for common no-version cases.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/bgen/Generator.cs | Adds caches for getter/setter ExportAttribute lookups and parent availability attribute collection. |
| src/bgen/AttributeManager.cs | Adds per-(provider,type) caches for GetCustomAttributes<T> and HasAttribute<T>. |
| src/bgen/AttributeFactory.cs | Caches attribute constructor lookups and reuses singleton no-version availability attributes. |
| src/bgen/AttributeFactory.ConstructorArguments.cs | Reuses static Type[] constructor signature arrays to avoid repeated allocations. |
This comment has been minimized.
This comment has been minimized.
Move the constructorCache dictionary from the static AttributeFactory class to the instance-based AttributeManager class. This eliminates the static mutable state that could be problematic when tests run in parallel. The cache is passed through to AttributeFactory and AttributeConversionManager methods as a parameter. Convenience overloads without the parameter are kept for test compatibility (they use a static fallback cache). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
Remove the two convenience CreateNewAttribute overloads (that didn't take an AttributeManager parameter) and the static defaultConstructorCache they used. Remove the corresponding tests that called those overloads. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| [TestFixture] | ||
| [Parallelizable (ParallelScope.All)] | ||
| public class AttributeFactoryTests { |
| public virtual T [] GetCustomAttributes<T> (ICustomAttributeProvider? provider) where T : System.Attribute | ||
| { | ||
| return FilterAttributes<T> (GetAttributes (provider), provider); | ||
| if (provider is null) | ||
| return Array.Empty<T> (); | ||
|
|
||
| var key = (provider, typeof (T)); | ||
| if (attributeCache.TryGetValue (key, out var cached)) | ||
| return (T []) cached; | ||
|
|
||
| var result = FilterAttributes<T> (GetAttributes (provider), provider); | ||
| attributeCache [key] = result; | ||
| return result; |
✅ [PR Build #f1dfcf9] Build passed (Detect API changes) ✅Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
✅ [PR Build #f1dfcf9] Build passed (Build packages) ✅Pipeline on Agent |
✅ API diff for current PR / commitNET (empty diffs)✅ API diff vs stableNET (empty diffs)ℹ️ Generator diffGenerator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes) Pipeline on Agent |
✅ [PR Build #f1dfcf9] Build passed (Build macOS tests) ✅Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
🚀 [CI Build #f1dfcf9] Test results 🚀Test results✅ All tests passed on VSTS: test results. 🎉 All 207 tests passed 🎉 Tests counts✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download macOS tests✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download Linux Build VerificationPipeline on Agent |
Cache various attribute query results in bgen to avoid repeated reflection and
attribute conversion work. This reduces total memory allocations by ~22% and
GC pressure by ~25-39% when generating bindings.
Changes:
GetCustomAttributes<T>results per (provider, type) pairHasAttribute<T>results to avoid repeatedGetCustomAttributesData()callsAttributeFactoryGetAllParentAttributesresults perMemberInfoConstructorInfolookups per (type, argTypes) to avoid repeated reflectionType[]arrays for attribute constructorsExportAttributeresults perPropertyInfoPerformance (tvOS bindings, 3-run averages):