From 551b500f4ecf8567cc0b21f9a50e752727f37666 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Thu, 2 Apr 2020 16:59:06 +0200 Subject: [PATCH] Add benchmarks and stuff --- .gitignore | 1 + .idea/.gitignore | 2 + .idea/benchmarks.iml | 14 ++++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ Cargo.lock | 194 ++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 +++ src/main.rs | 195 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 438 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/benchmarks.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..5c98b42 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/benchmarks.iml b/.idea/benchmarks.iml new file mode 100644 index 0000000..b7b4242 --- /dev/null +++ b/.idea/benchmarks.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..799c48d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..134b735 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,194 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "benchmarks" +version = "0.1.0" +dependencies = [ + "crossbeam-channel", + "rayon", + "termion", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "crossbeam-channel" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" +dependencies = [ + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" + +[[package]] +name = "hermit-abi" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memoffset" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + +[[package]] +name = "rayon" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" +dependencies = [ + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" +dependencies = [ + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +dependencies = [ + "redox_syscall", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "termion" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" +dependencies = [ + "libc", + "numtoa", + "redox_syscall", + "redox_termios", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..53da006 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "benchmarks" +version = "0.1.0" +authors = ["Trivernis "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rayon = "1.3.0" +crossbeam-channel = "0.4.2" +termion = "1.5.5" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..eb58caf --- /dev/null +++ b/src/main.rs @@ -0,0 +1,195 @@ +#![feature(test)] + +extern crate test; + +use rayon::prelude::*; +use std::ops::{Add, Div}; +use std::time::{Duration, Instant}; +use termion::{color, style}; + +const BENCHMARK_ITERATIONS: usize = 1000; + +pub fn main() { + bench_function("Spawn and Stop thread", || { + to_test::start_stop_thread(); + }); + bench_function("MPSC channel", || { + to_test::send_mpsc_channel(); + }); + bench_function("MPMC channel", || { + to_test::send_mpmc_channel(); + }); + bench_function("Multiply to 100", || { + to_test::multiply_to(100); + }); + bench_function("Largest prime", || { + to_test::largest_prime(1000000); + }); + bench_function("Largest prime parallel", || { + to_test::largest_prime_par(1000000); + }) +} + +fn bench_function(name: &str, func: F) { + println!( + "\n{}{}{}{}", + color::Fg(color::LightBlue), + style::Bold, + name, + style::Reset + ); + let (avg_duration, durations) = bench_n_times(BENCHMARK_ITERATIONS, func); + if durations.len() > 10 { + println!("Durations(10):\t {:?}...", &durations[0..10]); + } else { + println!("Durations:\t {:?}", durations); + } + let standard_deviation = (durations.par_iter().sum::().as_nanos() as f64 + / (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(n: usize, func: F) -> (Duration, Vec) { + let mut durations: Vec = Vec::new(); + for _ in 0..n { + let start = Instant::now(); + func(); + durations.push(start.elapsed()); + } + + ( + durations + .par_iter() + .cloned() + .reduce_with(|a, b| a.add(b).div(2)) + .unwrap(), + durations, + ) +} + +mod to_test { + + use crossbeam_channel::unbounded; + use rayon::prelude::*; + use std::sync::mpsc::channel; + use std::thread; + + pub fn start_stop_thread() { + let handle = thread::spawn(|| { + return; + }); + handle.join().unwrap(); + } + + pub fn multiply_to(end: usize) -> f64 { + let mut result = 0f64; + for i in 2..end { + result = (result * i as f64) / (i - 1) as f64; + } + + result + } + + pub fn largest_prime(end: u128) -> u128 { + let mut last_prime = 2; + for i in (2u128..end).step_by(2) { + let mut is_prime = true; + for j in 2..(i as f64).sqrt().ceil() as u128 { + if i % j == 0 { + is_prime = false; + break; + } + } + if is_prime { + last_prime = i; + } + } + + last_prime + } + + pub fn largest_prime_par(end: u128) -> u128 { + (2u128..((end as f64) / 2f64).ceil() as u128) + .into_par_iter() + .filter(|number| { + let num = number * 2; + for i in 2..(num as f64).sqrt().ceil() as u128 { + if num % i == 0 { + return false; + } + } + + true + }) + .max() + .unwrap() + * 2 + } + + pub fn send_mpsc_channel() { + let (rx, tx) = channel::(); + let handle = thread::spawn(move || for _ in tx {}); + for i in 0..1000 { + rx.send(i).unwrap(); + } + std::mem::drop(rx); + handle.join().unwrap(); + } + + pub fn send_mpmc_channel() { + let (rx, tx) = unbounded::(); + let handle = thread::spawn(move || for _ in tx {}); + for i in 0..1000 { + rx.send(i).unwrap(); + } + std::mem::drop(rx); + handle.join().unwrap(); + } +} + +#[cfg(test)] +mod tests { + use super::to_test::*; + use test::Bencher; + + #[bench] + fn bench_start_thread(b: &mut Bencher) { + b.iter(|| start_stop_thread()); + } + + #[bench] + fn bench_mpsc_channel(b: &mut Bencher) { + b.iter(|| send_mpsc_channel()) + } + + #[bench] + fn bench_mpmc_channel(b: &mut Bencher) { + b.iter(|| send_mpmc_channel()) + } + + #[bench] + fn bench_multiply_to_100(b: &mut Bencher) { + b.iter(|| multiply_to(100)); + } + + #[test] + fn test_largest_prime_functions() { + assert_eq!(largest_prime_par(1000), largest_prime(1000)) + } + + #[bench] + fn bench_largest_prime_1000000(b: &mut Bencher) { + b.iter(|| largest_prime(1000000)); + } + + #[bench] + fn bench_largest_prime_1000000_par(b: &mut Bencher) { + b.iter(|| largest_prime_par(1000000)); + } +}