-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[WIP] [stdlib] Improve performance of Array initialization with known capacity #17311
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
@swift-ci Please smoke test |
This doesn't seem like the right solution. I was under the impression that there was a single |
Ah, it might be that we just retain the Empty Array Storage instance. It was mostly that `_swift_release_` of `_EmptyArrayStorage` and `ContiguousArrayStorage` was showing up as a major bottleneck in Instruments.
Why don't you think this is the right solution (I haven't looked into the test failure yet)? And would you know of a different way to mitigate the issue?
|
stdlib/public/core/Collection.swift
Outdated
result.reserveCapacity(n) | ||
let result: ContiguousArray<T> | ||
var p: UnsafeMutablePointer<T> | ||
(result, p) = ContiguousArray<T>._allocateUninitialized(count) |
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.
Can you switch count
to n
here, in case a collection is super broken and returns a different count here compared to up above? Otherwise we might write past the buffer in the loop below.
e764b0f
to
3727020
Compare
@swift-ci Please smoke test |
AnySequence just forwards the call to map to its underlying storage which used to be an Array (and thus a collection). stride(from:through:by:) creates a proper Sequence.
3727020
to
fc36bed
Compare
@swift-ci Please smoke test |
Like I said, this is a narrow fix that will only work within the standard library for a general problem that affects all users. We need to figure out a way of solving it for everyone not just paper over it. Either in code inside the library (find some way that starting with an empty array is free) or via changing the API (i.e. allowing one-shot create-and-reserve). Once we have that solution, we can consider a localized temporary fix like this but we need to do it in that order. |
@swift-ci Please build toolchain |
So #17389 should provide what's needed – the ability to init with a capacity. This needs evolution approval, but maybe we can implement it with underscores and use it in the mean-time. In fact, it would be interesting to see if it yields a performance benefit to do use the full proposal to implement map and similar functions. |
This seems to be exactly what I need. Closing this and I'll wait for @natecook1000's implementation. |
cc @natecook1000 – looks like this would be a great candidate for proving out the changes you're proposing for one shot initialization. It might even make sense to land underscored implementations in master and then use them to implement map, wdyt? |
Currently the initialisation of an array with a known number of elements has two performance problems:
append
,_ContiguousArrayStorage
is retained and released whenappend
is exited. Since the Array already holds a reference to its storage this shouldn't be necessary.The fix
I've optimised the
Collection.map
andSequence.map
to directly allocate the required storage and write to its memory directly by calling to_allocateUninitialized
instead ofContiguousArray.init()
.