diff options
author | Jakub Kotur <qtr@google.com> | 2020-12-21 17:28:14 +0100 |
---|---|---|
committer | Jakub Kotur <qtr@google.com> | 2021-03-05 15:05:06 +0100 |
commit | 704f579139cd14c990899a887026adce4b6fb0ac (patch) | |
tree | 8ab32923fe4a5e70e694e6147ea7f6783bc1b04b /benches | |
parent | 71f53f93f889decb4b2faafb4eaea7b0e9c70722 (diff) | |
download | criterion-704f579139cd14c990899a887026adce4b6fb0ac.tar.gz |
Initial import of criterion-0.3.3.
Bug: 155309706
Change-Id: I8d6ee6f1995361f33b3b63527d1236f13de1ab0c
Diffstat (limited to 'benches')
-rwxr-xr-x | benches/bench_main.rs | 16 | ||||
-rwxr-xr-x | benches/benchmarks/compare_functions.rs | 83 | ||||
-rwxr-xr-x | benches/benchmarks/custom_measurement.rs | 118 | ||||
-rwxr-xr-x | benches/benchmarks/external_process.py | 36 | ||||
-rwxr-xr-x | benches/benchmarks/external_process.rs | 58 | ||||
-rwxr-xr-x | benches/benchmarks/iter_with_large_drop.rs | 34 | ||||
-rwxr-xr-x | benches/benchmarks/iter_with_large_setup.rs | 38 | ||||
-rwxr-xr-x | benches/benchmarks/iter_with_setup.rs | 14 | ||||
-rwxr-xr-x | benches/benchmarks/measurement_overhead.rs | 32 | ||||
-rwxr-xr-x | benches/benchmarks/mod.rs | 10 | ||||
-rwxr-xr-x | benches/benchmarks/sampling_mode.rs | 26 | ||||
-rwxr-xr-x | benches/benchmarks/special_characters.rs | 9 | ||||
-rwxr-xr-x | benches/benchmarks/with_inputs.rs | 18 |
13 files changed, 492 insertions, 0 deletions
diff --git a/benches/bench_main.rs b/benches/bench_main.rs new file mode 100755 index 0000000..3d9859b --- /dev/null +++ b/benches/bench_main.rs @@ -0,0 +1,16 @@ +use criterion::criterion_main; + +mod benchmarks; + +criterion_main! { + benchmarks::compare_functions::fibonaccis, + benchmarks::external_process::benches, + benchmarks::iter_with_large_drop::benches, + benchmarks::iter_with_large_setup::benches, + benchmarks::iter_with_setup::benches, + benchmarks::with_inputs::benches, + benchmarks::special_characters::benches, + benchmarks::measurement_overhead::benches, + benchmarks::custom_measurement::benches, + benchmarks::sampling_mode::benches, +} diff --git a/benches/benchmarks/compare_functions.rs b/benches/benchmarks/compare_functions.rs new file mode 100755 index 0000000..b3db640 --- /dev/null +++ b/benches/benchmarks/compare_functions.rs @@ -0,0 +1,83 @@ +use criterion::{criterion_group, BenchmarkId, Criterion, Fun, ParameterizedBenchmark}; + +fn fibonacci_slow(n: u64) -> u64 { + match n { + 0 | 1 => 1, + n => fibonacci_slow(n - 1) + fibonacci_slow(n - 2), + } +} + +fn fibonacci_fast(n: u64) -> u64 { + let mut a = 0; + let mut b = 1; + + match n { + 0 => b, + _ => { + for _ in 0..n { + let c = a + b; + a = b; + b = c; + } + b + } + } +} + +fn compare_fibonaccis(c: &mut Criterion) { + let fib_slow = Fun::new("Recursive", |b, i| b.iter(|| fibonacci_slow(*i))); + let fib_fast = Fun::new("Iterative", |b, i| b.iter(|| fibonacci_fast(*i))); + + let functions = vec![fib_slow, fib_fast]; + + c.bench_functions("Fibonacci", functions, 20); +} +fn compare_fibonaccis_builder(c: &mut Criterion) { + c.bench( + "Fibonacci2", + ParameterizedBenchmark::new( + "Recursive", + |b, i| b.iter(|| fibonacci_slow(*i)), + vec![20u64, 21u64], + ) + .with_function("Iterative", |b, i| b.iter(|| fibonacci_fast(*i))), + ); +} +fn compare_fibonaccis_group(c: &mut Criterion) { + let mut group = c.benchmark_group("Fibonacci3"); + for i in 20..=21 { + group.bench_with_input(BenchmarkId::new("Recursive", i), &i, |b, i| { + b.iter(|| fibonacci_slow(*i)) + }); + group.bench_with_input(BenchmarkId::new("Iterative", i), &i, |b, i| { + b.iter(|| fibonacci_fast(*i)) + }); + } + group.finish() +} + +fn compare_looped(c: &mut Criterion) { + use criterion::black_box; + + c.bench( + "small", + ParameterizedBenchmark::new("unlooped", |b, i| b.iter(|| i + 10), vec![10]).with_function( + "looped", + |b, i| { + b.iter(|| { + for _ in 0..10_000 { + black_box(i + 10); + } + }) + }, + ), + ); +} + +criterion_group!( + fibonaccis, + compare_fibonaccis, + compare_fibonaccis_builder, + compare_fibonaccis_group, + compare_looped +); diff --git a/benches/benchmarks/custom_measurement.rs b/benches/benchmarks/custom_measurement.rs new file mode 100755 index 0000000..c685f38 --- /dev/null +++ b/benches/benchmarks/custom_measurement.rs @@ -0,0 +1,118 @@ +use criterion::{ + black_box, criterion_group, + measurement::{Measurement, ValueFormatter}, + Criterion, Throughput, +}; +use std::time::{Duration, Instant}; + +struct HalfSecFormatter; +impl ValueFormatter for HalfSecFormatter { + fn format_value(&self, value: f64) -> String { + // The value will be in nanoseconds so we have to convert to half-seconds. + format!("{} s/2", value * 2f64 * 10f64.powi(-9)) + } + + fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { + match *throughput { + Throughput::Bytes(bytes) => { + format!("{} b/s/2", (bytes as f64) / (value * 2f64 * 10f64.powi(-9))) + } + Throughput::Elements(elems) => format!( + "{} elem/s/2", + (elems as f64) / (value * 2f64 * 10f64.powi(-9)) + ), + } + } + + fn scale_values(&self, _typical: f64, values: &mut [f64]) -> &'static str { + for val in values { + *val *= 2f64 * 10f64.powi(-9); + } + + "s/2" + } + + fn scale_throughputs( + &self, + _typical: f64, + throughput: &Throughput, + values: &mut [f64], + ) -> &'static str { + match *throughput { + Throughput::Bytes(bytes) => { + for val in values { + *val = (bytes as f64) / (*val * 2f64 * 10f64.powi(-9)) + } + + "b/s/2" + } + Throughput::Elements(elems) => { + for val in values { + *val = (elems as f64) / (*val * 2f64 * 10f64.powi(-9)) + } + + "elem/s/2" + } + } + } + + fn scale_for_machines(&self, values: &mut [f64]) -> &'static str { + for val in values { + *val *= 2f64 * 10f64.powi(-9); + } + + "s/2" + } +} + +const NANOS_PER_SEC: u64 = 1_000_000_000; + +/// Silly "measurement" that is really just wall-clock time reported in half-seconds. +struct HalfSeconds; +impl Measurement for HalfSeconds { + type Intermediate = Instant; + type Value = Duration; + + fn start(&self) -> Self::Intermediate { + Instant::now() + } + fn end(&self, i: Self::Intermediate) -> Self::Value { + i.elapsed() + } + fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value { + *v1 + *v2 + } + fn zero(&self) -> Self::Value { + Duration::from_secs(0) + } + fn to_f64(&self, val: &Self::Value) -> f64 { + let nanos = val.as_secs() * NANOS_PER_SEC + u64::from(val.subsec_nanos()); + nanos as f64 + } + fn formatter(&self) -> &dyn ValueFormatter { + &HalfSecFormatter + } +} + +fn fibonacci_slow(n: u64) -> u64 { + match n { + 0 | 1 => 1, + n => fibonacci_slow(n - 1) + fibonacci_slow(n - 2), + } +} + +fn fibonacci_cycles(criterion: &mut Criterion<HalfSeconds>) { + criterion.bench_function("fibonacci_custom_measurement", |bencher| { + bencher.iter(|| fibonacci_slow(black_box(10))) + }); +} + +fn alternate_measurement() -> Criterion<HalfSeconds> { + Criterion::default().with_measurement(HalfSeconds) +} + +criterion_group! { + name = benches; + config = alternate_measurement(); + targets = fibonacci_cycles +} diff --git a/benches/benchmarks/external_process.py b/benches/benchmarks/external_process.py new file mode 100755 index 0000000..376c475 --- /dev/null +++ b/benches/benchmarks/external_process.py @@ -0,0 +1,36 @@ +import time +import sys + + +def fibonacci(n): + if n == 0 or n == 1: + return 1 + return fibonacci(n - 1) + fibonacci(n - 2) + + +MILLIS = 1000 +MICROS = MILLIS * 1000 +NANOS = MICROS * 1000 + + +def benchmark(): + depth = int(sys.argv[1]) + for line in sys.stdin: + iters = int(line.strip()) + + # Setup + + start = time.perf_counter() + for x in range(iters): + fibonacci(depth) + end = time.perf_counter() + + # Teardown + + delta = end - start + nanos = int(delta * NANOS) + print("%d" % nanos) + sys.stdout.flush() + + +benchmark() diff --git a/benches/benchmarks/external_process.rs b/benches/benchmarks/external_process.rs new file mode 100755 index 0000000..c823df5 --- /dev/null +++ b/benches/benchmarks/external_process.rs @@ -0,0 +1,58 @@ +use criterion::{criterion_group, Criterion}; +use std::{ + io::{BufRead, BufReader, Write}, + process::{Command, Stdio}, + str::FromStr, + time::Duration, +}; + +fn create_command() -> Command { + let mut command = Command::new("python3"); + command + .arg("benches/benchmarks/external_process.py") + .arg("10"); + command +} + +#[allow(deprecated)] +fn python_fibonacci(c: &mut Criterion) { + let has_python3 = Command::new("python3") + .arg("--version") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .output() + .is_ok(); + + if has_python3 { + let process = create_command() + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .expect("Unable to start python process"); + + let mut stdin = process + .stdin + .expect("Unable to get stdin for child process"); + let stdout = process + .stdout + .expect("Unable to get stdout for child process"); + let mut stdout = BufReader::new(stdout); + c.bench_function("fibonacci-python", |b| { + b.iter_custom(|iters| { + writeln!(stdin, "{}", iters) + .expect("Unable to send iteration count to child process"); + let mut line = String::new(); + stdout + .read_line(&mut line) + .expect("Unable to read time from child process"); + let nanoseconds: u64 = + u64::from_str(line.trim()).expect("Unable to parse time from child process"); + Duration::from_nanos(nanoseconds) + }) + }); + + // Ensure that your child process terminates itself gracefully! + } +} + +criterion_group!(benches, python_fibonacci); diff --git a/benches/benchmarks/iter_with_large_drop.rs b/benches/benchmarks/iter_with_large_drop.rs new file mode 100755 index 0000000..11de5db --- /dev/null +++ b/benches/benchmarks/iter_with_large_drop.rs @@ -0,0 +1,34 @@ +use criterion::{criterion_group, Benchmark, Criterion, Throughput}; +use std::time::Duration; + +const SIZE: usize = 1024 * 1024; + +fn large_drop(c: &mut Criterion) { + c.bench( + "iter_with_large_drop", + Benchmark::new("large_drop", |b| { + let v: Vec<_> = (0..SIZE).map(|i| i as u8).collect(); + b.iter_with_large_drop(|| v.clone()); + }) + .throughput(Throughput::Bytes(SIZE as u64)), + ); +} + +fn small_drop(c: &mut Criterion) { + c.bench( + "iter_with_large_drop", + Benchmark::new("small_drop", |b| { + b.iter_with_large_drop(|| SIZE); + }), + ); +} + +fn short_warmup() -> Criterion { + Criterion::default().warm_up_time(Duration::new(1, 0)) +} + +criterion_group! { + name = benches; + config = short_warmup(); + targets = large_drop, small_drop +} diff --git a/benches/benchmarks/iter_with_large_setup.rs b/benches/benchmarks/iter_with_large_setup.rs new file mode 100755 index 0000000..9cbf51a --- /dev/null +++ b/benches/benchmarks/iter_with_large_setup.rs @@ -0,0 +1,38 @@ +use criterion::{criterion_group, Benchmark, Criterion, Throughput}; +use std::time::Duration; + +const SIZE: usize = 1024 * 1024; + +fn large_setup(c: &mut Criterion) { + c.bench( + "iter_with_large_setup", + Benchmark::new("large_setup", |b| { + // NOTE: iter_with_large_setup is deprecated. Use iter_batched instead. + b.iter_with_large_setup( + || (0..SIZE).map(|i| i as u8).collect::<Vec<_>>(), + |v| v.clone(), + ) + }) + .throughput(Throughput::Bytes(SIZE as u64)), + ); +} + +fn small_setup(c: &mut Criterion) { + c.bench( + "iter_with_large_setup", + Benchmark::new("small_setup", |b| { + // NOTE: iter_with_large_setup is deprecated. Use iter_batched instead. + b.iter_with_large_setup(|| SIZE, |size| size) + }), + ); +} + +fn short_warmup() -> Criterion { + Criterion::default().warm_up_time(Duration::new(1, 0)) +} + +criterion_group! { + name = benches; + config = short_warmup(); + targets = large_setup, small_setup +} diff --git a/benches/benchmarks/iter_with_setup.rs b/benches/benchmarks/iter_with_setup.rs new file mode 100755 index 0000000..0f87063 --- /dev/null +++ b/benches/benchmarks/iter_with_setup.rs @@ -0,0 +1,14 @@ +use criterion::{criterion_group, Criterion}; + +const SIZE: usize = 1024 * 1024; + +fn setup(c: &mut Criterion) { + c.bench_function("iter_with_setup", |b| { + b.iter_with_setup( + || (0..SIZE).map(|i| i as u8).collect::<Vec<_>>(), + |v| v.clone(), + ) + }); +} + +criterion_group!(benches, setup); diff --git a/benches/benchmarks/measurement_overhead.rs b/benches/benchmarks/measurement_overhead.rs new file mode 100755 index 0000000..15b243d --- /dev/null +++ b/benches/benchmarks/measurement_overhead.rs @@ -0,0 +1,32 @@ +use criterion::{criterion_group, BatchSize, Criterion}; + +fn some_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("overhead"); + group.bench_function("iter", |b| b.iter(|| 1)); + group.bench_function("iter_with_setup", |b| b.iter_with_setup(|| (), |_| 1)); + group.bench_function("iter_with_large_setup", |b| { + b.iter_with_large_setup(|| (), |_| 1) + }); + group.bench_function("iter_with_large_drop", |b| b.iter_with_large_drop(|| 1)); + group.bench_function("iter_batched_small_input", |b| { + b.iter_batched(|| (), |_| 1, BatchSize::SmallInput) + }); + group.bench_function("iter_batched_large_input", |b| { + b.iter_batched(|| (), |_| 1, BatchSize::LargeInput) + }); + group.bench_function("iter_batched_per_iteration", |b| { + b.iter_batched(|| (), |_| 1, BatchSize::PerIteration) + }); + group.bench_function("iter_batched_ref_small_input", |b| { + b.iter_batched_ref(|| (), |_| 1, BatchSize::SmallInput) + }); + group.bench_function("iter_batched_ref_large_input", |b| { + b.iter_batched_ref(|| (), |_| 1, BatchSize::LargeInput) + }); + group.bench_function("iter_batched_ref_per_iteration", |b| { + b.iter_batched_ref(|| (), |_| 1, BatchSize::PerIteration) + }); + group.finish(); +} + +criterion_group!(benches, some_benchmark); diff --git a/benches/benchmarks/mod.rs b/benches/benchmarks/mod.rs new file mode 100755 index 0000000..5ff243f --- /dev/null +++ b/benches/benchmarks/mod.rs @@ -0,0 +1,10 @@ +pub mod compare_functions; +pub mod custom_measurement; +pub mod external_process; +pub mod iter_with_large_drop; +pub mod iter_with_large_setup; +pub mod iter_with_setup; +pub mod measurement_overhead; +pub mod sampling_mode; +pub mod special_characters; +pub mod with_inputs; diff --git a/benches/benchmarks/sampling_mode.rs b/benches/benchmarks/sampling_mode.rs new file mode 100755 index 0000000..af76127 --- /dev/null +++ b/benches/benchmarks/sampling_mode.rs @@ -0,0 +1,26 @@ +use criterion::{criterion_group, Criterion, SamplingMode};
+use std::thread::sleep;
+use std::time::Duration;
+
+fn sampling_mode_tests(c: &mut Criterion) {
+ let mut group = c.benchmark_group("sampling_mode");
+
+ group.sampling_mode(SamplingMode::Auto);
+ group.bench_function("Auto", |bencher| {
+ bencher.iter(|| sleep(Duration::from_millis(0)))
+ });
+
+ group.sampling_mode(SamplingMode::Linear);
+ group.bench_function("Linear", |bencher| {
+ bencher.iter(|| sleep(Duration::from_millis(0)))
+ });
+
+ group.sampling_mode(SamplingMode::Flat);
+ group.bench_function("Flat", |bencher| {
+ bencher.iter(|| sleep(Duration::from_millis(10)))
+ });
+
+ group.finish();
+}
+
+criterion_group!(benches, sampling_mode_tests,);
diff --git a/benches/benchmarks/special_characters.rs b/benches/benchmarks/special_characters.rs new file mode 100755 index 0000000..6140f9a --- /dev/null +++ b/benches/benchmarks/special_characters.rs @@ -0,0 +1,9 @@ +use criterion::{criterion_group, Criterion}; + +fn some_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("\"*group/\""); + group.bench_function("\"*benchmark/\" '", |b| b.iter(|| 1 + 1)); + group.finish(); +} + +criterion_group!(benches, some_benchmark); diff --git a/benches/benchmarks/with_inputs.rs b/benches/benchmarks/with_inputs.rs new file mode 100755 index 0000000..8eaaf00 --- /dev/null +++ b/benches/benchmarks/with_inputs.rs @@ -0,0 +1,18 @@ +use std::iter; + +use criterion::{criterion_group, BenchmarkId, Criterion, Throughput}; + +fn from_elem(c: &mut Criterion) { + static KB: usize = 1024; + + let mut group = c.benchmark_group("from_elem"); + for size in [KB, 2 * KB, 4 * KB, 8 * KB, 16 * KB].iter() { + group.throughput(Throughput::Bytes(*size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| { + b.iter(|| iter::repeat(0u8).take(size).collect::<Vec<_>>()); + }); + } + group.finish(); +} + +criterion_group!(benches, from_elem); |