From e3db41bf97f6a96e2d1236a1c4c3055b5c06b282 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 5 Jan 2022 02:28:30 +0100 Subject: [PATCH 1/2] add benchmark --- library/core/benches/iter.rs | 24 ++++++++++++++++++++++++ library/core/benches/lib.rs | 1 + 2 files changed, 25 insertions(+) diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index 24257ba98785d..0abe20e4ca3b2 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -367,3 +367,27 @@ fn bench_partial_cmp(b: &mut Bencher) { fn bench_lt(b: &mut Bencher) { b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box))) } + +#[bench] +fn bench_trusted_random_access_adapters(b: &mut Bencher) { + let vec1: Vec<_> = (0usize..100000).collect(); + let vec2 = black_box(vec1.clone()); + b.iter(|| { + let mut iter = vec1 + .iter() + .copied() + .enumerate() + .map(|(idx, e)| idx.wrapping_add(e)) + .zip(vec2.iter().copied()) + .map(|(a, b)| a.wrapping_add(b)) + .fuse(); + let mut acc: usize = 0; + let size = iter.size(); + for i in 0..size { + // SAFETY: TRA requirements are satisfied by 0..size iteration and then dropping the + // iterator. + acc = acc.wrapping_add(unsafe { iter.__iterator_get_unchecked(i) }); + } + acc + }) +} diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs index d5e1ec083f95d..f1f1ae6e4635d 100644 --- a/library/core/benches/lib.rs +++ b/library/core/benches/lib.rs @@ -3,6 +3,7 @@ #![feature(flt2dec)] #![feature(int_log)] #![feature(test)] +#![feature(trusted_random_access)] extern crate test; From a68a5d219d0138c7b39403c6b9dc08e2cf5d05be Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 5 Jan 2022 02:22:39 +0100 Subject: [PATCH 2/2] This aligns the inline attributes of existing `__iterator_get_unchecked` with those of `next()` on adapters that have both. It improves the performance of iterators using unchecked access when building in incremental mode (due to the larger CGU count?). It might negatively affect incremental compile times for better runtime results, but considering that the equivalent `next()` implementations also are `#[inline]` and usually are more complex this should be ok. ``` ./x.py bench library/core -i --stage 0 --test-args bench_trusted_random_access OLD: 119,172 ns/iter NEW: 17,714 ns/iter ``` --- library/core/src/iter/adapters/enumerate.rs | 1 + library/core/src/iter/adapters/map.rs | 1 + library/core/src/iter/adapters/zip.rs | 2 ++ library/core/src/slice/iter/macros.rs | 1 + 4 files changed, 5 insertions(+) diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 84e4618844a61..10b4db84b3904 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -129,6 +129,7 @@ where #[rustc_inherit_overflow_checks] #[doc(hidden)] + #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 4b03449972c9a..6cbb35dc7c629 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -125,6 +125,7 @@ where } #[doc(hidden)] + #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index f50e71da20f16..de44bd66501e2 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -554,6 +554,7 @@ pub unsafe trait TrustedRandomAccessNoCoerce: Sized { /// /// Same requirements calling `get_unchecked` directly. #[doc(hidden)] +#[inline] pub(in crate::iter::adapters) unsafe fn try_get_unchecked(it: &mut I, idx: usize) -> I::Item where I: Iterator, @@ -576,6 +577,7 @@ unsafe impl SpecTrustedRandomAccess for I { } unsafe impl SpecTrustedRandomAccess for I { + #[inline] unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index b74ab28fc092a..78bf3381b4d26 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -326,6 +326,7 @@ macro_rules! iterator { } #[doc(hidden)] + #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // SAFETY: the caller must guarantee that `i` is in bounds of // the underlying slice, so `i` cannot overflow an `isize`, and