Skip to content

[Optimization] avoid copying for intersectInPlace() #419

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

Closed
wants to merge 2 commits into from

Conversation

dduan
Copy link
Contributor

@dduan dduan commented Dec 11, 2015

By droping down to native storage implementation, we can perform in place
intersection without making a copy of the set.

Clears tests in validation-test/stdlib/Set.swift

@dduan dduan force-pushed the optimize_set_intersectInPlace branch from 96a06b0 to 7848d18 Compare December 11, 2015 08:59
@dduan dduan changed the title Set: avoid copy during intersectInPlace [Optimization] avoid copy during intersectInPlace Dec 11, 2015
@dduan dduan changed the title [Optimization] avoid copy during intersectInPlace [Optimization] avoid copy for intersectInPlace() Dec 11, 2015
@nadavrot
Copy link
Contributor

@dduan Did you measure the performance of this change? Are you seeing any wins?

@dduan
Copy link
Contributor Author

dduan commented Dec 11, 2015

@nadavrot to be honest, I only took the hint from the "FIXME" comment and reasoned through the code. I'd love to collect some empirical evidence. Is there any established tools/convention for performance measuring for swift?

while bucket < native.capacity {
if native.isInitializedEntry(bucket) &&
!sequence.contains(native.keyAt(bucket)) {
native.destroyEntryAt(bucket)
Copy link
Contributor

Choose a reason for hiding this comment

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

Indentation is 2 space.

Copy link
Contributor

Choose a reason for hiding this comment

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

Please leave a FIXME(performance) comment about the necessity to shrink the storage.

@dduan dduan force-pushed the optimize_set_intersectInPlace branch from 7848d18 to 193e1d6 Compare December 11, 2015 21:55
var bucket = 0
while bucket < native.capacity {
if native.isInitializedEntry(bucket) &&
!sequence.contains(native.keyAt(bucket)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

SequenceType.contains() consumes the sequence. If our tests didn't catch this, it means this patch needs to add tests that use intersectInPlace() with MinimalSequence as the argument.

To fix this issue, you need to use the _preprocessingPass() method and only query the sequence directly multiple times when it is multi-pass. Otherwise, the sequence needs to be copied to a contiguous array first.

@gribozavr
Copy link
Contributor

@dduan Thank you for the patch. I support this change, but we need some changes to make sure we keep the code testable and tested.

Please take a look at this comment in the file:

   //
   // APIs below this comment should be implemented strictly in terms of
   // *public* APIs above.  `_variantStorage` should not be accessed directly.
   //
   // This separates concerns for testing.  Tests for the following APIs need
   // not to concern themselves with testing correctness of behavior of
   // underlying storage (and different variants of it), only correctness of the
   // API itself.
   //

Your change needs to move the method to a different category, and expand tests for this method to be more extensive (that is, to test with both native and bridged sets).

@dduan
Copy link
Contributor Author

dduan commented Dec 11, 2015

@gribozavr thanks for the comments. I'll make the changes when I get the time.

@nadavrot
Copy link
Contributor

@dduan At the moment there is no good way to test the performance of your patch. Can you write a small benchmark program and test the performance before/after? Adding code to the standard library has a cost (in terms of readability and compile time) and we need to have at least on example that shows a performance win.

@gribozavr

@dduan
Copy link
Contributor Author

dduan commented Dec 11, 2015

@nadavrot will do!

@dduan
Copy link
Contributor Author

dduan commented Dec 12, 2015

@nadavrot I ran this program and the speed improvement is around 42% percent (no joke!). Here's the output from my late 2013 MBP with i7:

unoptimized, —debug-swift:
small ∩ large * 100 -- 0.291758000850677
large ∩ small * 100 -- 7.83746302127838
small ∩ small * 100 -- 0.297053933143616
large ∩ large * 100 -- 18.2310382127762
total time spent ----- 26.6573131680489

optimized, —debug-swift
small ∩ large * 100 -- 0.0793769359588623
large ∩ small * 100 -- 7.71100395917892
small ∩ small * 100 -- 0.0776850581169128
large ∩ large * 100 -- 7.35030424594879
total time spent ----- 15.2183701992035

@lattner
Copy link
Contributor

lattner commented Dec 12, 2015

Whoa!

@dduan dduan force-pushed the optimize_set_intersectInPlace branch from 193e1d6 to c0bfab5 Compare December 12, 2015 09:19
By droping down to native storage implementation, we can perform in place
intersection without making a copy of the set.
@dduan dduan force-pushed the optimize_set_intersectInPlace branch from c0bfab5 to 101d698 Compare December 12, 2015 09:45
@dduan dduan changed the title [Optimization] avoid copy for intersectInPlace() [Optimization] avoid copying for intersectInPlace() Dec 12, 2015
@dduan dduan force-pushed the optimize_set_intersectInPlace branch from f16fc4e to 5a79983 Compare December 12, 2015 21:09
@dduan dduan force-pushed the optimize_set_intersectInPlace branch from 5a79983 to a0ff640 Compare December 12, 2015 21:48
@dduan
Copy link
Contributor Author

dduan commented Dec 12, 2015

@gribozavr I think I've addressed most of your comments. Care to take another look?

@lattner right back at you!

@nadavrot
Copy link
Contributor

@dduan Thank you. The numbers look excellent!

@dduan
Copy link
Contributor Author

dduan commented Dec 16, 2015

Closing this one for now. If done right, optimization here would also speed up removeAll(). See discussion on another PR for detail.

Thanks @nadavrot @gribozavr

@dduan dduan closed this Dec 16, 2015
@dduan dduan deleted the optimize_set_intersectInPlace branch December 23, 2019 21:48
freak4pc pushed a commit to freak4pc/swift that referenced this pull request Sep 28, 2022
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.

4 participants