-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Avoid extra Array.Copy in List<T>.Insert(Range) when the list is full
#90089
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
Conversation
Originally there are 3 `Array.Copy` during `List<T>.Insert` when `Capacity` is maxed out. Avoid this extra copy with a modified `Grow`. Fix dotnet#89915
|
Tagging subscribers to this area: @dotnet/area-system-collections Issue DetailsOriginally there are 3 Microbenchmark at the issue page. Fix #89915
|
List at capacityList at capacity
List at capacityArray.Copy when inserting to List<T> at capacity
|
If I understand it correctly, this gives us up to 3.5% imprvoement for the best case - insertion at the 0 index in a large array, right? |
The gain is 20%-ish for insertion at 0 into 10000-long list.
(InsertRange: 100->100 or 10000->10000) The correct benchmark should utilize |
Array.Copy when inserting to List<T> at capacityArray.Copy when inserting into a full List<T>
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs
Outdated
Show resolved
Hide resolved
Array.Copy when inserting into a full List<T>Array.Copy in List<T>.Insert(Range) when the list is full
Maybe. It would be a tradeoff between steady state speed vs. and startup time and memory consumption. This PR is a similar tradeoff at smaller scale. It makes each |
I just did a microbenchmark and it seems replacing
Yes you are right. |
The bigger impact here would be with smaller collections, since |
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.
@karajas Thank you for your contribution!
PTAL at my comments, apply the changes and share updated perf numbers. Thanks!
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs
Show resolved
Hide resolved
code formatting Co-authored-by: Adam Sitnik <adam.sitnik@gmail.com>
Shared logics of getting new capacities in Grow & GrowForInsertion are moved to a separated method.
code
code |
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.
LGTM, thank you for your contribution @karakasa !
|
@adamsitnik btw do you have thoughts on how to benchmark this, which requires a new Currently I added a baseline function and subtract results, but it can be unstable and troublesome. |
|
@karakasa this is tricky. You can combine |
|
It doesn't necessarily require a new List. For a small amount of overhead, it could do: CollectionsMarshal.SetCount(list, 0); or similar to put it back to the desired configuration. It could even use UnsafeAccessor to poke at list internals directly. |
|
Original issue: #89915 (by me) |
Originally there are 3
Array.CopyduringList<T>.InsertwhenCapacityis maxed out. Avoid one extra copy with a modifiedGrow.Microbenchmark in following comments.
List<T>.InsertRangealso benefits from similar patterns. Performance is ~20% better for best cases.Fix #89915