Skip to content

Commit 675221e

Browse files
author
bors-servo
authored
Auto merge of #97 - Vurich:vec-benches, r=mbrubeck
Add benchmarks for smallvec when it's on the stack This makes all the benchmarks generic so the addition of the `_small` variants didn't totally blow up the line count, which as an added bonus also means we don't get duplication between the vec and smallvec benchmarks. Results: ``` name vec.bench ns/iter smallvec.bench ns/iter diff ns/iter diff % speedup bench_extend 70 102 32 45.71% x 0.69 bench_extend_from_slice 65 52 -13 -20.00% x 1.25 bench_extend_from_slice_small 29 24 -5 -17.24% x 1.21 bench_extend_small 28 25 -3 -10.71% x 1.12 bench_from_slice 34 97 63 185.29% x 0.35 bench_from_slice_small 31 36 5 16.13% x 0.86 bench_insert 1,235 1,224 -11 -0.89% x 1.01 bench_insert_small 114 117 3 2.63% x 0.97 bench_macro_from_elem 45 55 10 22.22% x 0.82 bench_macro_from_elem_small 33 17 -16 -48.48% x 1.94 bench_macro_from_list 33 47 14 42.42% x 0.70 bench_push 379 462 83 21.90% x 0.82 bench_push_small 53 57 4 7.55% x 0.93 bench_pushpop 252 307 55 21.83% x 0.82 ``` <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-smallvec/97) <!-- Reviewable:end -->
2 parents 6e061f3 + 25255c8 commit 675221e

File tree

2 files changed

+176
-130
lines changed

2 files changed

+176
-130
lines changed

benches/bench.rs

Lines changed: 175 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -4,213 +4,259 @@
44
extern crate smallvec;
55
extern crate test;
66

7-
use smallvec::SmallVec;
87
use self::test::Bencher;
8+
use smallvec::{ExtendFromSlice, SmallVec};
99

