Skip to content

Try using withContiguousStorageIfAvailable in RangeReplaceableCollection.append(contentsOf:) before falling back to a slow element-by-element loop. #65778

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

Merged
merged 2 commits into from
May 19, 2023

Conversation

Catfish-Man
Copy link
Contributor

Fixes rdar://109059874

Should make a bunch of operations on naive RRC implementations much faster

@Catfish-Man Catfish-Man self-assigned this May 8, 2023
@Catfish-Man
Copy link
Contributor Author

@swift-ci please benchmark


if done == nil {
let approximateCapacity = self.count + newElements.underestimatedCount
self.reserveCapacity(approximateCapacity)
Copy link
Member

@lorentey lorentey May 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for followup work: This reserveCapacity call is extremely undesirable, for the same reason append(_:) doesn't call reserveCapacity(self.count + 1): for contiguous collections, reserveCapacity does not use the usual exponential resizing logic, it allocates precisely as much memory as needed. This makes calling append(contentsOf:) in a loop algorithmically worse than if reserveCapacity wasn't used: in the worst case, it can cause calling append(contentsOf:) n times (with the same argument) to reallocate storage on every single invocation, rather than log(n) times.

Copy link
Member

@lorentey lorentey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beware of #57014: withContiguousStorageIfAvailable can trap by mistake under certain conditions, on OS releases that predate Swift 5.5.

…ion.append(contentsOf:) before falling back to a slow element-by-element loop. Fixes rdar://109059874
@Catfish-Man Catfish-Man force-pushed the contiguous-conundrum branch from 740d037 to 465aa22 Compare May 9, 2023 00:04
@Catfish-Man
Copy link
Contributor Author

@swift-ci please smoke benchmark

@Catfish-Man
Copy link
Contributor Author

adding some benchmarks in #65802

@Catfish-Man
Copy link
Contributor Author

@swift-ci please benchmark

@Catfish-Man
Copy link
Contributor Author

Yup, new benchmarks detect the improvement, to say the least

IMPROVEMENT OLD NEW DELTA RATIO NaiveRRC.init.largeContiguous 21.643 0.0 -100.0% **21644.00x** NaiveRRC.append.largeContiguous 21.628 0.0 -100.0% **21629.00x**

@Catfish-Man
Copy link
Contributor Author

@swift-ci please test

@Catfish-Man
Copy link
Contributor Author

@swift-ci please smoke benchmark

Copy link
Member

@lorentey lorentey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make sure that both paths are exercised in our test suite, by e.g. adding dedicated tests for both. (If we are already testing that, then of course this is moot.)

This is an observable change of calling patterns, so ideally we should also have a test that verifies that withContiguousStorageIfAvailable is invoked -- however, adding that may be more effort than it's worth.

@Catfish-Man
Copy link
Contributor Author

Tests here #65953

@Catfish-Man
Copy link
Contributor Author

@swift-ci please test and merge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants