This program is mostly noise to prevent the optimiser from killing the program, but at its root it allocates a big Array and then calls workIt in a loop. workIt makes a copy of the array, removes all the elements from it (keeping capacity), and then iterates the (now empty) array and does some math.
When run under time profiler in Instruments this program spends all of its time (and it is a noticeable amount of time) in memmove. This is because the implementation of Array.removeAll(keepingCapacity🙂 is pessimistic for keepingCapacity=true:
replaceSubrange is extremely general, and so it keeps the contents of the Array as it is. This means, if the Array is not uniquely referenced, it wastes its time copying over the entire contents of the buffer, which it then promptly throws away.
The text was updated successfully, but these errors were encountered:
The same optimization opportunity also applies on most other Array mutations – AFAIR currently they all guarantee uniqueness as a standalone step before performing the mutation. In most cases it would make much more sense to fall back to generating a new Array instance directly, rather than copying the existing one then mutating the copy.
The tradeoff here is that adding a new code path roughly doubles the code size of these operations, which may have unintended consequences. Still, this is definitely something we should try fixing.
Environment
Apple Swift version 5.3.1 (swiftlang-1200.0.43 clang-1200.0.32.8)
Additional Detail from JIRA
md5: 724c0c846234a1ede0885d027c480e99
Issue Description:
Here's a simple (and stupid) Swift program:
This program is mostly noise to prevent the optimiser from killing the program, but at its root it allocates a big Array and then calls
workIt
in a loop.workIt
makes a copy of the array, removes all the elements from it (keeping capacity), and then iterates the (now empty) array and does some math.When run under time profiler in Instruments this program spends all of its time (and it is a noticeable amount of time) in
memmove
. This is because the implementation ofArray.removeAll(keepingCapacity🙂
is pessimistic forkeepingCapacity=true
:replaceSubrange
is extremely general, and so it keeps the contents of the Array as it is. This means, if the Array is not uniquely referenced, it wastes its time copying over the entire contents of the buffer, which it then promptly throws away.The text was updated successfully, but these errors were encountered: