diff options
| author | bors <bors@rust-lang.org> | 2021-07-08 09:44:52 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-07-08 09:44:52 +0000 |
| commit | 0cd0709f19d316c4796fa71c5f52c8612a5f3771 (patch) | |
| tree | 9f229878d45f701b2f9aeee4b14c1e03b7da0b72 | |
| parent | 2daa26b7caad3742c9c61849c67d7341c3df5b97 (diff) | |
| parent | 24094a04b66467623174199b2605e2f49be166f9 (diff) | |
| download | rust-0cd0709f19d316c4796fa71c5f52c8612a5f3771.tar.gz rust-0cd0709f19d316c4796fa71c5f52c8612a5f3771.zip | |
Auto merge of #86823 - the8472:opt-chunk-tra, r=kennytm
Optimize unchecked indexing into chunks and chunks_mut
Fixes #53340
```
# BEFORE
$ rustc +nightly -Copt-level=3 -Ccodegen-units=1 -Clto=fat chunks.rs
$ perf stat ./chunks
Performance counter stats for './chunks':
3,177.03 msec task-clock # 1.000 CPUs utilized
4 context-switches # 0.001 K/sec
0 cpu-migrations # 0.000 K/sec
984,006 page-faults # 0.310 M/sec
13,092,199,322 cycles # 4.121 GHz (83.29%)
384,543,475 stalled-cycles-frontend # 2.94% frontend cycles idle (83.35%)
7,414,280,722 stalled-cycles-backend # 56.63% backend cycles idle (83.38%)
50,493,980,662 instructions # 3.86 insn per cycle
# 0.15 stalled cycles per insn (83.29%)
6,625,375,297 branches # 2085.396 M/sec (83.38%)
3,087,652 branch-misses # 0.05% of all branches (83.31%)
3.178079469 seconds time elapsed
2.327156000 seconds user
0.762041000 seconds sys
# AFTER
$ ./build/x86_64-unknown-linux-gnu/stage1/bin/rustc -Copt-level=3 -Ccodegen-units=1 -Clto=fat chunks.rs
$ perf stat ./chunks
Performance counter stats for './chunks':
2,705.76 msec task-clock # 1.000 CPUs utilized
4 context-switches # 0.001 K/sec
0 cpu-migrations # 0.000 K/sec
984,005 page-faults # 0.364 M/sec
11,156,763,039 cycles # 4.123 GHz (83.26%)
342,198,882 stalled-cycles-frontend # 3.07% frontend cycles idle (83.37%)
6,486,263,637 stalled-cycles-backend # 58.14% backend cycles idle (83.37%)
40,553,476,617 instructions # 3.63 insn per cycle
# 0.16 stalled cycles per insn (83.37%)
6,668,429,113 branches # 2464.532 M/sec (83.37%)
3,099,636 branch-misses # 0.05% of all branches (83.26%)
2.706725288 seconds time elapsed
1.782083000 seconds user
0.848424000 seconds sys
```
| -rw-r--r-- | library/core/src/slice/iter.rs | 24 |
1 files changed, 11 insertions, 13 deletions
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index b2cb2f12bbf..5cbc6343e3a 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1418,18 +1418,17 @@ impl<'a, T> Iterator for Chunks<'a, T> { #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; // SAFETY: the caller guarantees that `i` is in bounds, // which means that `start` must be in bounds of the - // underlying `self.v` slice, and we made sure that `end` + // underlying `self.v` slice, and we made sure that `len` // is also in bounds of `self.v`. Thus, `start` cannot overflow // an `isize`, and the slice constructed by `from_raw_parts` // is a subslice of `self.v` which is guaranteed to be valid // for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + unsafe { + let len = cmp::min(self.v.len().unchecked_sub(start), self.chunk_size); + from_raw_parts(self.v.as_ptr().add(start), len) + } } } @@ -1457,7 +1456,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { } else { let start = (len - 1 - n) * self.chunk_size; let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), + Some(res) => cmp::min(self.v.len(), res), None => self.v.len(), }; let nth_back = &self.v[start..end]; @@ -1579,17 +1578,16 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; // SAFETY: see comments for `Chunks::__iterator_get_unchecked`. // // Also note that the caller also guarantees that we're never called // with the same index again, and that no other methods that will // access this subslice are called, so it is valid for the returned // slice to be mutable. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + unsafe { + let len = cmp::min(self.v.len().unchecked_sub(start), self.chunk_size); + from_raw_parts_mut(self.v.as_mut_ptr().add(start), len) + } } } @@ -1619,7 +1617,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { } else { let start = (len - 1 - n) * self.chunk_size; let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), + Some(res) => cmp::min(self.v.len(), res), None => self.v.len(), }; let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); |
