aboutsummaryrefslogtreecommitdiff
path: root/benches
diff options
context:
space:
mode:
authorJakub Kotur <qtr@google.com>2020-12-21 17:28:14 +0100
committerJakub Kotur <qtr@google.com>2021-03-05 15:05:06 +0100
commit704f579139cd14c990899a887026adce4b6fb0ac (patch)
tree8ab32923fe4a5e70e694e6147ea7f6783bc1b04b /benches
parent71f53f93f889decb4b2faafb4eaea7b0e9c70722 (diff)
downloadcriterion-704f579139cd14c990899a887026adce4b6fb0ac.tar.gz
Initial import of criterion-0.3.3.
Bug: 155309706 Change-Id: I8d6ee6f1995361f33b3b63527d1236f13de1ab0c
Diffstat (limited to 'benches')
-rwxr-xr-xbenches/bench_main.rs16
-rwxr-xr-xbenches/benchmarks/compare_functions.rs83
-rwxr-xr-xbenches/benchmarks/custom_measurement.rs118
-rwxr-xr-xbenches/benchmarks/external_process.py36
-rwxr-xr-xbenches/benchmarks/external_process.rs58
-rwxr-xr-xbenches/benchmarks/iter_with_large_drop.rs34
-rwxr-xr-xbenches/benchmarks/iter_with_large_setup.rs38
-rwxr-xr-xbenches/benchmarks/iter_with_setup.rs14
-rwxr-xr-xbenches/benchmarks/measurement_overhead.rs32
-rwxr-xr-xbenches/benchmarks/mod.rs10
-rwxr-xr-xbenches/benchmarks/sampling_mode.rs26
-rwxr-xr-xbenches/benchmarks/special_characters.rs9
-rwxr-xr-xbenches/benchmarks/with_inputs.rs18
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);