diff --git a/.travis.yml b/.travis.yml index 450a15959..9a563ab47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,12 +15,6 @@ matrix: - rust: 1.13.0 os: linux #if: everything! - before_script: - # rand 0.4.2 requires rust 1.15, and rand-0.3.22 requires rand-0.4 :/ - # manually lowering the dependency in rayon-core: - - sed -i -e 's/^rand = .*$/rand = "=0.3.20"/' rayon-core/Cargo.toml - - cargo generate-lockfile - - git checkout rayon-core/Cargo.toml - rust: stable os: linux diff --git a/Cargo.toml b/Cargo.toml index 873bf62ed..7693c613a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ default-features = false [dev-dependencies] docopt = "0.8" lazy_static = "1" -rand = ">= 0.3, < 0.5" +rand = "0.4" serde = "1" serde_derive = "1" diff --git a/rayon-core/Cargo.toml b/rayon-core/Cargo.toml index b918286e6..c98bf6d6f 100644 --- a/rayon-core/Cargo.toml +++ b/rayon-core/Cargo.toml @@ -14,7 +14,6 @@ keywords = ["parallel", "thread", "concurrency", "join", "performance"] categories = ["concurrency"] [dependencies] -rand = ">= 0.3, < 0.5" num_cpus = "1.2" libc = "0.2.16" lazy_static = "1" @@ -25,3 +24,4 @@ lazy_static = "1" version = "0.2.0" [dev-dependencies] +rand = "0.4" diff --git a/rayon-core/src/lib.rs b/rayon-core/src/lib.rs index 1e85e69f0..c8cbe3ba1 100644 --- a/rayon-core/src/lib.rs +++ b/rayon-core/src/lib.rs @@ -37,6 +37,8 @@ extern crate crossbeam_deque; extern crate lazy_static; extern crate libc; extern crate num_cpus; + +#[cfg(test)] extern crate rand; #[macro_use] diff --git a/rayon-core/src/registry.rs b/rayon-core/src/registry.rs index 18748b344..0fb8e2038 100644 --- a/rayon-core/src/registry.rs +++ b/rayon-core/src/registry.rs @@ -7,14 +7,15 @@ use job::Job; use internal::task::Task; use latch::{LatchProbe, Latch, CountLatch, LockLatch, SpinLatch, TickleLatch}; use log::Event::*; -use rand::{self, Rng}; use sleep::Sleep; use std::any::Any; -use std::cell::{Cell, UnsafeCell}; +use std::cell::Cell; +use std::collections::hash_map::DefaultHasher; +use std::hash::Hasher; use std::sync::{Arc, Mutex, Once, ONCE_INIT}; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use std::thread; use std::mem; -use std::u32; use std::usize; use unwind; use util::leak; @@ -460,7 +461,7 @@ pub struct WorkerThread { breadth_first: bool, /// A weak random number generator. - rng: UnsafeCell, + rng: XorShift64Star, registry: Arc, } @@ -602,17 +603,8 @@ impl WorkerThread { if num_threads <= 1 { return None; } - assert!(num_threads < (u32::MAX as usize), - "we do not support more than u32::MAX worker threads"); - - let start = { - // OK to use this UnsafeCell because (a) this data is - // confined to current thread, as WorkerThread is not Send - // nor Sync and (b) rand crate will not call back into - // this method. - let rng = &mut *self.rng.get(); - rng.next_u32() % num_threads as u32 - } as usize; + + let start = self.rng.next_usize(num_threads); (start .. num_threads) .chain(0 .. start) .filter(|&i| i != self.index) @@ -646,7 +638,7 @@ unsafe fn main_loop(worker: Deque, worker: worker, breadth_first: breadth_first, index: index, - rng: UnsafeCell::new(rand::weak_rng()), + rng: XorShift64Star::new(), registry: registry.clone(), }; WorkerThread::set_current(&worker_thread); @@ -716,3 +708,43 @@ pub fn in_worker(op: OP) -> R } } } + +/// [xorshift*] is a fast pseudorandom number generator which will +/// even tolerate weak seeding, as long as it's not zero. +/// +/// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift* +struct XorShift64Star { + state: Cell, +} + +impl XorShift64Star { + fn new() -> Self { + // Any non-zero seed will do -- this uses the hash of a global counter. + let mut seed = 0; + while seed == 0 { + let mut hasher = DefaultHasher::new(); + static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed)); + seed = hasher.finish(); + } + + XorShift64Star { + state: Cell::new(seed), + } + } + + fn next(&self) -> u64 { + let mut x = self.state.get(); + debug_assert_ne!(x, 0); + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + self.state.set(x); + x.wrapping_mul(0x2545_f491_4f6c_dd1d) + } + + /// Return a value from `0..n`. + fn next_usize(&self, n: usize) -> usize { + (self.next() % n as u64) as usize + } +} diff --git a/rayon-demo/Cargo.toml b/rayon-demo/Cargo.toml index e2b473c99..19c59a522 100644 --- a/rayon-demo/Cargo.toml +++ b/rayon-demo/Cargo.toml @@ -12,7 +12,7 @@ fixedbitset = "0.1.5" glium = "0.20" lazy_static = "1" odds = "0.3" -rand = ">= 0.3, < 0.5" +rand = "0.4" regex = "0.2" serde = "1" serde_derive = "1"