use entropy::rng::{
AesCtr, BsdRandCompat, BsdRandom, ConstantRng, CounterRng, Lcg32,
LinuxLibcRandom, Mt19937, OsRng, Rand48, Rng, SpongeBob, SystemVRand, WindowsDotNetRandom,
WindowsMsvcRand, WindowsVb6Rnd, Xorshift32, Xorshift64,
};
use std::time::Instant;
const BATCH: u64 = 10_000_000; const WARMUP: usize = 3; const MIN_SAMP: usize = 5; const MAX_SAMP: usize = 200; const TARGET_RCI: f64 = 0.05;
fn t_crit(df: usize) -> f64 {
const TABLE: [f64; 31] = [
f64::NAN, 12.706,
4.303,
3.182,
2.776,
2.571, 2.447,
2.365,
2.306,
2.262,
2.228, 2.201,
2.179,
2.160,
2.145,
2.131, 2.120,
2.110,
2.101,
2.093,
2.086, 2.080,
2.074,
2.069,
2.064,
2.060, 2.056,
2.052,
2.048,
2.045,
2.042, ];
if df <= 30 {
TABLE[df]
} else {
1.960
}
}
fn bench<R: Rng>(name: &str, mut rng: R) {
for _ in 0..WARMUP {
let mut acc = 0u32;
for _ in 0..BATCH {
acc ^= rng.next_u32();
}
std::hint::black_box(acc);
}
let mut samples: Vec<f64> = Vec::with_capacity(32);
loop {
let t0 = Instant::now();
let mut acc = 0u32;
for _ in 0..BATCH {
acc ^= rng.next_u32();
}
std::hint::black_box(acc);
let elapsed = t0.elapsed().as_secs_f64();
let mw_s = BATCH as f64 / elapsed / 1_000_000.0;
samples.push(mw_s);
let n = samples.len();
if n < MIN_SAMP {
continue;
}
let mean = samples.iter().sum::<f64>() / n as f64;
let var = samples.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (n - 1) as f64;
let se = (var / n as f64).sqrt();
let half = t_crit(n - 1) * se;
if half / mean <= TARGET_RCI || n >= MAX_SAMP {
let pct = 100.0 * half / mean;
println!(
" {name:<36} {mean:>7.1} ± {pct:.1}% MW/s [{:>7.1}..{:>7.1}] MB/s n={n}",
(mean - half) * 4.0,
(mean + half) * 4.0,
);
return;
}
if n >= MAX_SAMP {
break;
}
}
}
fn main() {
println!("\n RNG throughput (10 M words/batch, 95% CI ≤5% or n=200)\n");
println!(
" {:<36} {:>16} {:>24} n",
"Generator", "mean ± rCI", "95% CI [lo..hi] MB/s"
);
println!(" {}", "-".repeat(90));
bench("OsRng (/dev/urandom)", OsRng::new());
bench("MT19937 (seed=19650218)", Mt19937::new(19650218));
bench("Xorshift64 (seed=1)", Xorshift64::new(1));
bench("Xorshift32 (seed=1)", Xorshift32::new(1));
bench("BAD Unix System V rand() (seed=1)", SystemVRand::new(1));
bench("BAD Unix System V mrand48() (seed=1)", Rand48::new(1));
bench("BAD Unix BSD random() TYPE_3 (seed=1)", BsdRandom::new(1));
bench(
"BAD Unix Linux glibc rand()/random() (seed=1)",
LinuxLibcRandom::new(1),
);
bench(
"BAD Unix FreeBSD12 rand_r() compat (seed=1)",
BsdRandCompat::new(1),
);
bench("BAD Windows CRT rand() (seed=1)", WindowsMsvcRand::new(1));
bench("BAD Windows VB6/VBA Rnd() (seed=1)", WindowsVb6Rnd::new(1));
bench(
"BAD Windows .NET Random(seed=1) compat",
WindowsDotNetRandom::new(1),
);
bench("ANSI C sample LCG (seed=1)", Lcg32::ansi_c());
bench("LCG MINSTD (seed=1)", Lcg32::minstd());
bench("AES-128-CTR (NIST key)", AesCtr::with_nist_key());
bench(
"SpongeBob (SHA3-512 chain, seed=00..3f)",
SpongeBob::with_test_seed(),
);
bench("Constant (0xDEAD_DEAD)", ConstantRng::new(0xDEAD_DEAD));
bench("Counter (0,1,2,…)", CounterRng::new(0));
println!();
}