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
```
This commit is contained in:
bors 2021-07-08 09:44:52 +00:00
commit 0cd0709f19

View file

@ -1418,18 +1418,17 @@ fn last(self) -> Option<Self::Item> {
#[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 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
} 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 @@ fn last(self) -> Option<Self::Item> {
#[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 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
} 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);