Auto merge of #96626 - thomcc:rand-bump, r=m-ou-se

Avoid using `rand::thread_rng` in the stdlib benchmarks.

This is kind of an anti-pattern because it introduces extra nondeterminism for no real reason. In thread_rng's case this comes both from the random seed and also from the reseeding operations it does, which occasionally does syscalls (which adds additional nondeterminism). The impact of this would be pretty small in most cases, but it's a good practice to avoid (particularly because avoiding it was not hard).

Anyway, several of our benchmarks already did the right thing here anyway, so the change was pretty easy and mostly just applying it more universally. That said, the stdlib benchmarks aren't particularly stable (nor is our benchmark framework particularly great), so arguably this doesn't matter that much in practice.

~~Anyway, this also bumps the `rand` dev-dependency to 0.8, since it had fallen somewhat out of date.~~ Nevermind, too much of a headache.
This commit is contained in:
bors 2022-05-05 05:08:44 +00:00
commit 12d3f107c1
10 changed files with 43 additions and 28 deletions

View File

@ -828,6 +828,7 @@ name = "core"
version = "0.0.0"
dependencies = [
"rand 0.7.3",
"rand_xorshift",
]
[[package]]

View File

@ -1,11 +1,11 @@
use std::collections::BinaryHeap;
use rand::{seq::SliceRandom, thread_rng};
use rand::seq::SliceRandom;
use test::{black_box, Bencher};
#[bench]
fn bench_find_smallest_1000(b: &mut Bencher) {
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
let mut vec: Vec<u32> = (0..100_000).collect();
vec.shuffle(&mut rng);
@ -47,7 +47,7 @@ fn bench_peek_mut_deref_mut(b: &mut Bencher) {
#[bench]
fn bench_from_vec(b: &mut Bencher) {
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
let mut vec: Vec<u32> = (0..100_000).collect();
vec.shuffle(&mut rng);
@ -64,7 +64,7 @@ fn bench_into_sorted_vec(b: &mut Bencher) {
#[bench]
fn bench_push(b: &mut Bencher) {
let mut bheap = BinaryHeap::with_capacity(50_000);
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
let mut vec: Vec<u32> = (0..50_000).collect();
vec.shuffle(&mut rng);

View File

@ -3,7 +3,7 @@ use std::iter::Iterator;
use std::ops::RangeBounds;
use std::vec::Vec;
use rand::{seq::SliceRandom, thread_rng, Rng};
use rand::{seq::SliceRandom, Rng};
use test::{black_box, Bencher};
macro_rules! map_insert_rand_bench {
@ -13,7 +13,7 @@ macro_rules! map_insert_rand_bench {
let n: usize = $n;
let mut map = $map::new();
// setup
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
for _ in 0..n {
let i = rng.gen::<usize>() % n;
@ -60,7 +60,7 @@ macro_rules! map_from_iter_rand_bench {
pub fn $name(b: &mut Bencher) {
let n: usize = $n;
// setup
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
let mut vec = Vec::with_capacity(n);
for _ in 0..n {
@ -106,7 +106,7 @@ macro_rules! map_find_rand_bench {
let n: usize = $n;
// setup
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
let mut keys: Vec<_> = (0..n).map(|_| rng.gen::<usize>() % n).collect();
for &k in &keys {
@ -169,7 +169,7 @@ map_find_seq_bench! {find_seq_10_000, 10_000, BTreeMap}
fn bench_iteration(b: &mut Bencher, size: i32) {
let mut map = BTreeMap::<i32, i32>::new();
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
for _ in 0..size {
map.insert(rng.gen(), rng.gen());
@ -199,7 +199,7 @@ pub fn iteration_100000(b: &mut Bencher) {
fn bench_iteration_mut(b: &mut Bencher, size: i32) {
let mut map = BTreeMap::<i32, i32>::new();
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
for _ in 0..size {
map.insert(rng.gen(), rng.gen());

View File

@ -1,10 +1,10 @@
use std::collections::BTreeSet;
use rand::{thread_rng, Rng};
use rand::Rng;
use test::Bencher;
fn random(n: usize) -> BTreeSet<usize> {
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
let mut set = BTreeSet::new();
while set.len() < n {
set.insert(rng.gen());

View File

@ -17,3 +17,11 @@ mod str;
mod string;
mod vec;
mod vec_deque;
/// Returns a `rand::Rng` seeded with a consistent seed.
///
/// This is done to avoid introducing nondeterminism in benchmark results.
fn bench_rng() -> rand_xorshift::XorShiftRng {
const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
rand::SeedableRng::from_seed(SEED)
}

View File

@ -1,8 +1,7 @@
use std::{mem, ptr};
use rand::distributions::{Alphanumeric, Standard};
use rand::{thread_rng, Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use rand::Rng;
use test::{black_box, Bencher};
#[bench]
@ -152,7 +151,7 @@ fn zero_1kb_mut_iter(b: &mut Bencher) {
#[bench]
fn random_inserts(b: &mut Bencher) {
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
b.iter(|| {
let mut v = vec![(0, 0); 30];
for _ in 0..100 {
@ -164,7 +163,7 @@ fn random_inserts(b: &mut Bencher) {
#[bench]
fn random_removes(b: &mut Bencher) {
let mut rng = thread_rng();
let mut rng = crate::bench_rng();
b.iter(|| {
let mut v = vec![(0, 0); 130];
for _ in 0..100 {
@ -182,20 +181,18 @@ fn gen_descending(len: usize) -> Vec<u64> {
(0..len as u64).rev().collect()
}
const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
fn gen_random(len: usize) -> Vec<u64> {
let mut rng = XorShiftRng::from_seed(SEED);
let mut rng = crate::bench_rng();
(&mut rng).sample_iter(&Standard).take(len).collect()
}
fn gen_random_bytes(len: usize) -> Vec<u8> {
let mut rng = XorShiftRng::from_seed(SEED);
let mut rng = crate::bench_rng();
(&mut rng).sample_iter(&Standard).take(len).collect()
}
fn gen_mostly_ascending(len: usize) -> Vec<u64> {
let mut rng = XorShiftRng::from_seed(SEED);
let mut rng = crate::bench_rng();
let mut v = gen_ascending(len);
for _ in (0usize..).take_while(|x| x * x <= len) {
let x = rng.gen::<usize>() % len;
@ -206,7 +203,7 @@ fn gen_mostly_ascending(len: usize) -> Vec<u64> {
}
fn gen_mostly_descending(len: usize) -> Vec<u64> {
let mut rng = XorShiftRng::from_seed(SEED);
let mut rng = crate::bench_rng();
let mut v = gen_descending(len);
for _ in (0usize..).take_while(|x| x * x <= len) {
let x = rng.gen::<usize>() % len;
@ -217,7 +214,7 @@ fn gen_mostly_descending(len: usize) -> Vec<u64> {
}
fn gen_strings(len: usize) -> Vec<String> {
let mut rng = XorShiftRng::from_seed(SEED);
let mut rng = crate::bench_rng();
let mut v = vec![];
for _ in 0..len {
let n = rng.gen::<usize>() % 20 + 1;
@ -227,7 +224,7 @@ fn gen_strings(len: usize) -> Vec<String> {
}
fn gen_big_random(len: usize) -> Vec<[u64; 16]> {
let mut rng = XorShiftRng::from_seed(SEED);
let mut rng = crate::bench_rng();
(&mut rng).sample_iter(&Standard).map(|x| [x; 16]).take(len).collect()
}

View File

@ -476,7 +476,7 @@ fn bench_in_place_recycle(b: &mut Bencher) {
#[bench]
fn bench_in_place_zip_recycle(b: &mut Bencher) {
let mut data = vec![0u8; 1000];
let mut rng = rand::thread_rng();
let mut rng = crate::bench_rng();
let mut subst = vec![0u8; 1000];
rng.fill_bytes(&mut subst[..]);
@ -495,7 +495,7 @@ fn bench_in_place_zip_recycle(b: &mut Bencher) {
#[bench]
fn bench_in_place_zip_iter_mut(b: &mut Bencher) {
let mut data = vec![0u8; 256];
let mut rng = rand::thread_rng();
let mut rng = crate::bench_rng();
let mut subst = vec![0u8; 1000];
rng.fill_bytes(&mut subst[..]);

View File

@ -25,6 +25,7 @@ test = true
[dev-dependencies]
rand = "0.7"
rand_xorshift = "0.2"
[features]
# Make panics and failed asserts immediately abort without formatting any message

View File

@ -18,3 +18,11 @@ mod ops;
mod pattern;
mod slice;
mod str;
/// Returns a `rand::Rng` seeded with a consistent seed.
///
/// This is done to avoid introducing nondeterminism in benchmark results.
fn bench_rng() -> rand_xorshift::XorShiftRng {
const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
rand::SeedableRng::from_seed(SEED)
}

View File

@ -17,7 +17,7 @@ macro_rules! int_log_bench {
#[bench]
fn $random(bench: &mut Bencher) {
let mut rng = rand::thread_rng();
let mut rng = crate::bench_rng();
/* Exponentially distributed random numbers from the whole range of the type. */
let numbers: Vec<$t> = (0..256)
.map(|_| {
@ -34,7 +34,7 @@ macro_rules! int_log_bench {
#[bench]
fn $random_small(bench: &mut Bencher) {
let mut rng = rand::thread_rng();
let mut rng = crate::bench_rng();
/* Exponentially distributed random numbers from the range 0..256. */
let numbers: Vec<$t> = (0..256)
.map(|_| {