Skip to content

Commit 34e0bcf

Browse files
wainwrightmarkvks
andauthored
Added new versions of choose and choose_stable (rust-random#1268)
* Added new versions of choose and choose_stable * Removed coin_flipper tests which were unnecessary and not building on ci * Performance optimizations in coin_flipper * Clippy fixes and more documentation * Added a correctness fix for coin_flipper * Update benches/seq.rs Co-authored-by: Vinzent Steinberg <Vinzent.Steinberg@gmail.com> * Update benches/seq.rs Co-authored-by: Vinzent Steinberg <Vinzent.Steinberg@gmail.com> * Removed old version of choose and choose stable and updated value stability tests * Moved sequence choose benchmarks to their own file * Reworked coin_flipper * Use criterion for seq_choose benches * Removed an old comment * Change how c is estimated in coin_flipper * Revert "Use criterion for seq_choose benches" This reverts commit 2339539. * Added seq_choose benches for smaller numbers * Removed some unneeded lines from seq_choose * Improvements in coin_flipper.rs * Small refactor of coin_flipper * Tidied comments in coin_flipper * Use criterion for seq_choose benchmarks * Made choose not generate a random number if len=1 * small change to IteratorRandom::choose * Made it easier to change seq_choose benchmarks RNG * Added Pcg64 benchmarks for seq_choose * Added TODO to coin_flipper * Changed criterion settings in seq_choose Co-authored-by: Vinzent Steinberg <Vinzent.Steinberg@gmail.com>
1 parent 38c9823 commit 34e0bcf

2 files changed

Lines changed: 112 additions & 71 deletions

File tree

seq.rs

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ extern crate test;
1313

1414
use test::Bencher;
1515

16+
use core::mem::size_of;
1617
use rand::prelude::*;
1718
use rand::seq::*;
18-
use core::mem::size_of;
1919

2020
// We force use of 32-bit RNG since seq code is optimised for use with 32-bit
2121
// generators on all platforms.
@@ -74,76 +74,6 @@ seq_slice_choose_multiple!(seq_slice_choose_multiple_950_of_1000, 950, 1000);
7474
seq_slice_choose_multiple!(seq_slice_choose_multiple_10_of_100, 10, 100);
7575
seq_slice_choose_multiple!(seq_slice_choose_multiple_90_of_100, 90, 100);
7676

77-
#[bench]
78-
fn seq_iter_choose_from_1000(b: &mut Bencher) {
79-
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
80-
let x: &mut [usize] = &mut [1; 1000];
81-
for (i, r) in x.iter_mut().enumerate() {
82-
*r = i;
83-
}
84-
b.iter(|| {
85-
let mut s = 0;
86-
for _ in 0..RAND_BENCH_N {
87-
s += x.iter().choose(&mut rng).unwrap();
88-
}
89-
s
90-
});
91-
b.bytes = size_of::<usize>() as u64 * crate::RAND_BENCH_N;
92-
}
93-
94-
#[derive(Clone)]
95-
struct UnhintedIterator<I: Iterator + Clone> {
96-
iter: I,
97-
}
98-
impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> {
99-
type Item = I::Item;
100-
101-
fn next(&mut self) -> Option<Self::Item> {
102-
self.iter.next()
103-
}
104-
}
105-
106-
#[derive(Clone)]
107-
struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> {
108-
iter: I,
109-
window_size: usize,
110-
}
111-
impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<I> {
112-
type Item = I::Item;
113-
114-
fn next(&mut self) -> Option<Self::Item> {
115-
self.iter.next()
116-
}
117-
118-
fn size_hint(&self) -> (usize, Option<usize>) {
119-
(core::cmp::min(self.iter.len(), self.window_size), None)
120-
}
121-
}
122-
123-
#[bench]
124-
fn seq_iter_unhinted_choose_from_1000(b: &mut Bencher) {
125-
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
126-
let x: &[usize] = &[1; 1000];
127-
b.iter(|| {
128-
UnhintedIterator { iter: x.iter() }
129-
.choose(&mut rng)
130-
.unwrap()
131-
})
132-
}
133-
134-
#[bench]
135-
fn seq_iter_window_hinted_choose_from_1000(b: &mut Bencher) {
136-
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
137-
let x: &[usize] = &[1; 1000];
138-
b.iter(|| {
139-
WindowHintedIterator {
140-
iter: x.iter(),
141-
window_size: 7,
142-
}
143-
.choose(&mut rng)
144-
})
145-
}
146-
14777
#[bench]
14878
fn seq_iter_choose_multiple_10_of_100(b: &mut Bencher) {
14979
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();

seq_choose.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2018-2022 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
9+
use rand::prelude::*;
10+
use rand::SeedableRng;
11+
12+
criterion_group!(
13+
name = benches;
14+
config = Criterion::default();
15+
targets = bench
16+
);
17+
criterion_main!(benches);
18+
19+
pub fn bench(c: &mut Criterion) {
20+
bench_rng::<rand_chacha::ChaCha20Rng>(c, "ChaCha20");
21+
bench_rng::<rand_pcg::Pcg32>(c, "Pcg32");
22+
bench_rng::<rand_pcg::Pcg64>(c, "Pcg64");
23+
}
24+
25+
fn bench_rng<Rng: RngCore + SeedableRng>(c: &mut Criterion, rng_name: &'static str) {
26+
for length in [1, 2, 3, 10, 100, 1000].map(|x| black_box(x)) {
27+
c.bench_function(
28+
format!("choose_size-hinted_from_{length}_{rng_name}").as_str(),
29+
|b| {
30+
let mut rng = Rng::seed_from_u64(123);
31+
b.iter(|| choose_size_hinted(length, &mut rng))
32+
},
33+
);
34+
35+
c.bench_function(
36+
format!("choose_stable_from_{length}_{rng_name}").as_str(),
37+
|b| {
38+
let mut rng = Rng::seed_from_u64(123);
39+
b.iter(|| choose_stable(length, &mut rng))
40+
},
41+
);
42+
43+
c.bench_function(
44+
format!("choose_unhinted_from_{length}_{rng_name}").as_str(),
45+
|b| {
46+
let mut rng = Rng::seed_from_u64(123);
47+
b.iter(|| choose_unhinted(length, &mut rng))
48+
},
49+
);
50+
51+
c.bench_function(
52+
format!("choose_windowed_from_{length}_{rng_name}").as_str(),
53+
|b| {
54+
let mut rng = Rng::seed_from_u64(123);
55+
b.iter(|| choose_windowed(length, 7, &mut rng))
56+
},
57+
);
58+
}
59+
}
60+
61+
fn choose_size_hinted<R: Rng>(max: usize, rng: &mut R) -> Option<usize> {
62+
let iterator = 0..max;
63+
iterator.choose(rng)
64+
}
65+
66+
fn choose_stable<R: Rng>(max: usize, rng: &mut R) -> Option<usize> {
67+
let iterator = 0..max;
68+
iterator.choose_stable(rng)
69+
}
70+
71+
fn choose_unhinted<R: Rng>(max: usize, rng: &mut R) -> Option<usize> {
72+
let iterator = UnhintedIterator { iter: (0..max) };
73+
iterator.choose(rng)
74+
}
75+
76+
fn choose_windowed<R: Rng>(max: usize, window_size: usize, rng: &mut R) -> Option<usize> {
77+
let iterator = WindowHintedIterator {
78+
iter: (0..max),
79+
window_size,
80+
};
81+
iterator.choose(rng)
82+
}
83+
84+
#[derive(Clone)]
85+
struct UnhintedIterator<I: Iterator + Clone> {
86+
iter: I,
87+
}
88+
impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> {
89+
type Item = I::Item;
90+
91+
fn next(&mut self) -> Option<Self::Item> {
92+
self.iter.next()
93+
}
94+
}
95+
96+
#[derive(Clone)]
97+
struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> {
98+
iter: I,
99+
window_size: usize,
100+
}
101+
impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<I> {
102+
type Item = I::Item;
103+
104+
fn next(&mut self) -> Option<Self::Item> {
105+
self.iter.next()
106+
}
107+
108+
fn size_hint(&self) -> (usize, Option<usize>) {
109+
(core::cmp::min(self.iter.len(), self.window_size), None)
110+
}
111+
}

0 commit comments

Comments
 (0)