|
|
@ -1,35 +1,104 @@
|
|
|
|
#![feature(test)]
|
|
|
|
#![feature(test)]
|
|
|
|
|
|
|
|
#![allow(dead_code)]
|
|
|
|
|
|
|
|
|
|
|
|
extern crate test;
|
|
|
|
extern crate test;
|
|
|
|
|
|
|
|
|
|
|
|
use rayon::prelude::*;
|
|
|
|
use rayon::prelude::*;
|
|
|
|
use std::ops::{Add, Div};
|
|
|
|
use std::fmt::{self, Display};
|
|
|
|
use std::time::{Duration, Instant};
|
|
|
|
use std::time::{Duration, Instant};
|
|
|
|
use termion::{color, style};
|
|
|
|
use termion::{color, style};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
|
|
struct BenchVec {
|
|
|
|
|
|
|
|
pub inner: Vec<Duration>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A struct that stores a vector of Durations for benchmarks
|
|
|
|
|
|
|
|
/// and allows some statistical operations on it
|
|
|
|
|
|
|
|
impl BenchVec {
|
|
|
|
|
|
|
|
/// Creates a new empty BenchVec
|
|
|
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
|
|
|
Self { inner: Vec::new() }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a BenchVec from an existing vector of Durations
|
|
|
|
|
|
|
|
pub fn from_vec(vec: &Vec<Duration>) -> Self {
|
|
|
|
|
|
|
|
Self { inner: vec.clone() }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Adds an element to the BenchVec
|
|
|
|
|
|
|
|
pub fn push(&mut self, item: Duration) -> &mut Self {
|
|
|
|
|
|
|
|
self.inner.push(item);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Appends a different BenchVec to this one
|
|
|
|
|
|
|
|
pub fn append(&mut self, other: Self) -> &mut Self {
|
|
|
|
|
|
|
|
self.inner.append(&mut other.inner.clone());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the length of stored elements
|
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
|
|
|
|
self.inner.len()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the sum of all stored elements
|
|
|
|
|
|
|
|
pub fn sum(&self) -> Duration {
|
|
|
|
|
|
|
|
self.inner.par_iter().sum::<Duration>()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the average of all durations
|
|
|
|
|
|
|
|
pub fn average(&self) -> Duration {
|
|
|
|
|
|
|
|
self.sum() / self.inner.len() as u32
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the standard deviation of all durations
|
|
|
|
|
|
|
|
pub fn standard_deviation(&self) -> f64 {
|
|
|
|
|
|
|
|
(self.sum().as_nanos() as f64 / (self.len() as f64 - 1f64)).sqrt()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Display for BenchVec {
|
|
|
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
|
|
|
let avg_duration = self.average();
|
|
|
|
|
|
|
|
let standard_deviation = self.standard_deviation();
|
|
|
|
|
|
|
|
write!(
|
|
|
|
|
|
|
|
f,
|
|
|
|
|
|
|
|
"Average Duration: {:?} (±{:.2}ns ~ {:.1}%)",
|
|
|
|
|
|
|
|
avg_duration,
|
|
|
|
|
|
|
|
standard_deviation,
|
|
|
|
|
|
|
|
(standard_deviation / avg_duration.as_nanos() as f64) * 100f64
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
const BENCHMARK_ITERATIONS: usize = 1000;
|
|
|
|
const BENCHMARK_ITERATIONS: usize = 1000;
|
|
|
|
|
|
|
|
|
|
|
|
pub fn main() {
|
|
|
|
pub fn main() {
|
|
|
|
bench_function("Spawn and Stop thread", || {
|
|
|
|
bench_function("Spawn and Stop thread", || {
|
|
|
|
to_test::start_stop_thread();
|
|
|
|
to_test::start_stop_thread();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
bench_function("MPSC channel", || {
|
|
|
|
bench_function("MPSC channel 1000 u128", || {
|
|
|
|
to_test::send_mpsc_channel();
|
|
|
|
to_test::send_mpsc_channel();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
bench_function("MPMC channel", || {
|
|
|
|
bench_function("MPMC channel 1000 u128", || {
|
|
|
|
to_test::send_mpmc_channel();
|
|
|
|
to_test::send_mpmc_channel();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
bench_function("Multiply to 100", || {
|
|
|
|
bench_function("Multiply to 100", || {
|
|
|
|
to_test::multiply_to(100);
|
|
|
|
to_test::multiply_to(100);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
bench_function("Largest prime", || {
|
|
|
|
bench_function("Largest prime until 10000000", || {
|
|
|
|
to_test::largest_prime(1000000);
|
|
|
|
to_test::largest_prime(10000000);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
bench_function("Largest prime parallel", || {
|
|
|
|
bench_function("Largest prime parallel until 10000000", || {
|
|
|
|
to_test::largest_prime_par(1000000);
|
|
|
|
to_test::largest_prime_par(10000000);
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Benchmarks a closure a specific number of times
|
|
|
|
|
|
|
|
/// and reports the results to the commandline
|
|
|
|
fn bench_function<F: Fn()>(name: &str, func: F) {
|
|
|
|
fn bench_function<F: Fn()>(name: &str, func: F) {
|
|
|
|
println!(
|
|
|
|
println!(
|
|
|
|
"\n{}{}{}{}",
|
|
|
|
"\n{}{}{}{}",
|
|
|
@ -38,39 +107,26 @@ fn bench_function<F: Fn()>(name: &str, func: F) {
|
|
|
|
name,
|
|
|
|
name,
|
|
|
|
style::Reset
|
|
|
|
style::Reset
|
|
|
|
);
|
|
|
|
);
|
|
|
|
let (avg_duration, durations) = bench_n_times(BENCHMARK_ITERATIONS, func);
|
|
|
|
let bench_durations = bench_n_times(BENCHMARK_ITERATIONS, func);
|
|
|
|
if durations.len() > 10 {
|
|
|
|
if bench_durations.len() > 10 {
|
|
|
|
println!("Durations(10):\t {:?}...", &durations[0..10]);
|
|
|
|
println!("Durations(10):\t {:?}...", &bench_durations.inner[0..10]);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
println!("Durations:\t {:?}", durations);
|
|
|
|
println!("Durations:\t {:?}", bench_durations.inner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let standard_deviation = (durations.par_iter().sum::<Duration>().as_nanos() as f64
|
|
|
|
println!("{}", bench_durations);
|
|
|
|
/ (BENCHMARK_ITERATIONS as f64 - 1f64))
|
|
|
|
|
|
|
|
.sqrt();
|
|
|
|
|
|
|
|
println!(
|
|
|
|
|
|
|
|
"Average Duration: {:?} (±{:.2}ns ~ {:.1}%)",
|
|
|
|
|
|
|
|
avg_duration,
|
|
|
|
|
|
|
|
standard_deviation,
|
|
|
|
|
|
|
|
(standard_deviation / avg_duration.as_nanos() as f64) * 100f64
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn bench_n_times<F: Fn()>(n: usize, func: F) -> (Duration, Vec<Duration>) {
|
|
|
|
/// Benchmarks a closure a given number of times and returns the
|
|
|
|
let mut durations: Vec<Duration> = Vec::new();
|
|
|
|
/// average duration as well as all measured durations
|
|
|
|
|
|
|
|
fn bench_n_times<F: Fn()>(n: usize, func: F) -> BenchVec {
|
|
|
|
|
|
|
|
let mut durations = BenchVec::new();
|
|
|
|
for _ in 0..n {
|
|
|
|
for _ in 0..n {
|
|
|
|
let start = Instant::now();
|
|
|
|
let start = Instant::now();
|
|
|
|
func();
|
|
|
|
func();
|
|
|
|
durations.push(start.elapsed());
|
|
|
|
durations.push(start.elapsed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
(
|
|
|
|
durations
|
|
|
|
durations
|
|
|
|
|
|
|
|
.par_iter()
|
|
|
|
|
|
|
|
.cloned()
|
|
|
|
|
|
|
|
.reduce_with(|a, b| a.add(b).div(2))
|
|
|
|
|
|
|
|
.unwrap(),
|
|
|
|
|
|
|
|
durations,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mod to_test {
|
|
|
|
mod to_test {
|
|
|
@ -133,7 +189,7 @@ mod to_test {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn send_mpsc_channel() {
|
|
|
|
pub fn send_mpsc_channel() {
|
|
|
|
let (rx, tx) = channel::<usize>();
|
|
|
|
let (rx, tx) = channel::<u128>();
|
|
|
|
let handle = thread::spawn(move || for _ in tx {});
|
|
|
|
let handle = thread::spawn(move || for _ in tx {});
|
|
|
|
for i in 0..1000 {
|
|
|
|
for i in 0..1000 {
|
|
|
|
rx.send(i).unwrap();
|
|
|
|
rx.send(i).unwrap();
|
|
|
@ -143,7 +199,7 @@ mod to_test {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn send_mpmc_channel() {
|
|
|
|
pub fn send_mpmc_channel() {
|
|
|
|
let (rx, tx) = unbounded::<usize>();
|
|
|
|
let (rx, tx) = unbounded::<u128>();
|
|
|
|
let handle = thread::spawn(move || for _ in tx {});
|
|
|
|
let handle = thread::spawn(move || for _ in tx {});
|
|
|
|
for i in 0..1000 {
|
|
|
|
for i in 0..1000 {
|
|
|
|
rx.send(i).unwrap();
|
|
|
|
rx.send(i).unwrap();
|
|
|
|