-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Implement nth_back for slice::{Iter, IterMut} #60772
Conversation
r? @TimNN (rust_highfive has picked a reviewer for you, use r? to override) |
src/libcore/slice/mod.rs
Outdated
// end of the iterator backwards by `n`. | ||
#[inline(always)] | ||
fn zst_shrink(&mut self, n: isize) { | ||
self.end = (self.end as * $raw_mut u8).wrapping_offset(-n) as * $raw_mut T; |
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.
Maybe add a debug_assert
making sure mem::size_of::<T>() == 0
?
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 didn't do this as not to affect the performance of debug builds, although I'm not opposed to adding it. Either way, this function should probably be unsafe
?
src/libcore/slice/mod.rs
Outdated
accum = f(accum, self.next_unchecked())?; | ||
accum = f(accum, self.next_unchecked())?; | ||
accum = f(accum, self.next_unchecked())?; | ||
accum = f(accum, self.next_unchecked())?; |
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.
Last time I touched these, even introducing inline(always)
functions in some of these places had significant impact on performance. This should get a perf run, and ideally also some manual benchmarking.
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.
Yikes, yep, benchmarks I just ran confirm this. So are they not actually being inlined, or what's going on?
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.
So we don't need to bother perfbot then?^^
So are they not actually being inlined, or what's going on?
Your guess is as good as mine. One hypothesis we had last time was that inlining happens after some other passes -- so manually inlined code basically is already present earlier in the pipeline and gets simplified better.
You could try to compile your benchmark to LLVM IR with the old and new version of libstd and compare. You'll see that the function did get inlined, but the IR is still vastly different.
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.
It's unfortunate that functions apparently aren't zero-cost here, but I guess it is what it is.
I turned next_unchecked
and next_back_unchecked
into macros and that seems to have fixed all the regressions. 🙂 It's hard to say for sure though, every time I run the benchmarks there are a few that change by up to 5% or so in either direction, although it's not always the same ones. It seems like they're just not very stable.
For perf:
When I tried, this made a difference. See in particular the discussion starting here. |
⌛ Trying commit dde6587388afb05ddf716c97aaa6d8cdfecfae97 with merge a7f658d531f58408d872991a0aad92876b86712c... |
☀️ Try build successful - checks-travis |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
@RalfJung Thanks! That's very helpful. Looks like we can't get rid of the macros yet, then. |
Let's see what perf has to say, then. @bors try |
Implement nth_back for slice::{Iter, IterMut} Part of #54054. I implemented `nth_back` as straightforwardly as I could, and then slightly changed `nth` to match `nth_back`. I believe I did so correctly, but please double-check 🙂 I also added the helper methods `zst_shrink`, `next_unchecked`, and `next_back_unchecked` to get rid of some duplicated code. These changes hopefully make this code easier to understand for new contributors like me. I noticed the `is_empty!` and `len!` macros which sole purpose seems to be inlining, according to the comment right above them, but the `is_empty` and `len` methods are already marked with `#[inline(always)]`. Does that mean we could replace these macros with method calls, without affecting anything? I'd love to get rid of them.
☀️ Try build successful - checks-travis |
@rust-timer build e89b9fd |
Success: Queued e89b9fd with parent a9ec99f, comparison URL. |
It's not clear to me whether the 0.8% change to |
I also made @bors try |
@timvermeulen: 🔑 Insufficient privileges: not in try users |
@bors try |
Implement nth_back for slice::{Iter, IterMut} Part of #54054. I implemented `nth_back` as straightforwardly as I could, and then slightly changed `nth` to match `nth_back`. I believe I did so correctly, but please double-check 🙂 I also added the helper methods `zst_shrink`, `next_unchecked`, and `next_back_unchecked` to get rid of some duplicated code. These changes hopefully make this code easier to understand for new contributors like me. I noticed the `is_empty!` and `len!` macros which sole purpose seems to be inlining, according to the comment right above them, but the `is_empty` and `len` methods are already marked with `#[inline(always)]`. Does that mean we could replace these macros with method calls, without affecting anything? I'd love to get rid of them.
☀️ Try build successful - checks-travis |
@rust-timer build 01fe51e |
Success: Queued 01fe51e with parent 315ab95, comparison URL. |
Finished benchmarking try commit 01fe51e: comparison url |
This looks better! |
r? @scottmcm |
Triage: Waiting for review by @rust-lang/libs |
Looks good, thanks @timvermeulen! @bors r+ |
📌 Commit 97a6c93 has been approved by |
…=scottmcm Implement nth_back for slice::{Iter, IterMut} Part of rust-lang#54054. I implemented `nth_back` as straightforwardly as I could, and then slightly changed `nth` to match `nth_back`. I believe I did so correctly, but please double-check 🙂 I also added the helper methods `zst_shrink`, `next_unchecked`, and `next_back_unchecked` to get rid of some duplicated code. These changes hopefully make this code easier to understand for new contributors like me. I noticed the `is_empty!` and `len!` macros which sole purpose seems to be inlining, according to the comment right above them, but the `is_empty` and `len` methods are already marked with `#[inline(always)]`. Does that mean we could replace these macros with method calls, without affecting anything? I'd love to get rid of them.
@bors rollup- |
Well that didn't do anything. And it's already been rolled up anyway... whatever^^ |
Part of #54054.
I implemented
nth_back
as straightforwardly as I could, and then slightly changednth
to matchnth_back
. I believe I did so correctly, but please double-check 🙂I also added the helper methods
zst_shrink
,next_unchecked
, andnext_back_unchecked
to get rid of some duplicated code. These changes hopefully make this code easier to understand for new contributors like me.I noticed the
is_empty!
andlen!
macros which sole purpose seems to be inlining, according to the comment right above them, but theis_empty
andlen
methods are already marked with#[inline(always)]
. Does that mean we could replace these macros with method calls, without affecting anything? I'd love to get rid of them.