Skip to content

Commit

Permalink
Auto merge of #96626 - thomcc:rand-bump, r=m-ou-se
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed May 5, 2022
2 parents 7d3e036 + 0812759 commit 12d3f10
Show file tree
Hide file tree
Showing 10 changed files with 43 additions and 28 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,7 @@ name = "core"
version = "0.0.0"
dependencies = [
"rand 0.7.3",
"rand_xorshift",
]

[[package]]
Expand Down
8 changes: 4 additions & 4 deletions library/alloc/benches/binary_heap.rs
Original file line number Diff line number Diff line change
@@ -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);

Expand Down Expand Up @@ -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);

Expand All @@ -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);

Expand Down
12 changes: 6 additions & 6 deletions library/alloc/benches/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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());
Expand Down
4 changes: 2 additions & 2 deletions library/alloc/benches/btree/set.rs
Original file line number Diff line number Diff line change
@@ -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());
Expand Down
8 changes: 8 additions & 0 deletions library/alloc/benches/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
21 changes: 9 additions & 12 deletions library/alloc/benches/slice.rs
Original file line number Diff line number Diff line change
@@ -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]
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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()
}

Expand Down
4 changes: 2 additions & 2 deletions library/alloc/benches/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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[..]);

Expand All @@ -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[..]);

Expand Down
1 change: 1 addition & 0 deletions library/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions library/core/benches/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
4 changes: 2 additions & 2 deletions library/core/benches/num/int_log/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(|_| {
Expand All @@ -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(|_| {
Expand Down

0 comments on commit 12d3f10

Please sign in to comment.