Skip to content

Commit 0cd0709

Browse files
committed
Auto merge of rust-lang#86823 - the8472:opt-chunk-tra, r=kennytm
Optimize unchecked indexing into chunks and chunks_mut Fixes rust-lang#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 ```
2 parents 2daa26b + 24094a0 commit 0cd0709

File tree

1 file changed

+11
-13
lines changed

1 file changed

+11
-13
lines changed

library/core/src/slice/iter.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -1418,18 +1418,17 @@ impl<'a, T> Iterator for Chunks<'a, T> {
14181418
#[doc(hidden)]
14191419
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
14201420
let start = idx * self.chunk_size;
1421-
let end = match start.checked_add(self.chunk_size) {
1422-
None => self.v.len(),
1423-
Some(end) => cmp::min(end, self.v.len()),
1424-
};
14251421
// SAFETY: the caller guarantees that `i` is in bounds,
14261422
// which means that `start` must be in bounds of the
1427-
// underlying `self.v` slice, and we made sure that `end`
1423+
// underlying `self.v` slice, and we made sure that `len`
14281424
// is also in bounds of `self.v`. Thus, `start` cannot overflow
14291425
// an `isize`, and the slice constructed by `from_raw_parts`
14301426
// is a subslice of `self.v` which is guaranteed to be valid
14311427
// for the lifetime `'a` of `self.v`.
1432-
unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
1428+
unsafe {
1429+
let len = cmp::min(self.v.len().unchecked_sub(start), self.chunk_size);
1430+
from_raw_parts(self.v.as_ptr().add(start), len)
1431+
}
14331432
}
14341433
}
14351434

@@ -1457,7 +1456,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
14571456
} else {
14581457
let start = (len - 1 - n) * self.chunk_size;
14591458
let end = match start.checked_add(self.chunk_size) {
1460-
Some(res) => cmp::min(res, self.v.len()),
1459+
Some(res) => cmp::min(self.v.len(), res),
14611460
None => self.v.len(),
14621461
};
14631462
let nth_back = &self.v[start..end];
@@ -1579,17 +1578,16 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
15791578
#[doc(hidden)]
15801579
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
15811580
let start = idx * self.chunk_size;
1582-
let end = match start.checked_add(self.chunk_size) {
1583-
None => self.v.len(),
1584-
Some(end) => cmp::min(end, self.v.len()),
1585-
};
15861581
// SAFETY: see comments for `Chunks::__iterator_get_unchecked`.
15871582
//
15881583
// Also note that the caller also guarantees that we're never called
15891584
// with the same index again, and that no other methods that will
15901585
// access this subslice are called, so it is valid for the returned
15911586
// slice to be mutable.
1592-
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
1587+
unsafe {
1588+
let len = cmp::min(self.v.len().unchecked_sub(start), self.chunk_size);
1589+
from_raw_parts_mut(self.v.as_mut_ptr().add(start), len)
1590+
}
15931591
}
15941592
}
15951593

@@ -1619,7 +1617,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
16191617
} else {
16201618
let start = (len - 1 - n) * self.chunk_size;
16211619
let end = match start.checked_add(self.chunk_size) {
1622-
Some(res) => cmp::min(res, self.v.len()),
1620+
Some(res) => cmp::min(self.v.len(), res),
16231621
None => self.v.len(),
16241622
};
16251623
let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);

0 commit comments

Comments
 (0)