10-
#[bench]
11-
fn bench_push(b: &mut Bencher) {
12-
#[inline(never)]
13-
fn push_noinline(vec: &mut SmallVec<[u64; 16]>, x: u64) {
14-
vec.push(x)
15-
}
10+
const VEC_SIZE: usize = 16;
11+
const SPILLED_SIZE: usize = 100;
1612

17-
b.iter(|| {
18-
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
19-
for x in 0..100 {
20-
push_noinline(&mut vec, x);
21-
}
22-
vec
23-
});
13+
trait Vector<T>: for<'a> From<&'a [T]> + Extend<T> + ExtendFromSlice<T> {
14+
fn new() -> Self;
15+
fn push(&mut self, val: T);
16+
fn pop(&mut self) -> Option<T>;
17+
fn remove(&mut self, p: usize) -> T;
18+
fn insert(&mut self, n: usize, val: T);
19+
fn from_elem(val: T, n: usize) -> Self;
2420
}
2521

26-
#[bench]
27-
fn bench_insert(b: &mut Bencher) {
28-
#[inline(never)]
29-
fn insert_noinline(vec: &mut SmallVec<[u64; 16]>, x: u64) {
30-
vec.insert(0, x)
22+
impl<T: Copy> Vector<T> for Vec<T> {
23+
fn new() -> Self {
24+
Self::with_capacity(VEC_SIZE)
3125
}
3226

33-
b.iter(|| {
34-
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
35-
for x in 0..100 {
36-
insert_noinline(&mut vec, x);
37-
}
38-
vec
39-
});
27+
fn push(&mut self, val: T) {
28+
self.push(val)
29+
}
30+
31+
fn pop(&mut self) -> Option<T> {
32+
self.pop()
33+
}
34+
35+
fn remove(&mut self, p: usize) -> T {
36+
self.remove(p)
37+
}
38+
39+
fn insert(&mut self, n: usize, val: T) {
40+
self.insert(n, val)
41+
}
42+
43+
fn from_elem(val: T, n: usize) -> Self {
44+
vec![val; n]
45+
}
4046
}
4147

42-
#[bench]
43-
fn bench_insert_many(b: &mut Bencher) {
44-
#[inline(never)]
45-
fn insert_many_noinline<I: IntoIterator<Item=u64>>(
46-
vec: &mut SmallVec<[u64; 16]>, index: usize, iterable: I) {
47-
vec.insert_many(index, iterable)
48+
impl<T: Copy> Vector<T> for SmallVec<[T; VEC_SIZE]> {
49+
fn new() -> Self {
50+
Self::new()
4851
}
4952

50-
b.iter(|| {
51-
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
52-
insert_many_noinline(&mut vec, 0, 0..100);
53-
insert_many_noinline(&mut vec, 0, 0..100);
54-
vec
55-
});
53+
fn push(&mut self, val: T) {
54+
self.push(val)
55+
}
56+
57+
fn pop(&mut self) -> Option<T> {
58+
self.pop()
59+
}
60+
61+
fn remove(&mut self, p: usize) -> T {
62+
self.remove(p)
63+
}
64+
65+
fn insert(&mut self, n: usize, val: T) {
66+
self.insert(n, val)
67+
}
68+
69+
fn from_elem(val: T, n: usize) -> Self {
70+
smallvec![val; n]
71+
}
5672
}
5773

58-
#[bench]
59-
fn bench_extend(b: &mut Bencher) {
60-
b.iter(|| {
61-
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
62-
vec.extend(0..100);
63-
vec
64-
});
74+
macro_rules! make_benches {
75+
($typ:ty { $($b_name:ident => $g_name:ident($($args:expr),*),)* }) => {
76+
$(
77+
#[bench]
78+
fn $b_name(b: &mut Bencher) {
79+
$g_name::<$typ>($($args,)* b)
80+
}
81+
)*
82+
}
6583
}
6684

67-
#[bench]
68-
fn bench_from_slice(b: &mut Bencher) {
69-
let v: Vec<u64> = (0..100).collect();
70-
b.iter(|| {
71-
let vec: SmallVec<[u64; 16]> = SmallVec::from_slice(&v);
72-
vec
73-
});
85+
make_benches! {
86+
SmallVec<[u64; VEC_SIZE]> {
87+
bench_push => gen_push(SPILLED_SIZE as _),
88+
bench_push_small => gen_push(VEC_SIZE as _),
89+
bench_insert => gen_insert(SPILLED_SIZE as _),
90+
bench_insert_small => gen_insert(VEC_SIZE as _),
91+
bench_remove => gen_remove(SPILLED_SIZE as _),
92+
bench_remove_small => gen_remove(VEC_SIZE as _),
93+
bench_extend => gen_extend(SPILLED_SIZE as _),
94+
bench_extend_small => gen_extend(VEC_SIZE as _),
95+
bench_from_slice => gen_from_slice(SPILLED_SIZE as _),
96+
bench_from_slice_small => gen_from_slice(VEC_SIZE as _),
97+
bench_extend_from_slice => gen_extend_from_slice(SPILLED_SIZE as _),
98+
bench_extend_from_slice_small => gen_extend_from_slice(VEC_SIZE as _),
99+
bench_macro_from_elem => gen_from_elem(SPILLED_SIZE as _),
100+
bench_macro_from_elem_small => gen_from_elem(VEC_SIZE as _),
101+
bench_pushpop => gen_pushpop(),
102+
}
74103
}
75104

76-
#[bench]
77-
fn bench_extend_from_slice(b: &mut Bencher) {
78-
let v: Vec<u64> = (0..100).collect();
105+
make_benches! {
106+
Vec<u64> {
107+
bench_push_vec => gen_push(SPILLED_SIZE as _),
108+
bench_push_vec_small => gen_push(VEC_SIZE as _),
109+
bench_insert_vec => gen_insert(SPILLED_SIZE as _),
110+
bench_insert_vec_small => gen_insert(VEC_SIZE as _),
111+
bench_remove_vec => gen_remove(SPILLED_SIZE as _),
112+
bench_remove_vec_small => gen_remove(VEC_SIZE as _),
113+
bench_extend_vec => gen_extend(SPILLED_SIZE as _),
114+
bench_extend_vec_small => gen_extend(VEC_SIZE as _),
115+
bench_from_slice_vec => gen_from_slice(SPILLED_SIZE as _),
116+
bench_from_slice_vec_small => gen_from_slice(VEC_SIZE as _),
117+
bench_extend_from_slice_vec => gen_extend_from_slice(SPILLED_SIZE as _),
118+
bench_extend_from_slice_vec_small => gen_extend_from_slice(VEC_SIZE as _),
119+
bench_macro_from_elem_vec => gen_from_elem(SPILLED_SIZE as _),
120+
bench_macro_from_elem_vec_small => gen_from_elem(VEC_SIZE as _),
121+
bench_pushpop_vec => gen_pushpop(),
122+
}
123+
}
124+
125+
fn gen_push<V: Vector<u64>>(n: u64, b: &mut Bencher) {
126+
#[inline(never)]
127+
fn push_noinline<V: Vector<u64>>(vec: &mut V, x: u64) {
128+
vec.push(x);
129+
}
130+
79131
b.iter(|| {
80-
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
81-
vec.extend_from_slice(&v);
132+
let mut vec = V::new();
133+
for x in 0..n {
134+
push_noinline(&mut vec, x);
135+
}
82136
vec
83137
});
84138
}
85139

86-
#[bench]
87-
fn bench_insert_from_slice(b: &mut Bencher) {
88-
let v: Vec<u64> = (0..100).collect();
140+
fn gen_insert<V: Vector<u64>>(n: u64, b: &mut Bencher) {
141+
#[inline(never)]
142+
fn insert_noinline<V: Vector<u64>>(vec: &mut V, p: usize, x: u64) {
143+
vec.insert(p, x)
144+
}
145+
89146
b.iter(|| {
90-
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
91-
vec.insert_from_slice(0, &v);
92-
vec.insert_from_slice(0, &v);
147+
let mut vec = V::new();
148+
// Add one element, with each iteration we insert one before the end.
149+
// This means that we benchmark the insertion operation and not the
150+
// time it takes to `ptr::copy` the data.
151+
vec.push(0);
152+
for x in 0..n {
153+
insert_noinline(&mut vec, x as _, x);
154+
}
93155
vec
94156
});
95157
}
96158

97-
#[bench]
98-
fn bench_pushpop(b: &mut Bencher) {
159+
fn gen_remove<V: Vector<u64>>(n: usize, b: &mut Bencher) {
99160
#[inline(never)]
100-
fn pushpop_noinline(vec: &mut SmallVec<[u64; 16]>, x: u64) {
101-
vec.push(x);
102-
vec.pop();
161+
fn remove_noinline<V: Vector<u64>>(vec: &mut V, p: usize) {
162+
vec.remove(p);
103163
}
104164

105165
b.iter(|| {
106-
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
107-
for x in 0..100 {
108-
pushpop_noinline(&mut vec, x);
166+
let mut vec = V::from_elem(0, n as _);
167+
168+
for x in (0..n - 1).rev() {
169+
remove_noinline(&mut vec, x)
109170
}
110-
vec
111171
});
112172
}
113173

114-
#[bench]
115-
fn bench_macro_from_elem(b: &mut Bencher) {
174+
fn gen_extend<V: Vector<u64>>(n: u64, b: &mut Bencher) {
116175
b.iter(|| {
117-
let vec: SmallVec<[u64; 16]> = smallvec![42; 100];
176+
let mut vec = V::new();
177+
vec.extend(0..n);
118178
vec
119179
});
120180
}
121181

122-
#[bench]
123-
fn bench_macro_from_list(b: &mut Bencher) {
182+
fn gen_from_slice<V: Vector<u64>>(n: u64, b: &mut Bencher) {
183+
let v: Vec<u64> = (0..n).collect();
124184
b.iter(|| {
125-
let vec: SmallVec<[u64; 16]> = smallvec![
126-
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80,
127-
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000,
128-
0x80000, 0x100000
129-
];
185+
let vec = V::from(&v);
130186
vec
131187
});
132188
}
133-
#[bench]
134-
fn bench_push_vec(b: &mut Bencher) {
135-
#[inline(never)]
136-
fn push_noinline(vec: &mut Vec<u64>, x: u64) {
137-
vec.push(x)
138-
}
139189

190+
fn gen_extend_from_slice<V: Vector<u64>>(n: u64, b: &mut Bencher) {
191+
let v: Vec<u64> = (0..n).collect();
140192
b.iter(|| {
141-
let mut vec: Vec<u64> = Vec::with_capacity(16);
142-
for x in 0..100 {
143-
push_noinline(&mut vec, x);
144-
}
193+
let mut vec = V::new();
194+
vec.extend_from_slice(&v);
145195
vec
146196
});
147197
}
148198

149-
#[bench]
150-
fn bench_insert_vec(b: &mut Bencher) {
199+
fn gen_pushpop<V: Vector<u64>>(b: &mut Bencher) {
151200
#[inline(never)]
152-
fn insert_noinline(vec: &mut Vec<u64>, x: u64) {
153-
vec.insert(0, x)
201+
fn pushpop_noinline<V: Vector<u64>>(vec: &mut V, x: u64) -> Option<u64> {
202+
vec.push(x);
203+
vec.pop()
154204
}
155205

156206
b.iter(|| {
157-
let mut vec: Vec<u64> = Vec::with_capacity(16);
158-
for x in 0..100 {
159-
insert_noinline(&mut vec, x);
207+
let mut vec = V::new();
208+
for x in 0..SPILLED_SIZE as _ {
209+
pushpop_noinline(&mut vec, x);
160210
}
161211
vec
162212
});
163213
}
164214

165-
#[bench]
166-
fn bench_extend_vec(b: &mut Bencher) {
215+
fn gen_from_elem<V: Vector<u64>>(n: usize, b: &mut Bencher) {
167216
b.iter(|| {
168-
let mut vec: Vec<u64> = Vec::with_capacity(16);
169-
vec.extend(0..100);
217+
let vec = V::from_elem(42, n);
170218
vec
171219
});
172220
}
173221

174222
#[bench]
175-
fn bench_from_slice_vec(b: &mut Bencher) {
176-
let v: Vec<u64> = (0..100).collect();
177-
b.iter(|| {
178-
let vec: Vec<u64> = Vec::from(&v[..]);
179-
vec
180-
});
181-
}
223+
fn bench_insert_many(b: &mut Bencher) {
224+
#[inline(never)]
225+
fn insert_many_noinline<I: IntoIterator<Item = u64>>(
226+
vec: &mut SmallVec<[u64; VEC_SIZE]>,
227+
index: usize,
228+
iterable: I,
229+
) {
230+
vec.insert_many(index, iterable)
231+
}
182232

183-
#[bench]
184-
fn bench_extend_from_slice_vec(b: &mut Bencher) {
185-
let v: Vec<u64> = (0..100).collect();
186233
b.iter(|| {
187-
let mut vec: Vec<u64> = Vec::with_capacity(16);
188-
vec.extend_from_slice(&v);
234+
let mut vec = SmallVec::<[u64; VEC_SIZE]>::new();
235+
insert_many_noinline(&mut vec, 0, 0..SPILLED_SIZE as _);
236+
insert_many_noinline(&mut vec, 0, 0..SPILLED_SIZE as _);
189237
vec
190238
});
191239
}
192240

193241
#[bench]
194-
fn bench_pushpop_vec(b: &mut Bencher) {
195-
#[inline(never)]
196-
fn pushpop_noinline(vec: &mut Vec<u64>, x: u64) {
197-
vec.push(x);
198-
vec.pop();
199-
}
200-
242+
fn bench_insert_from_slice(b: &mut Bencher) {
243+
let v: Vec<u64> = (0..SPILLED_SIZE as _).collect();
201244
b.iter(|| {
202-
let mut vec: Vec<u64> = Vec::with_capacity(16);
203-
for x in 0..100 {
204-
pushpop_noinline(&mut vec, x);
205-
}
245+
let mut vec = SmallVec::<[u64; VEC_SIZE]>::new();
246+
vec.insert_from_slice(0, &v);
247+
vec.insert_from_slice(0, &v);
206248
vec
207249
});
208250
}
209251

210252
#[bench]
211-
fn bench_macro_from_elem_vec(b: &mut Bencher) {
253+
fn bench_macro_from_list(b: &mut Bencher) {
212254
b.iter(|| {
213-
let vec: Vec<u64> = vec![42; 100];
255+
let vec: SmallVec<[u64; 16]> = smallvec![
256+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80,
257+
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000,
258+
0x80000, 0x100000,
259+
];
214260
vec
215261
});
216262
}
@@ -221,7 +267,7 @@ fn bench_macro_from_list_vec(b: &mut Bencher) {
221267
let vec: Vec<u64> = vec![
222268
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80,
223269
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000,
224-
0x80000, 0x100000
270+
0x80000, 0x100000,
225271
];
226272
vec
227273
});

0 commit comments

Comments
 (0)