Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ThreadRng performance bug #43120

Closed
SharplEr opened this issue Jul 8, 2017 · 3 comments
Closed

ThreadRng performance bug #43120

SharplEr opened this issue Jul 8, 2017 · 3 comments

Comments

@SharplEr
Copy link

SharplEr commented Jul 8, 2017

ThreadRng works 5 times slower than ThreadLocalRandom in Java.

I run this benchmark in Rust:

#[bench]
fn bench_rnd(b: &mut Bencher) {
    b.iter(|| rand::thread_rng().gen_range::<f64>(2.0, 100.0));
}

On my laptop the result is:
test tests::bench_rnd ... bench: 49 ns/iter (+/- 1)

But if I run the same benchmark on JHM:

@Benchmark
public double testRnd() {
    return ThreadLocalRandom.current().nextDouble(2, 100);
}

On my laptop the result is:
Benchmark Mode Cnt Score Error Units
Main.testRnd avgt 20 9,018 ± 0,094 ns/op

So the difference is 5.44 times looks like performance bug.

Meta

Rust:

rbose
rustc 1.20.0-nightly (c9bb935 2017-06-24)
binary: rustc
commit-hash: c9bb935
commit-date: 2017-06-24
host: x86_64-unknown-linux-gnu
release: 1.20.0-nightly
LLVM version: 4.0

Java:
OpenJDK 1.8.131

@retep998
Copy link
Member

retep998 commented Jul 8, 2017

Since rand is an external crate with its own repository, this issue probably belongs there, unless you're able to somehow demonstrate that this is Rust's fault, and not rand's fault.

However, the question you should really be asking, is what kind of random numbers are you getting? rand::ThreadRng is a cryptographically secure RNG, so it's going to be at an inherent performance disadvantage to RNGs that don't have to be as secure. Looking at the documentation... "Instances of ThreadLocalRandom are not cryptographically secure. " which means you're not even doing a fair comparison.

Running your benchmark as written is 21ns/iter for me.

Modifying your benchmark to cache the result of thread_rng() speeds it up 15 ns/iter for me.

#[bench]
fn bench_rnd(b: &mut Bencher) {
    let mut rng = rand::thread_rng();
    b.iter(|| rng.gen_range::<f64>(2.0, 100.0));
}

If I use weak_rng() however and throw out cryptographic security, it races ahead to 3 ns/iter.

#[bench]
fn bench_rnd(b: &mut Bencher) {
    let mut rng = rand::weak_rng();
    b.iter(|| rng.gen_range::<f64>(2.0, 100.0));
}

@kennytm
Copy link
Member

kennytm commented Jul 8, 2017

Also note that Java's ThreadLocalRandom is an extremely simple linear congruential PRNG, while Rust's rand's thread_rng() is based on the ISAAC (claimed-to-be) cryptographically secure PRNG which is more expensive, so this benchmark is not an exactly apple-to-apple comparison.

@SharplEr
Copy link
Author

SharplEr commented Jul 8, 2017

Thank you a lot for the explanation.

@SharplEr SharplEr closed this as completed Jul 8, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants