|
| 1 | +// Copyright 2018-2021 Developers of the Rand project. |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 4 | +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 5 | +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
| 6 | +// option. This file may not be copied, modified, or distributed |
| 7 | +// except according to those terms. |
| 8 | + |
| 9 | +#![feature(custom_inner_attributes)] |
| 10 | + |
| 11 | +// Rustfmt splits macro invocations to shorten lines; in this case longer-lines are more readable |
| 12 | +#![rustfmt::skip] |
| 13 | + |
| 14 | +const RAND_BENCH_N: u64 = 1000; |
| 15 | + |
| 16 | +use criterion::{criterion_group, criterion_main, Criterion, |
| 17 | + Throughput}; |
| 18 | +use criterion_cycles_per_byte::CyclesPerByte; |
| 19 | + |
| 20 | +use core::mem::size_of; |
| 21 | + |
| 22 | +use rand::prelude::*; |
| 23 | +use rand_distr::*; |
| 24 | + |
| 25 | +// At this time, distributions are optimised for 64-bit platforms. |
| 26 | +use rand_pcg::Pcg64Mcg; |
| 27 | + |
| 28 | +macro_rules! distr_int { |
| 29 | + ($group:ident, $fnn:expr, $ty:ty, $distr:expr) => { |
| 30 | + $group.throughput(Throughput::Bytes( |
| 31 | + size_of::<$ty>() as u64 * RAND_BENCH_N)); |
| 32 | + $group.bench_function($fnn, |c| { |
| 33 | + let mut rng = Pcg64Mcg::from_entropy(); |
| 34 | + let distr = $distr; |
| 35 | + |
| 36 | + c.iter(|| { |
| 37 | + let mut accum: $ty = 0; |
| 38 | + for _ in 0..RAND_BENCH_N { |
| 39 | + let x: $ty = distr.sample(&mut rng); |
| 40 | + accum = accum.wrapping_add(x); |
| 41 | + } |
| 42 | + accum |
| 43 | + }); |
| 44 | + }); |
| 45 | + }; |
| 46 | +} |
| 47 | + |
| 48 | +macro_rules! distr_float { |
| 49 | + ($group:ident, $fnn:expr, $ty:ty, $distr:expr) => { |
| 50 | + $group.throughput(Throughput::Bytes( |
| 51 | + size_of::<$ty>() as u64 * RAND_BENCH_N)); |
| 52 | + $group.bench_function($fnn, |c| { |
| 53 | + let mut rng = Pcg64Mcg::from_entropy(); |
| 54 | + let distr = $distr; |
| 55 | + |
| 56 | + c.iter(|| { |
| 57 | + let mut accum = 0.; |
| 58 | + for _ in 0..RAND_BENCH_N { |
| 59 | + let x: $ty = distr.sample(&mut rng); |
| 60 | + accum += x; |
| 61 | + } |
| 62 | + accum |
| 63 | + }); |
| 64 | + }); |
| 65 | + }; |
| 66 | +} |
| 67 | + |
| 68 | +macro_rules! distr { |
| 69 | + ($group:ident, $fnn:expr, $ty:ty, $distr:expr) => { |
| 70 | + $group.throughput(Throughput::Bytes( |
| 71 | + size_of::<$ty>() as u64 * RAND_BENCH_N)); |
| 72 | + $group.bench_function($fnn, |c| { |
| 73 | + let mut rng = Pcg64Mcg::from_entropy(); |
| 74 | + let distr = $distr; |
| 75 | + |
| 76 | + c.iter(|| { |
| 77 | + let mut accum: u32 = 0; |
| 78 | + for _ in 0..RAND_BENCH_N { |
| 79 | + let x: $ty = distr.sample(&mut rng); |
| 80 | + accum = accum.wrapping_add(x as u32); |
| 81 | + } |
| 82 | + accum |
| 83 | + }); |
| 84 | + }); |
| 85 | + }; |
| 86 | +} |
| 87 | + |
| 88 | +macro_rules! distr_arr { |
| 89 | + ($group:ident, $fnn:expr, $ty:ty, $distr:expr) => { |
| 90 | + $group.throughput(Throughput::Bytes( |
| 91 | + size_of::<$ty>() as u64 * RAND_BENCH_N)); |
| 92 | + $group.bench_function($fnn, |c| { |
| 93 | + let mut rng = Pcg64Mcg::from_entropy(); |
| 94 | + let distr = $distr; |
| 95 | + |
| 96 | + c.iter(|| { |
| 97 | + let mut accum: u32 = 0; |
| 98 | + for _ in 0..RAND_BENCH_N { |
| 99 | + let x: $ty = distr.sample(&mut rng); |
| 100 | + accum = accum.wrapping_add(x[0] as u32); |
| 101 | + } |
| 102 | + accum |
| 103 | + }); |
| 104 | + }); |
| 105 | + }; |
| 106 | +} |
| 107 | + |
| 108 | +macro_rules! sample_binomial { |
| 109 | + ($group:ident, $name:expr, $n:expr, $p:expr) => { |
| 110 | + distr_int!($group, $name, u64, Binomial::new($n, $p).unwrap()) |
| 111 | + }; |
| 112 | +} |
| 113 | + |
| 114 | +fn bench(c: &mut Criterion<CyclesPerByte>) { |
| 115 | + { |
| 116 | + let mut g = c.benchmark_group("exp"); |
| 117 | + distr_float!(g, "exp", f64, Exp::new(1.23 * 4.56).unwrap()); |
| 118 | + distr_float!(g, "exp1_specialized", f64, Exp1); |
| 119 | + distr_float!(g, "exp1_general", f64, Exp::new(1.).unwrap()); |
| 120 | + } |
| 121 | + |
| 122 | + { |
| 123 | + let mut g = c.benchmark_group("normal"); |
| 124 | + distr_float!(g, "normal", f64, Normal::new(-1.23, 4.56).unwrap()); |
| 125 | + distr_float!(g, "standardnormal_specialized", f64, StandardNormal); |
| 126 | + distr_float!(g, "standardnormal_general", f64, Normal::new(0., 1.).unwrap()); |
| 127 | + distr_float!(g, "log_normal", f64, LogNormal::new(-1.23, 4.56).unwrap()); |
| 128 | + g.throughput(Throughput::Bytes(size_of::<f64>() as u64 * RAND_BENCH_N)); |
| 129 | + g.bench_function("iter", |c| { |
| 130 | + let mut rng = Pcg64Mcg::from_entropy(); |
| 131 | + let distr = Normal::new(-2.71828, 3.14159).unwrap(); |
| 132 | + let mut iter = distr.sample_iter(&mut rng); |
| 133 | + |
| 134 | + c.iter(|| { |
| 135 | + let mut accum = 0.0; |
| 136 | + for _ in 0..RAND_BENCH_N { |
| 137 | + accum += iter.next().unwrap(); |
| 138 | + } |
| 139 | + accum |
| 140 | + }); |
| 141 | + }); |
| 142 | + } |
| 143 | + |
| 144 | + { |
| 145 | + let mut g = c.benchmark_group("skew_normal"); |
| 146 | + distr_float!(g, "shape_zero", f64, SkewNormal::new(0.0, 1.0, 0.0).unwrap()); |
| 147 | + distr_float!(g, "shape_positive", f64, SkewNormal::new(0.0, 1.0, 100.0).unwrap()); |
| 148 | + distr_float!(g, "shape_negative", f64, SkewNormal::new(0.0, 1.0, -100.0).unwrap()); |
| 149 | + } |
| 150 | + |
| 151 | + { |
| 152 | + let mut g = c.benchmark_group("gamma"); |
| 153 | + distr_float!(g, "gamma_large_shape", f64, Gamma::new(10., 1.0).unwrap()); |
| 154 | + distr_float!(g, "gamma_small_shape", f64, Gamma::new(0.1, 1.0).unwrap()); |
| 155 | + distr_float!(g, "beta_small_param", f64, Beta::new(0.1, 0.1).unwrap()); |
| 156 | + distr_float!(g, "beta_large_param_similar", f64, Beta::new(101., 95.).unwrap()); |
| 157 | + distr_float!(g, "beta_large_param_different", f64, Beta::new(10., 1000.).unwrap()); |
| 158 | + distr_float!(g, "beta_mixed_param", f64, Beta::new(0.5, 100.).unwrap()); |
| 159 | + } |
| 160 | + |
| 161 | + { |
| 162 | + let mut g = c.benchmark_group("cauchy"); |
| 163 | + distr_float!(g, "cauchy", f64, Cauchy::new(4.2, 6.9).unwrap()); |
| 164 | + } |
| 165 | + |
| 166 | + { |
| 167 | + let mut g = c.benchmark_group("triangular"); |
| 168 | + distr_float!(g, "triangular", f64, Triangular::new(0., 1., 0.9).unwrap()); |
| 169 | + } |
| 170 | + |
| 171 | + { |
| 172 | + let mut g = c.benchmark_group("geometric"); |
| 173 | + distr_int!(g, "geometric", u64, Geometric::new(0.5).unwrap()); |
| 174 | + distr_int!(g, "standard_geometric", u64, StandardGeometric); |
| 175 | + } |
| 176 | + |
| 177 | + { |
| 178 | + let mut g = c.benchmark_group("weighted"); |
| 179 | + distr_int!(g, "weighted_i8", usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap()); |
| 180 | + distr_int!(g, "weighted_u32", usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap()); |
| 181 | + distr_int!(g, "weighted_f64", usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap()); |
| 182 | + distr_int!(g, "weighted_large_set", usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap()); |
| 183 | + distr_int!(g, "weighted_alias_method_i8", usize, WeightedAliasIndex::new(vec![1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap()); |
| 184 | + distr_int!(g, "weighted_alias_method_u32", usize, WeightedAliasIndex::new(vec![1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap()); |
| 185 | + distr_int!(g, "weighted_alias_method_f64", usize, WeightedAliasIndex::new(vec![1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap()); |
| 186 | + distr_int!(g, "weighted_alias_method_large_set", usize, WeightedAliasIndex::new((0..10000).rev().chain(1..10001).collect()).unwrap()); |
| 187 | + } |
| 188 | + |
| 189 | + { |
| 190 | + let mut g = c.benchmark_group("binomial"); |
| 191 | + sample_binomial!(g, "binomial", 20, 0.7); |
| 192 | + sample_binomial!(g, "binomial_small", 1_000_000, 1e-30); |
| 193 | + sample_binomial!(g, "binomial_1", 1, 0.9); |
| 194 | + sample_binomial!(g, "binomial_10", 10, 0.9); |
| 195 | + sample_binomial!(g, "binomial_100", 100, 0.99); |
| 196 | + sample_binomial!(g, "binomial_1000", 1000, 0.01); |
| 197 | + sample_binomial!(g, "binomial_1e12", 1000_000_000_000, 0.2); |
| 198 | + } |
| 199 | + |
| 200 | + { |
| 201 | + let mut g = c.benchmark_group("poisson"); |
| 202 | + distr_float!(g, "poisson", f64, Poisson::new(4.0).unwrap()); |
| 203 | + } |
| 204 | + |
| 205 | + { |
| 206 | + let mut g = c.benchmark_group("zipf"); |
| 207 | + distr_float!(g, "zipf", f64, Zipf::new(10, 1.5).unwrap()); |
| 208 | + distr_float!(g, "zeta", f64, Zeta::new(1.5).unwrap()); |
| 209 | + } |
| 210 | + |
| 211 | + { |
| 212 | + let mut g = c.benchmark_group("bernoulli"); |
| 213 | + distr!(g, "bernoulli", bool, Bernoulli::new(0.18).unwrap()); |
| 214 | + } |
| 215 | + |
| 216 | + { |
| 217 | + let mut g = c.benchmark_group("circle"); |
| 218 | + distr_arr!(g, "circle", [f64; 2], UnitCircle); |
| 219 | + } |
| 220 | + |
| 221 | + { |
| 222 | + let mut g = c.benchmark_group("sphere"); |
| 223 | + distr_arr!(g, "sphere", [f64; 3], UnitSphere); |
| 224 | + } |
| 225 | +} |
| 226 | + |
| 227 | +criterion_group!( |
| 228 | + name = benches; |
| 229 | + config = Criterion::default().with_measurement(CyclesPerByte); |
| 230 | + targets = bench |
| 231 | +); |
| 232 | +criterion_main!(benches); |
0 commit comments