-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🐇 Avoid generic enumeration in ChecksumCollection.FindAsync #53959
Conversation
See AB#1333566
internal static async Task FindAsync<TState>( | ||
TextDocumentStates<TState> documentStates, | ||
HashSet<Checksum> searchingChecksumsLeft, | ||
Dictionary<Checksum, object> result, | ||
CancellationToken cancellationToken) where TState : TextDocumentState | ||
{ | ||
foreach (var state in documentStates.States) | ||
foreach (var (_, state) in documentStates.States) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 The generic enumeration was responsible for 89% of the total allocations in searching for assets (10% of the total for the entire VS recording). This fixes a 16.10 regression introduced in #51526.
=> projectState.DocumentStates.States | ||
.Concat(projectState.AdditionalDocumentStates.States) | ||
.Concat(projectState.AnalyzerConfigDocumentStates.States); | ||
=> projectState.DocumentStates.States.Values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ This line is the same in this pull request as it was before this pull request. The performance improvement was applied targeting the single hot path method which is now marked with [PerformanceSensitive]
. Other methods were optimized where trivial, or left the same.
@@ -83,8 +83,8 @@ public TState GetRequiredState(DocumentId documentId) | |||
/// <summary> | |||
/// States ordered by <see cref="DocumentId"/>. | |||
/// </summary> | |||
public IEnumerable<TState> States | |||
=> _map.Values; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add ImmutableSortedDictionary.Values to banned APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also make this a struct enumerator and keep the callers as they are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add ImmutableSortedDictionary.Values to banned APIs?
I wouldn't go this far. The PerformanceSensitive
attribute is designed with the intent of statically validating this case where it matters.
We could also make this a struct enumerator and keep the callers as they are.
This is a bit difficult. I added these struct enumerators when I wrote ImmutableSortedTreeDictionary<TKey, TValue>
but it would be a binary breaking change to incorporate it back into System.Collections.Immutable. See dotnet/runtime#13927 for more details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I understand we can't update ImmutableSortedTreeDictionary, but we can either create an extension method GetValues(ImmutableSortedTreeDictionary<K,V>)
or make specialized struct enumerator just for this property.
See AB#1333566