From 0c0f9311bbce0c41a6705db2b0957ff772111ce7 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 22 Apr 2019 11:42:07 +0100 Subject: [PATCH 1/2] Remove specialisations of fill_bytes for block RNGs These specialisations relied on casting a u8 byte slice to a u32 or u64 slice, which is UB due to alignment requirements. --- rand_core/src/block.rs | 84 ------------------------------------------ 1 file changed, 84 deletions(-) diff --git a/rand_core/src/block.rs b/rand_core/src/block.rs index 6772a18a895..0d4caae7261 100644 --- a/rand_core/src/block.rs +++ b/rand_core/src/block.rs @@ -210,48 +210,6 @@ where ::Results: AsRef<[u32]> + AsMut<[u32]> } } - // As an optimization we try to write directly into the output buffer. - // This is only enabled for little-endian platforms where unaligned writes - // are known to be safe and fast. - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut filled = 0; - - // Continue filling from the current set of results - if self.index < self.results.as_ref().len() { - let (consumed_u32, filled_u8) = - fill_via_u32_chunks(&self.results.as_ref()[self.index..], - dest); - - self.index += consumed_u32; - filled += filled_u8; - } - - let len_remainder = - (dest.len() - filled) % (self.results.as_ref().len() * 4); - let end_direct = dest.len() - len_remainder; - - while filled < end_direct { - let dest_u32: &mut R::Results = unsafe { - &mut *(dest[filled..].as_mut_ptr() as - *mut ::Results) - }; - self.core.generate(dest_u32); - filled += self.results.as_ref().len() * 4; - self.index = self.results.as_ref().len(); - } - - if len_remainder > 0 { - self.core.generate(&mut self.results); - let (consumed_u32, _) = - fill_via_u32_chunks(self.results.as_ref(), - &mut dest[filled..]); - - self.index = consumed_u32; - } - } - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn fill_bytes(&mut self, dest: &mut [u8]) { let mut read_len = 0; while read_len < dest.len() { @@ -416,48 +374,6 @@ where ::Results: AsRef<[u64]> + AsMut<[u64]> value } - // As an optimization we try to write directly into the output buffer. - // This is only enabled for little-endian platforms where unaligned writes - // are known to be safe and fast. - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut filled = 0; - self.half_used = false; - - // Continue filling from the current set of results - if self.index < self.results.as_ref().len() { - let (consumed_u64, filled_u8) = - fill_via_u64_chunks(&self.results.as_ref()[self.index..], - dest); - - self.index += consumed_u64; - filled += filled_u8; - } - - let len_remainder = - (dest.len() - filled) % (self.results.as_ref().len() * 8); - let end_direct = dest.len() - len_remainder; - - while filled < end_direct { - let dest_u64: &mut R::Results = unsafe { - ::core::mem::transmute(dest[filled..].as_mut_ptr()) - }; - self.core.generate(dest_u64); - filled += self.results.as_ref().len() * 8; - self.index = self.results.as_ref().len(); - } - - if len_remainder > 0 { - self.core.generate(&mut self.results); - let (consumed_u64, _) = - fill_via_u64_chunks(&mut self.results.as_ref(), - &mut dest[filled..]); - - self.index = consumed_u64; - } - } - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn fill_bytes(&mut self, dest: &mut [u8]) { let mut read_len = 0; self.half_used = false; From 232c634c61699ffc0b555884fd072117df336fa3 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 22 Apr 2019 11:43:48 +0100 Subject: [PATCH 2/2] Benches: fix warnings and move Binomial benches to appropriate suite --- benches/distributions.rs | 23 +++++++++++++++++++++-- benches/generators.rs | 6 +++--- benches/misc.rs | 24 ++---------------------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/benches/distributions.rs b/benches/distributions.rs index eabda4d491c..a78555a573d 100644 --- a/benches/distributions.rs +++ b/benches/distributions.rs @@ -20,8 +20,7 @@ use std::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128}; use test::Bencher; use std::time::Duration; -use rand::{Rng, FromEntropy}; -use rand::rngs::SmallRng; +use rand::prelude::*; use rand_distr::{*, weighted::WeightedIndex}; macro_rules! distr_int { @@ -291,3 +290,23 @@ fn dist_iter(b: &mut Bencher) { }); b.bytes = size_of::() as u64 * ::RAND_BENCH_N; } + +macro_rules! sample_binomial { + ($name:ident, $n:expr, $p:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let (n, p) = ($n, $p); + b.iter(|| { + let d = Binomial::new(n, p).unwrap(); + rng.sample(d) + }) + } + } +} + +sample_binomial!(misc_binomial_1, 1, 0.9); +sample_binomial!(misc_binomial_10, 10, 0.9); +sample_binomial!(misc_binomial_100, 100, 0.99); +sample_binomial!(misc_binomial_1000, 1000, 0.01); +sample_binomial!(misc_binomial_1e12, 1000_000_000_000, 0.2); diff --git a/benches/generators.rs b/benches/generators.rs index b9bb9cd746d..19f811804f2 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -70,7 +70,7 @@ gen_bytes!(gen_bytes_isaac, IsaacRng::from_entropy()); gen_bytes!(gen_bytes_isaac64, Isaac64Rng::from_entropy()); gen_bytes!(gen_bytes_std, StdRng::from_entropy()); gen_bytes!(gen_bytes_small, SmallRng::from_entropy()); -gen_bytes!(gen_bytes_os, OsRng::new().unwrap()); +gen_bytes!(gen_bytes_os, OsRng); macro_rules! gen_uint { ($fnn:ident, $ty:ty, $gen:expr) => { @@ -107,7 +107,7 @@ gen_uint!(gen_u32_isaac, u32, IsaacRng::from_entropy()); gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::from_entropy()); gen_uint!(gen_u32_std, u32, StdRng::from_entropy()); gen_uint!(gen_u32_small, u32, SmallRng::from_entropy()); -gen_uint!(gen_u32_os, u32, OsRng::new().unwrap()); +gen_uint!(gen_u32_os, u32, OsRng); gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy()); gen_uint!(gen_u64_xoshiro256starstar, u64, Xoshiro256StarStar::from_entropy()); @@ -127,7 +127,7 @@ gen_uint!(gen_u64_isaac, u64, IsaacRng::from_entropy()); gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::from_entropy()); gen_uint!(gen_u64_std, u64, StdRng::from_entropy()); gen_uint!(gen_u64_small, u64, SmallRng::from_entropy()); -gen_uint!(gen_u64_os, u64, OsRng::new().unwrap()); +gen_uint!(gen_u64_os, u64, OsRng); macro_rules! init_gen { ($fnn:ident, $gen:ident) => { diff --git a/benches/misc.rs b/benches/misc.rs index 8fb3a832f22..4577ac76682 100644 --- a/benches/misc.rs +++ b/benches/misc.rs @@ -16,6 +16,7 @@ const RAND_BENCH_N: u64 = 1000; use test::Bencher; use rand::prelude::*; +use rand::distributions::{Distribution, Standard, Bernoulli}; #[bench] fn misc_gen_bool_const(b: &mut Bencher) { @@ -87,7 +88,7 @@ fn misc_bernoulli_var(b: &mut Bencher) { let mut accum = true; let mut p = 0.18; for _ in 0..::RAND_BENCH_N { - let d = rand::distributions::Bernoulli::new(p); + let d = Bernoulli::new(p); accum ^= rng.sample(d); p += 0.0001; } @@ -95,26 +96,6 @@ fn misc_bernoulli_var(b: &mut Bencher) { }) } -macro_rules! sample_binomial { - ($name:ident, $n:expr, $p:expr) => { - #[bench] - fn $name(b: &mut Bencher) { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let (n, p) = ($n, $p); - b.iter(|| { - let d = rand::distributions::Binomial::new(n, p); - rng.sample(d) - }) - } - } -} - -sample_binomial!(misc_binomial_1, 1, 0.9); -sample_binomial!(misc_binomial_10, 10, 0.9); -sample_binomial!(misc_binomial_100, 100, 0.99); -sample_binomial!(misc_binomial_1000, 1000, 0.01); -sample_binomial!(misc_binomial_1e12, 1000_000_000_000, 0.2); - #[bench] fn gen_1k_iter_repeat(b: &mut Bencher) { use std::iter; @@ -128,7 +109,6 @@ fn gen_1k_iter_repeat(b: &mut Bencher) { #[bench] fn gen_1k_sample_iter(b: &mut Bencher) { - use rand::distributions::{Distribution, Standard}; let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); b.iter(|| { let v: Vec = Standard.sample_iter(&mut rng).take(128).collect();