Skip to content

Commit d26bf8a

Browse files
committed
Improve benchmarks
1 parent 7e76353 commit d26bf8a

File tree

2 files changed

+211
-145
lines changed

2 files changed

+211
-145
lines changed

dec/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ static_assertions = "1.1.0"
1919

2020
[dev-dependencies]
2121
criterion = "0.3.0"
22+
itertools = "0.10.1"
2223
rand = "0.7.3"
2324
serde_test = "1.0.117"
2425

dec/benches/dec.rs

Lines changed: 210 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -13,169 +13,234 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16-
use std::convert::TryFrom;
17-
18-
use criterion::{criterion_group, criterion_main, Bencher, Criterion};
16+
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
17+
use itertools::Itertools as _;
1918
use rand::{thread_rng, Rng};
2019

2120
use dec::{Context, Decimal, Decimal128, Decimal64};
2221

23-
fn bench_decode_decimal64(d: Decimal64, b: &mut Bencher) {
24-
b.iter_with_setup(|| d.clone(), |d| (d.exponent(), d.coefficient()))
25-
}
22+
use std::fmt;
2623

27-
fn bench_decode_decimal128(d: Decimal128, b: &mut Bencher) {
28-
b.iter_with_setup(|| d.clone(), |d| (d.exponent(), d.coefficient()))
24+
fn bench_to_string<T: fmt::Display>(slice: &[T]) {
25+
for d in slice {
26+
let string = d.to_string();
27+
black_box(string);
28+
}
2929
}
3030

31-
pub fn bench_decode(c: &mut Criterion) {
32-
// decode_decimal64
33-
let mut rng = thread_rng();
34-
let mut cx = Context::<Decimal64>::default();
35-
let d64 = cx.from_i64(rng.gen());
36-
c.bench_function("decode_decimal64", |b| bench_decode_decimal64(d64, b));
31+
macro_rules! bench_fixed_impl {
32+
($bencher: ident, $size: expr, $type: ty, $group: expr) => {
33+
let mut cx = Context::<$type>::default();
3734

38-
// decode_decimal128
39-
let mut rng = thread_rng();
40-
let mut cx = Context::<Decimal128>::default();
41-
let d128 = cx.from_i128(rng.gen());
42-
c.bench_function("decode_decimal128", |b| bench_decode_decimal128(d128, b));
43-
}
35+
let vec: Vec<$type> = (0..$size)
36+
.into_iter()
37+
.map(|_| {
38+
let array = thread_rng().gen();
39+
<$type>::from_ne_bytes(array)
40+
})
41+
.collect();
4442

45-
pub fn bench_to_string(d: Decimal128, b: &mut Bencher) {
46-
b.iter_with_setup(
47-
|| {
48-
let mut cx = Context::<Decimal128>::default();
49-
[-50, 0, 50]
50-
.iter()
51-
.map(|exp| {
52-
let mut d = d.clone();
53-
cx.set_exponent(&mut d, *exp);
54-
d
55-
})
56-
.collect::<Vec<_>>()
57-
},
58-
|d| {
59-
for d in d {
60-
d.to_string();
61-
}
62-
},
63-
)
43+
let mut group = $bencher.benchmark_group($group);
44+
group
45+
.throughput(Throughput::Elements(SIZE))
46+
.bench_with_input("to_string", &vec, |b, vec| b.iter(|| bench_to_string(vec)));
47+
group
48+
.throughput(Throughput::Elements(SIZE))
49+
.bench_with_input("to_standard_notation_string", &vec, |b, vec| {
50+
b.iter(|| {
51+
for &d in vec {
52+
let string = d.to_standard_notation_string();
53+
black_box(string);
54+
}
55+
})
56+
});
57+
group
58+
.throughput(Throughput::Elements(SIZE))
59+
.bench_with_input("coefficient", &vec, |b, vec| {
60+
b.iter(|| {
61+
for &d in vec {
62+
let coeff = d.coefficient();
63+
black_box(coeff);
64+
}
65+
})
66+
});
67+
group
68+
.throughput(Throughput::Elements(SIZE))
69+
.bench_with_input("exponent", &vec, |b, vec| {
70+
b.iter(|| {
71+
for &d in vec {
72+
let exp = d.exponent();
73+
black_box(exp);
74+
}
75+
})
76+
});
77+
group
78+
.throughput(Throughput::Elements(SIZE / 2))
79+
.bench_with_input("add", &vec, |b, vec| {
80+
b.iter(|| {
81+
for (&a, &b) in vec.iter().tuples::<(_, _)>() {
82+
let c = cx.add(a, b);
83+
black_box(c);
84+
}
85+
})
86+
});
87+
group
88+
.throughput(Throughput::Elements(SIZE / 2))
89+
.bench_with_input("sub", &vec, |b, vec| {
90+
b.iter(|| {
91+
for (&a, &b) in vec.iter().tuples::<(_, _)>() {
92+
let c = cx.sub(a, b);
93+
black_box(c);
94+
}
95+
})
96+
});
97+
group
98+
.throughput(Throughput::Elements(SIZE / 2))
99+
.bench_with_input("mul", &vec, |b, vec| {
100+
b.iter(|| {
101+
for (&a, &b) in vec.iter().tuples::<(_, _)>() {
102+
let c = cx.mul(a, b);
103+
black_box(c);
104+
}
105+
})
106+
});
107+
group
108+
.throughput(Throughput::Elements(SIZE / 2))
109+
.bench_with_input("div", &vec, |b, vec| {
110+
b.iter(|| {
111+
for (&a, &b) in vec.iter().tuples::<(_, _)>() {
112+
let c = cx.div(a, b);
113+
black_box(c);
114+
}
115+
})
116+
});
117+
group
118+
.throughput(Throughput::Elements(SIZE))
119+
.bench_with_input("abs", &vec, |b, vec| {
120+
b.iter(|| {
121+
for &d in vec {
122+
let v = cx.abs(d);
123+
black_box(v);
124+
}
125+
})
126+
});
127+
group.finish();
128+
};
64129
}
65130

66-
pub fn bench_to_string_64(d: Decimal64, b: &mut Bencher) {
67-
b.iter_with_setup(
68-
|| {
69-
let mut cx = Context::<Decimal64>::default();
70-
[-50, 0, 50]
71-
.iter()
72-
.map(|exp| {
73-
let mut d = d.clone();
74-
cx.set_exponent(&mut d, *exp);
75-
d
76-
})
77-
.collect::<Vec<_>>()
78-
},
79-
|d| {
80-
for d in d {
81-
d.to_string();
82-
}
83-
},
84-
)
85-
}
131+
fn bench_fixed_size(bencher: &mut Criterion) {
132+
const SIZE: u64 = 10_000;
86133

87-
pub fn bench_standard_notation_string(d: Decimal128, b: &mut Bencher) {
88-
b.iter_with_setup(
89-
|| {
90-
let mut cx = Context::<Decimal128>::default();
91-
[-50, 0, 50]
92-
.iter()
93-
.map(|exp| {
94-
let mut d = d.clone();
95-
cx.set_exponent(&mut d, *exp);
96-
d
97-
})
98-
.collect::<Vec<_>>()
99-
},
100-
|d| {
101-
for d in d {
102-
d.to_standard_notation_string();
103-
}
104-
},
105-
)
134+
bench_fixed_impl!(bencher, SIZE, Decimal64, "Decimal64");
135+
bench_fixed_impl!(bencher, SIZE, Decimal128, "Decimal128");
106136
}
107137

108-
pub fn bench_standard_notation_string_64(d: Decimal64, b: &mut Bencher) {
109-
b.iter_with_setup(
110-
|| {
111-
let mut cx = Context::<Decimal64>::default();
112-
[-50, 0, 50]
113-
.iter()
114-
.map(|exp| {
115-
let mut d = d.clone();
116-
cx.set_exponent(&mut d, *exp);
117-
d
118-
})
119-
.collect::<Vec<_>>()
120-
},
121-
|d| {
122-
for d in d {
123-
d.to_standard_notation_string();
124-
}
125-
},
126-
)
127-
}
138+
macro_rules! bench_dyn_impl {
139+
($bencher: ident, $size: expr, $type: ty, $group: expr) => {
140+
let mut cx = Context::<$type>::default();
128141

129-
pub fn bench_print(c: &mut Criterion) {
130-
let mut rng = thread_rng();
131-
let mut cx = Context::<Decimal128>::default();
132-
let d128 = cx.from_i128(rng.gen());
133-
c.bench_function("to_string_dec128", |b| bench_to_string(d128.clone(), b));
134-
let mut rng = thread_rng();
135-
let mut cx = Context::<Decimal128>::default();
136-
let d128 = cx.from_i128(rng.gen());
137-
c.bench_function("to_standard_notation_string_dec128", |b| {
138-
bench_standard_notation_string(d128, b)
139-
});
140-
let mut rng = thread_rng();
141-
let mut cx = Context::<Decimal64>::default();
142-
let d64 = cx.from_i64(rng.gen());
143-
c.bench_function("to_string_dec64", |b| bench_to_string_64(d64.clone(), b));
144-
let mut rng = thread_rng();
145-
let mut cx = Context::<Decimal64>::default();
146-
let d64 = cx.from_i64(rng.gen());
147-
c.bench_function("to_standard_notation_string_dec64", |b| {
148-
bench_standard_notation_string_64(d64, b)
149-
});
150-
}
142+
let vec: Vec<$type> = (0..$size)
143+
.into_iter()
144+
.map(|_| {
145+
let array = thread_rng().gen();
146+
Decimal128::from_ne_bytes(array).into()
147+
})
148+
.collect();
151149

152-
pub fn bench_try_into_primitive(d: Decimal<13>, b: &mut Bencher) {
153-
b.iter_with_setup(
154-
|| {
155-
[-1, 0, 1]
156-
.iter()
157-
.map(|exp| {
158-
let mut d = d.clone();
159-
d.set_exponent(*exp);
160-
d
161-
})
162-
.collect::<Vec<_>>()
163-
},
164-
|v| {
165-
for d in v {
166-
let _ = i128::try_from(d);
167-
}
168-
},
169-
)
150+
let mut group = $bencher.benchmark_group($group);
151+
group
152+
.throughput(Throughput::Elements(SIZE))
153+
.bench_with_input("to_string", &vec, |b, vec| b.iter(|| bench_to_string(vec)));
154+
group
155+
.throughput(Throughput::Elements(SIZE))
156+
.bench_with_input("to_standard_notation_string", &vec, |b, vec| {
157+
b.iter(|| {
158+
for &d in vec {
159+
let string = d.to_standard_notation_string();
160+
black_box(string);
161+
}
162+
})
163+
});
164+
group
165+
.throughput(Throughput::Elements(SIZE))
166+
.bench_with_input("coefficient", &vec, |b, vec| {
167+
b.iter(|| {
168+
for &(mut d) in vec {
169+
let res = d.coefficient::<$type>();
170+
let _ = black_box(res);
171+
}
172+
})
173+
});
174+
group
175+
.throughput(Throughput::Elements(SIZE))
176+
.bench_with_input("exponent", &vec, |b, vec| {
177+
b.iter(|| {
178+
for &d in vec {
179+
let exp = d.exponent();
180+
black_box(exp);
181+
}
182+
})
183+
});
184+
group
185+
.throughput(Throughput::Elements(SIZE / 2))
186+
.bench_with_input("add", &vec, |b, vec| {
187+
b.iter(|| {
188+
for (&(mut a), &b) in vec.iter().tuples::<(_, _)>() {
189+
let c = cx.add(&mut a, &b);
190+
black_box(c);
191+
}
192+
})
193+
});
194+
group
195+
.throughput(Throughput::Elements(SIZE / 2))
196+
.bench_with_input("sub", &vec, |b, vec| {
197+
b.iter(|| {
198+
for (&(mut a), &b) in vec.iter().tuples::<(_, _)>() {
199+
let c = cx.sub(&mut a, &b);
200+
black_box(c);
201+
}
202+
})
203+
});
204+
group
205+
.throughput(Throughput::Elements(SIZE / 2))
206+
.bench_with_input("mul", &vec, |b, vec| {
207+
b.iter(|| {
208+
for (&(mut a), &b) in vec.iter().tuples::<(_, _)>() {
209+
let c = cx.mul(&mut a, &b);
210+
black_box(c);
211+
}
212+
})
213+
});
214+
group
215+
.throughput(Throughput::Elements(SIZE / 2))
216+
.bench_with_input("div", &vec, |b, vec| {
217+
b.iter(|| {
218+
for (&(mut a), &b) in vec.iter().tuples::<(_, _)>() {
219+
let c = cx.div(&mut a, &b);
220+
black_box(c);
221+
}
222+
})
223+
});
224+
group
225+
.throughput(Throughput::Elements(SIZE))
226+
.bench_with_input("abs", &vec, |b, vec| {
227+
b.iter(|| {
228+
for &(mut d) in vec {
229+
let v = cx.abs(&mut d);
230+
black_box(v);
231+
}
232+
})
233+
});
234+
group.finish();
235+
};
170236
}
171237

172-
pub fn bench_tryinto_primitive(c: &mut Criterion) {
173-
let mut rng = thread_rng();
174-
let d: Decimal<13> = i32::into(rng.gen());
175-
c.bench_function("bench_try_into_primitive", |b| {
176-
bench_try_into_primitive(d.clone(), b)
177-
});
238+
fn bench_dyn_size(bencher: &mut Criterion) {
239+
const SIZE: u64 = 10_000;
240+
241+
bench_dyn_impl!(bencher, SIZE, Decimal<12>, "Decimal<12>");
242+
bench_dyn_impl!(bencher, SIZE, Decimal<16>, "Decimal<16>");
178243
}
179244

180-
criterion_group!(benches, bench_decode, bench_print, bench_tryinto_primitive);
245+
criterion_group!(benches, bench_fixed_size, bench_dyn_size);
181246
criterion_main!(benches);

0 commit comments

Comments
 (0)