Skip to content

Commit

Permalink
Auto merge of rust-lang#116422 - the8472:chunked-generic-slice-eq, r=…
Browse files Browse the repository at this point in the history
…<try>

Chunked generic slice eq

looks nice in a microbenchmark, let's see if perf agrees

```
OLD:
    slice::slice_cmp_generic 54.00ns/iter +/- 1.00ns
NEW:
    slice::slice_cmp_generic 20.00ns/iter +/- 2.00ns
```
  • Loading branch information
bors committed Oct 4, 2023
2 parents 65519f5 + 9d3905f commit dfe514e
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
14 changes: 14 additions & 0 deletions library/core/benches/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,17 @@ fn fold_to_last(b: &mut Bencher) {
let slice: &[i32] = &[0; 1024];
b.iter(|| black_box(slice).iter().fold(None, |_, r| Some(NonNull::from(r))));
}

#[bench]
fn slice_cmp_generic(b: &mut Bencher) {
#[derive(PartialEq, Clone, Copy)]
struct Foo(u32, u32);

let left = [Foo(128, 128); 128];
let right = [Foo(128, 128); 128];

b.iter(|| {
let (left, right) = (black_box(&left), black_box(&right));
left.as_slice() == right.as_slice()
});
}
17 changes: 16 additions & 1 deletion library/core/src/slice/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,22 @@ where
return false;
}

self.iter().zip(other.iter()).all(|(x, y)| x == y)
let (chunks_a, residual_a) = self.as_chunks::<4>();
let (chunks_b, residual_b) = other.as_chunks::<4>();

// check the residual first to bail out fast if there's a mismatch and comparisons
// happen to be expensive
let mut result = residual_a.into_iter().zip(residual_b).all(|(a, b)| a == b);

// iter.all short-circuits which means the backend can't unroll the loop due to early exits.
// So we unroll it manually.
result = result
&& chunks_a
.iter()
.zip(chunks_b.iter())
.all(|(a, b)| (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]));

result
}
}

Expand Down

0 comments on commit dfe514e

Please sign in to comment.