Skip to content

Commit 689e847

Browse files
committedMar 30, 2021
Auto merge of #83458 - saethlin:improve-vec-benches, r=dtolnay
Clean up Vec's benchmarks The Vec benchmarks need a lot of love. I sort of noticed this in #83357 but the overall situation is much less awesome than I thought at the time. The first commit just removes a lot of asserts and does a touch of other cleanup. A number of these benchmarks are poorly-named. For example, `bench_map_fast` is not in fact fast, `bench_rev_1` and `bench_rev_2` are vague, `bench_in_place_zip_iter_mut` doesn't call `zip`, `bench_in_place*` don't do anything in-place... Should I fix these, or is there tooling that depend on the names not changing? I've also noticed that `bench_rev_1` and `bench_rev_2` are remarkably fragile. It looks like poking other code in `Vec` can cause the codegen of this benchmark to switch to a version that has almost exactly half its current throughput and I have absolutely no idea why. Here's the fast version: ```asm 0.69 │110: movdqu -0x20(%rbx,%rdx,4),%xmm0 1.76 │ movdqu -0x10(%rbx,%rdx,4),%xmm1 0.71 │ pshufd $0x1b,%xmm1,%xmm1 0.60 │ pshufd $0x1b,%xmm0,%xmm0 3.68 │ movdqu %xmm1,-0x30(%rcx) 14.36 │ movdqu %xmm0,-0x20(%rcx) 13.88 │ movdqu -0x40(%rbx,%rdx,4),%xmm0 6.64 │ movdqu -0x30(%rbx,%rdx,4),%xmm1 0.76 │ pshufd $0x1b,%xmm1,%xmm1 0.77 │ pshufd $0x1b,%xmm0,%xmm0 1.87 │ movdqu %xmm1,-0x10(%rcx) 13.01 │ movdqu %xmm0,(%rcx) 38.81 │ add $0x40,%rcx 0.92 │ add $0xfffffffffffffff0,%rdx 1.22 │ ↑ jne 110 ``` And the slow one: ```asm 0.42 │9a880: movdqa %xmm2,%xmm1 4.03 │9a884: movq -0x8(%rbx,%rsi,4),%xmm4 8.49 │9a88a: pshufd $0xe1,%xmm4,%xmm4 2.58 │9a88f: movq -0x10(%rbx,%rsi,4),%xmm5 7.02 │9a895: pshufd $0xe1,%xmm5,%xmm5 4.79 │9a89a: punpcklqdq %xmm5,%xmm4 5.77 │9a89e: movdqu %xmm4,-0x18(%rdx) 15.74 │9a8a3: movq -0x18(%rbx,%rsi,4),%xmm4 3.91 │9a8a9: pshufd $0xe1,%xmm4,%xmm4 5.04 │9a8ae: movq -0x20(%rbx,%rsi,4),%xmm5 5.29 │9a8b4: pshufd $0xe1,%xmm5,%xmm5 4.60 │9a8b9: punpcklqdq %xmm5,%xmm4 9.81 │9a8bd: movdqu %xmm4,-0x8(%rdx) 11.05 │9a8c2: paddq %xmm3,%xmm0 0.86 │9a8c6: paddq %xmm3,%xmm2 5.89 │9a8ca: add $0x20,%rdx 0.12 │9a8ce: add $0xfffffffffffffff8,%rsi 1.16 │9a8d2: add $0x2,%rdi 2.96 │9a8d6: → jne 9a880 <<alloc::vec::Vec<T,A> as core::iter::traits::collect::Extend<&T>>::extend+0xd0> ```
2 parents a0e229a + 8c88418 commit 689e847

File tree

1 file changed

+25
-68
lines changed

1 file changed

+25
-68
lines changed
 

‎library/alloc/benches/vec.rs

+25-68
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,13 @@ use test::{black_box, Bencher};
44

55
#[bench]
66
fn bench_new(b: &mut Bencher) {
7-
b.iter(|| {
8-
let v: Vec<u32> = Vec::new();
9-
assert_eq!(v.len(), 0);
10-
assert_eq!(v.capacity(), 0);
11-
v
12-
})
7+
b.iter(|| Vec::<u32>::new())
138
}
149

1510
fn do_bench_with_capacity(b: &mut Bencher, src_len: usize) {
1611
b.bytes = src_len as u64;
1712

18-
b.iter(|| {
19-
let v: Vec<u32> = Vec::with_capacity(src_len);
20-
assert_eq!(v.len(), 0);
21-
assert_eq!(v.capacity(), src_len);
22-
v
23-
})
13+
b.iter(|| Vec::<u32>::with_capacity(src_len))
2414
}
2515

