-
Notifications
You must be signed in to change notification settings - Fork 693
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
Reduce allocations in RuntimeDescription and RuntimeDependencySet #5248
Conversation
These two classes follow a similar construction and clone pattern, and the changes to each are similar. Previously each expected to receive non-null enumerables with input values, which would then be enumerated to materialise copies. In cases where these collections were empty, the allocations are avoidable. This changes the constructors to receive nullable values, allowing singleton collections to be used in such cases. Similarly, when cloning, if the collections are empty, nulls are passed so that these singletons are applied. Also when cloning, the known collection type is cast to to enable allocation-free enumeration of the source when constructing the clone object.
After a few of the other PRs were merged, there's conflicts @drewnoakes |
…-runtime-class-allocations
Merged in |
left.RuntimeIdentifier, | ||
// If collections are empty, pass null to avoid allocations. | ||
inheritedRuntimes.Count == 0 ? null : inheritedRuntimes, | ||
newSets.Count == 0 ? null : newSets); |
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.
newSets
passed to the new overload will no longer be case-insensitive.
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.
Indeed! Fixed in #5321
Fixes #12757 PR NuGet#5248 reworked how construction of `RuntimeDescription` instances happens, partly to reduce the number of redundant collection copies that occurred. As an example of that innefficiency, the prior `RuntimeDesciption.Merge` method would build a dictionary of merged `RuntimeDependencySet` instances, then call a `RuntimeDescription` constructor that would copy those into a new dictionary. The PR added a new private constructor that allowed the copy to be avoided. That change introduced a bug however. It turns out that during the redundant copy a case-insensitive key comparer was specified, while the `Merge` method's dictionary was case-sensitive. So if two different `RuntimeDependencySet` identifiers differed only by case, then the collection created internally within the `Merge` method would contain both instances, then the constructor call would merge them during the subsequent `ToDictionary` call. The fix is to ensure that the `Merge` method uses the correct `StringComparer` for `RuntimeDependencySet` identifiers, to preserve the prior behaviour. Several unit tests have been added to validate the behaviour of `RuntimeDescription.Merge`.
Fixes #12757 PR NuGet#5248 reworked how construction of `RuntimeDescription` instances happens, partly to reduce the number of redundant collection copies that occurred. As an example of that innefficiency, the prior `RuntimeDesciption.Merge` method would build a dictionary of merged `RuntimeDependencySet` instances, then call a `RuntimeDescription` constructor that would copy those into a new dictionary. The PR added a new private constructor that allowed the copy to be avoided. That change introduced a bug however. It turns out that during the redundant copy a case-insensitive key comparer was specified, while the `Merge` method's dictionary was case-sensitive. So if two different `RuntimeDependencySet` identifiers differed only by case, then the collection created internally within the `Merge` method would contain both instances, then the constructor call would merge them during the subsequent `ToDictionary` call. The fix is to ensure that the `Merge` method uses the correct `StringComparer` for `RuntimeDependencySet` identifiers, to preserve the prior behaviour. Several unit tests have been added to validate the behaviour of `RuntimeDescription.Merge`.
Bug
Fixes: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1837525
Fixes: NuGet/Home#12714
Regression? Last working version:
Description
The
RuntimeDescription
andRuntimeDependencySet
classes follow similar construction and clone patterns, and the changes to each class here are similar.Previously each expected to receive non-null enumerables with input values, which would then be enumerated to materialise copies.
In cases where these collections were empty, the allocations are avoidable.
This changes the constructors to receive nullable values, allowing singleton collections to be used in such cases.
Similarly, when cloning, if the collections are empty, nulls are passed so that these singletons are applied. Also when cloning, the known collection type is cast to to enable allocation-free enumeration of the source when constructing the clone object.
PR Checklist
PR has a meaningful title
PR has a linked issue.
Described changes
Tests
Documentation