diff --git a/CHANGELOG.md b/CHANGELOG.md index a5c0540..adb2b23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - ## [Unreleased] - ReleaseDate +### Added +### Changed +### Fixed + +## [0.3.0] - 2023-06-12 + +### Added + +- `max_iterations` overriding argument to set a hard maximum of iterations. + +### Fixed + +- Update for new lints and a reformat pass. ## [0.2.0] - 2022-10-07 diff --git a/tiny-bench/Cargo.toml b/tiny-bench/Cargo.toml index 471eafa..ca56f6f 100644 --- a/tiny-bench/Cargo.toml +++ b/tiny-bench/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-bench" -version = "0.2.0" +version = "0.3.0" edition = "2021" authors = ["Embark "] license = "MIT OR Apache-2.0" diff --git a/tiny-bench/benches/benchmark.rs b/tiny-bench/benches/benchmark.rs index c73b5dc..3d1d23a 100644 --- a/tiny-bench/benches/benchmark.rs +++ b/tiny-bench/benches/benchmark.rs @@ -1,10 +1,11 @@ use std::time::Duration; -use tiny_bench::black_box; +use tiny_bench::{black_box, BenchmarkConfig}; fn main() { bench_test_one(); bench_test_two(); bench_test_three(); + bench_test_four(); } fn bench_test_one() { @@ -45,3 +46,14 @@ fn bench_test_two() { fn bench_test_three() { tiny_bench::bench_labeled("test three, empty", || {}); } + +fn bench_test_four() { + tiny_bench::bench_with_configuration_labeled( + "test four, max_it", + &BenchmarkConfig { + max_iterations: Some(5000), + ..BenchmarkConfig::default() + }, + || {}, + ); +} diff --git a/tiny-bench/src/benching/mod.rs b/tiny-bench/src/benching/mod.rs index 82c79e1..0ef6744 100644 --- a/tiny-bench/src/benching/mod.rs +++ b/tiny-bench/src/benching/mod.rs @@ -67,11 +67,9 @@ pub fn bench_with_configuration_labeled T>( let wu = run_warm_up(&mut closure, cfg.warm_up_time); let mean_execution_time = wu.elapsed.as_nanos() as f64 / wu.iterations as f64; let sample_size = cfg.num_samples as u64; - let iters = calculate_iterations(mean_execution_time, sample_size, cfg.measurement_time); - let mut total_iters = 0u128; - for count in iters.iter().copied() { - total_iters = total_iters.saturating_add(u128::from(count)); - } + let (iters, total_iters) = + calculate_iters_and_total_iters(cfg, mean_execution_time, sample_size); + println!( "{} mean warm up execution time {} running {} iterations", wrap_bold_green(label), @@ -86,6 +84,23 @@ pub fn bench_with_configuration_labeled T>( } } +fn calculate_iters_and_total_iters( + cfg: &BenchmarkConfig, + mean_execution_time: f64, + sample_size: u64, +) -> (Vec, u128) { + if let Some(max_it) = cfg.max_iterations { + (vec![max_it], u128::from(max_it)) + } else { + let iters = calculate_iterations(mean_execution_time, sample_size, cfg.measurement_time); + let mut total_iters = 0u128; + for count in iters.iter().copied() { + total_iters = total_iters.saturating_add(u128::from(count)); + } + (iters, total_iters) + } +} + fn run T>(sample_sizes: Vec, mut closure: F) -> SamplingData { let times = sample_sizes .iter() @@ -181,11 +196,9 @@ pub fn bench_with_setup_configuration_labeled T, S: FnMut() let mean_execution_time = wu.elapsed.as_nanos() as f64 / wu.iterations as f64; let sample_size = cfg.num_samples as u64; - let iters = calculate_iterations(mean_execution_time, sample_size, cfg.measurement_time); - let mut total_iters = 0u128; - for count in iters.iter().copied() { - total_iters = total_iters.saturating_add(u128::from(count)); - } + + let (iters, total_iters) = + calculate_iters_and_total_iters(cfg, mean_execution_time, sample_size); println!( "{} mean warm up execution time {} running {} iterations", wrap_bold_green(label), diff --git a/tiny-bench/src/output/analysis/criterion/mod.rs b/tiny-bench/src/output/analysis/criterion/mod.rs index 5e8e737..46b7c83 100644 --- a/tiny-bench/src/output/analysis/criterion/mod.rs +++ b/tiny-bench/src/output/analysis/criterion/mod.rs @@ -42,6 +42,11 @@ pub struct BenchmarkConfig { /// Puts results in target/tiny-bench/label/.. if target can be found. /// used for comparing previous runs pub dump_results_to_disk: bool, + + /// Sets a hard ceiling on max iterations, overriding the heuristic calculations for iteration + /// count. A rule of thumb; if this is used, the results are unlikely to be statistically + /// significant. + pub max_iterations: Option, } impl Default for BenchmarkConfig { @@ -52,6 +57,7 @@ impl Default for BenchmarkConfig { num_samples: 100, warm_up_time: Duration::from_secs(3), dump_results_to_disk: true, + max_iterations: None, } } } @@ -73,8 +79,7 @@ pub(crate) fn calculate_iterations( println!( "{} You may wish to increase target time to {:.1?} or lower the requested number of samples", wrap_yellow(&format!( - "Unable to complete {} samples in {:.1?}", - num_samples, target_time + "Unable to complete {num_samples} samples in {target_time:.1?}" )), actual_time ); diff --git a/tiny-bench/src/output/disk.rs b/tiny-bench/src/output/disk.rs index f563050..9a96951 100644 --- a/tiny-bench/src/output/disk.rs +++ b/tiny-bench/src/output/disk.rs @@ -73,8 +73,7 @@ fn try_write( let parent_dir = find_or_create_result_parent_dir(label)?; std::fs::create_dir_all(&parent_dir).map_err(|e| { Error::new(format!( - "Failed to create output directory {:?}, cause {e}, will not write results", - parent_dir + "Failed to create output directory {parent_dir:?}, cause {e}, will not write results" )) })?; @@ -83,17 +82,14 @@ fn try_write( let old_file = parent_dir.join(old_file_name); if let Err(e) = std::fs::rename(&latest_persisted, &old_file) { println!( - "{} from {:?} to {:?}, cause {e}, will try to overwrite.", - wrap_yellow("Failed to move old sample"), - latest_persisted, - old_file + "{} from {latest_persisted:?} to {old_file:?}, cause {e}, will try to overwrite.", + wrap_yellow("Failed to move old sample") ); } } std::fs::write(&latest_persisted, data).map_err(|e| { Error::new(format!( - "Failed to write benchmark-data to {:?}, cause {e}", - latest_persisted + "Failed to write benchmark-data to {latest_persisted:?}, cause {e}" )) }) } @@ -111,8 +107,7 @@ fn try_read(label: &'static str, current_file_name: &'static str) -> Result match e.kind() { ErrorKind::NotFound => Ok(None), _ => Err(Error::new(format!( - "Failed to read file at {:?}, cause: {e}", - latest_persisted_path + "Failed to read file at {latest_persisted_path:?}, cause: {e}" ))), }, } @@ -133,8 +128,7 @@ fn find_or_create_result_parent_dir(label: &'static str) -> Result { let pb = PathBuf::from(&target); let target_buf = std::fs::metadata(&pb).map_err(|e| { Error::new(format!( - "Failed to check metadata for target dir {:?}, cause {e}", - target + "Failed to check metadata for target dir {target:?}, cause {e}" )) })?; if !target_buf.is_dir() { @@ -148,8 +142,7 @@ fn find_or_create_result_parent_dir(label: &'static str) -> Result { std::fs::create_dir_all(&result_parent_dir).map_err(|e| { Error::new(format!( - "Failed to create output directory {:?}, cause {e}", - result_parent_dir + "Failed to create output directory {result_parent_dir:?}, cause {e}" )) })?; Ok(result_parent_dir) diff --git a/tiny-bench/src/output/mod.rs b/tiny-bench/src/output/mod.rs index a1a8e2f..3721de8 100644 --- a/tiny-bench/src/output/mod.rs +++ b/tiny-bench/src/output/mod.rs @@ -310,7 +310,7 @@ pub(crate) fn wrap_high_intensity_white(text: &str) -> String { pub(crate) fn fmt_time(time: f64) -> String { // Nanos if time < NANO_LIMIT { - format!("{:.2}ns", time) + format!("{time:.2}ns") } else if time < MICRO_LIMIT { format!("{:.2}µs", time / NANO_LIMIT) } else if time < MILLI_LIMIT { @@ -321,12 +321,12 @@ pub(crate) fn fmt_time(time: f64) -> String { } fn fmt_change(change: f64) -> String { - format!("{:.4}%", change) + format!("{change:.4}%") } pub(crate) fn fmt_num(num: f64) -> String { if num < NANO_LIMIT { - format!("{:.1}", num) + format!("{num:.1}") } else if num < MICRO_LIMIT { format!("{:.1} thousand", num / NANO_LIMIT) } else if num < MILLI_LIMIT {