2616
#[bench]
@@ -46,12 +36,7 @@ fn bench_with_capacity_1000(b: &mut Bencher) {
4636
fn do_bench_from_fn(b: &mut Bencher, src_len: usize) {
4737
b.bytes = src_len as u64;
4838

49-
b.iter(|| {
50-
let dst = (0..src_len).collect::<Vec<_>>();
51-
assert_eq!(dst.len(), src_len);
52-
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
53-
dst
54-
})
39+
b.iter(|| (0..src_len).collect::<Vec<_>>())
5540
}
5641

5742
#[bench]
@@ -77,12 +62,7 @@ fn bench_from_fn_1000(b: &mut Bencher) {
7762
fn do_bench_from_elem(b: &mut Bencher, src_len: usize) {
7863
b.bytes = src_len as u64;
7964

80-
b.iter(|| {
81-
let dst: Vec<usize> = repeat(5).take(src_len).collect();
82-
assert_eq!(dst.len(), src_len);
83-
assert!(dst.iter().all(|x| *x == 5));
84-
dst
85-
})
65+
b.iter(|| repeat(5).take(src_len).collect::<Vec<usize>>())
8666
}
8767

8868
#[bench]
@@ -110,12 +90,7 @@ fn do_bench_from_slice(b: &mut Bencher, src_len: usize) {
11090

11191
b.bytes = src_len as u64;
11292

113-
b.iter(|| {
114-
let dst = src.clone()[..].to_vec();
115-
assert_eq!(dst.len(), src_len);
116-
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
117-
dst
118-
});
93+
b.iter(|| src.as_slice().to_vec());
11994
}
12095

12196
#[bench]
@@ -144,9 +119,7 @@ fn do_bench_from_iter(b: &mut Bencher, src_len: usize) {
144119
b.bytes = src_len as u64;
145120

146121
b.iter(|| {
147-
let dst: Vec<_> = FromIterator::from_iter(src.clone());
148-
assert_eq!(dst.len(), src_len);
149-
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
122+
let dst: Vec<_> = FromIterator::from_iter(src.iter().cloned());
150123
dst
151124
});
152125
}
@@ -180,8 +153,6 @@ fn do_bench_extend(b: &mut Bencher, dst_len: usize, src_len: usize) {
180153
b.iter(|| {
181154
let mut dst = dst.clone();
182155
dst.extend(src.clone());
183-
assert_eq!(dst.len(), dst_len + src_len);
184-
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
185156
dst
186157
});
187158
}
@@ -230,8 +201,6 @@ fn do_bench_extend_from_slice(b: &mut Bencher, dst_len: usize, src_len: usize) {
230201
b.iter(|| {
231202
let mut dst = dst.clone();
232203
dst.extend_from_slice(&src);
233-
assert_eq!(dst.len(), dst_len + src_len);
234-
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
235204
dst
236205
});
237206
}
@@ -290,12 +259,7 @@ fn do_bench_clone(b: &mut Bencher, src_len: usize) {
290259

291260
b.bytes = src_len as u64;
292261

293-
b.iter(|| {
294-
let dst = src.clone();
295-
assert_eq!(dst.len(), src_len);
296-
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
297-
dst
298-
});
262+
b.iter(|| src.clone());
299263
}
300264

301265
#[bench]
@@ -329,8 +293,7 @@ fn do_bench_clone_from(b: &mut Bencher, times: usize, dst_len: usize, src_len: u
329293

330294
for _ in 0..times {
331295
dst.clone_from(&src);
332-
assert_eq!(dst.len(), src_len);
333-
assert!(dst.iter().enumerate().all(|(i, x)| dst_len + i == *x));
296+
dst = black_box(dst);
334297
}
335298
dst
336299
});
@@ -463,11 +426,10 @@ macro_rules! bench_in_place {
463426
fn $fname(b: &mut Bencher) {
464427
b.iter(|| {
465428
let src: Vec<$type> = black_box(vec![$init; $count]);
466-
let mut sink = src.into_iter()
429+
src.into_iter()
467430
.enumerate()
468431
.map(|(idx, e)| idx as $type ^ e)
469-
.collect::<Vec<$type>>();
470-
black_box(sink.as_mut_ptr())
432+
.collect::<Vec<$type>>()
471433
});
472434
}
473435
)+
@@ -527,7 +489,6 @@ fn bench_in_place_zip_recycle(b: &mut Bencher) {
527489
.enumerate()
528490
.map(|(i, (d, s))| d.wrapping_add(i as u8) ^ s)
529491
.collect::<Vec<_>>();
530-
assert_eq!(mangled.len(), 1000);
531492
data = black_box(mangled);
532493
});
533494
}
@@ -614,23 +575,6 @@ fn bench_nest_chain_chain_collect(b: &mut Bencher) {
614575
});
615576
}
616577

617-
pub fn example_plain_slow(l: &[u32]) -> Vec<u32> {
618-
let mut result = Vec::with_capacity(l.len());
619-
result.extend(l.iter().rev());
620-
result
621-
}
622-
623-
pub fn map_fast(l: &[(u32, u32)]) -> Vec<u32> {
624-
let mut result = Vec::with_capacity(l.len());
625-
for i in 0..l.len() {
626-
unsafe {
627-
*result.get_unchecked_mut(i) = l[i].0;
628-
result.set_len(i);
629-
}
630-
}
631-
result
632-
}
633-
634578
#[bench]
635579
fn bench_range_map_collect(b: &mut Bencher) {
636580
b.iter(|| (0..LEN).map(|_| u32::default()).collect::<Vec<_>>());
@@ -669,7 +613,11 @@ fn bench_rev_1(b: &mut Bencher) {
669613
#[bench]
670614
fn bench_rev_2(b: &mut Bencher) {
671615
let data = black_box([0; LEN]);
672-
b.iter(|| example_plain_slow(&data));
616+
b.iter(|| {
617+
let mut v = Vec::<u32>::with_capacity(data.len());
618+
v.extend(data.iter().rev());
619+
v
620+
});
673621
}
674622

675623
#[bench]
@@ -685,7 +633,16 @@ fn bench_map_regular(b: &mut Bencher) {
685633
#[bench]
686634
fn bench_map_fast(b: &mut Bencher) {
687635
let data = black_box([(0, 0); LEN]);
688-
b.iter(|| map_fast(&data));
636+
b.iter(|| {
637+
let mut result = Vec::with_capacity(data.len());
638+
for i in 0..data.len() {
639+
unsafe {
640+
*result.get_unchecked_mut(i) = data[i].0;
641+
result.set_len(i);
642+
}
643+
}
644+
result
645+
});
689646
}
690647

691648
fn random_sorted_fill(mut seed: u32, buf: &mut [u32]) {

0 commit comments

Comments
 (0)
Please sign in to comment.