-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[stdlib] Resolving some FIXME comments on Set type. #20631
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
Welcome to the Swift open source project, @LucianoPAlmeida! This looks great. Could you change your additions to use 2-space indentation? Once that's done we can kick off a test. |
For sure @natecook1000, fixed indentation :)) |
@swift-ci please smoke test |
@swift-ci please benchmark |
Build comment file:Performance: -Onone
How to read the dataThe tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.If you see any unexpected regressions, you should consider fixing the Noise: Sometimes the performance results (not code size!) contain false Hardware Overview
|
Hey guys :)) |
@@ -712,7 +712,8 @@ extension Set: SetAlgebra { | |||
@inlinable | |||
public func isSubset<S: Sequence>(of possibleSuperset: S) -> Bool | |||
where S.Element == Element { | |||
// FIXME(performance): isEmpty fast path, here and elsewhere. |
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.
As noted in the comment, there are places "elsewhere" that could use an isEmpty
fast path. Before deleting the fixme, it'd be important to identify where those other places are and either implement the fast path or add the fixme comment there.
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.
For sure @xwu 👍
I've checked the methods on Set and added it in all places that I could find it would be possible :))
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.
I’m not so sure you got everything. Wouldn’t isSuperset
benefit from an isEmpty
fast path?
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.
I've check this isSuperset
, but didn't think it has benefit, is an interesting case because just because we have two cases there
let s: Set<String> = []
print(s.isSuperset(of: [])) //false
print(s.isSuperset(of: ["A", "B"])) //true
So to add an isEmpty
fast path will require, check also possibleSubset for empty too, but since it is a arbitrary sequence it doens't have an isEmpty
and as far as I know we could not do this check on underestimatedCount.
Also looking to the implementation(below) no matter what is the size of possibleSubset
if self is empty it will return on the first iteration because contains will return false. So there's no performance problem because it will not iterate unnecessarily. Basically, that is the reason I think is not a benefit :))
public func isSuperset<S: Sequence>(of possibleSubset: __owned S) -> Bool
where S.Element == Element {
for member in possibleSubset {
if !contains(member) {
return false
}
}
return true
}
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.
Turns out there was more "elsewhere": isStrictSubset
and isStrictSuperset
with Sequence
parameter could probably also benefit form optimizations for isEmpty
cases... see #24156 (comment).
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.
@palimondo Sorry I miss those 😅, I'll take a look and I can patch up a PR later today :))
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.
No problem. Please don't go in there now, #21300 is about to drastically change how that's handled and I'm already looking into how to handle it only pays the cheap creation of isEmpty
cases on top of it…_Bitset(capacity: self.bucketCount)
and will bail out of the Sequence
consuming loop ASAP.
I just couldn't resist noting how @xwu's pedantry usually turns out to be right, even though it feels pretty annoying to be on the receiving end of it (speaking from experience 😉).
Co-Authored-By: LucianoPAlmeida <[email protected]>
@swift-ci Please smoke test |
Only some people can trigger tests, right? Can someone please trigger benchmark here :)) |
@swift-ci Benchmark |
@swift-ci Please benchmark? |
Build comment file:Performance: -O
How to read the dataThe tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.If you see any unexpected regressions, you should consider fixing the Noise: Sometimes the performance results (not code size!) contain false Hardware Overview
|
Checking the benchmark/single-source/SetTest.swift found that isDisjoint was not being benchmarked. |
@swift-ci Please benchmark |
@swift-ci Please smoke test |
Build comment file:Performance: -O
Code size: -O
Performance: -Osize
Code size: -Osize
Performance: -Onone
How to read the dataThe tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.If you see any unexpected regressions, you should consider fixing the Noise: Sometimes the performance results (not code size!) contain false Hardware Overview
|
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.
Nice work; thanks for adding those missing benchmarks!
The benchmark report pointed out two scaling issues (also noted in my comment above); other than those, this looks ready to merge!
setUpFunction: { blackHole([setAB, setCD]) }), | ||
BenchmarkInfo( | ||
name: "SetIsDisjointBox0", | ||
runFunction: { n in run_SetIsDisjointBox(setOAB, setOCD, true, 5000 * n) }, |
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.
0-overlap sets are the most expensive for isDisjoint(with:)
— these two benchmark cases (SetIsDisjointInt0, SetIsDisjointBox0) should use the same factor of 50 as the others.
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.
Just fixed 👍
Thank's for the review @lorentey :))
@swift-ci Please smoke test |
For the future reference: new performance tests should land in a separate commit from the actual performance work, so that they can demonstrate the expected improvements. Now we only see the after effect in the Added section of the benchmark results. I'm working on a fix to the loop multipliers that are too low for most of the newly introduced benchmarks and improvement to the benchmark validation to prevent this kind of mistake in PR #21717. |
This is a very simple PR resolving some FIXME comments on Set.swift as a very first contribution :))