diff --git a/CHANGELOG.md b/CHANGELOG.md index 053bda9a..4b76ba96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,9 +32,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - A `--discard-baseline` flag for discarding rather than saving benchmark results. - Formal support for benchmarking code compiled to web-assembly. - A `--quiet` flag for printing just a single line per benchmark. +- A `Throughput::BytesDecimal` option for measuring throughput in bytes but printing them using + decimal units like kilobytes instead of binary units like kibibytes. ### Fixed -- When using `bench_with_input`, the input parameter will now be passed through `black_box` before +- When using `bench_with_input`, the input parameter will now be passed through `black_box` before passing it to the benchmark. ## [0.3.6] - 2022-07-06 @@ -502,12 +504,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Initial release on Crates.io. -<<<<<<< HEAD -[unreleased]: https://github.com/bheisler/criterion.rs/compare/0.3.4...HEAD -======= - [Unreleased]: https://github.com/bheisler/criterion.rs/compare/0.3.6...HEAD ->>>>>>> master [0.1.1]: https://github.com/bheisler/criterion.rs/compare/0.1.0...0.1.1 [0.1.2]: https://github.com/bheisler/criterion.rs/compare/0.1.1...0.1.2 [0.2.0]: https://github.com/bheisler/criterion.rs/compare/0.1.2...0.2.0 @@ -528,4 +525,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. [0.3.3]: https://github.com/bheisler/criterion.rs/compare/0.3.2...0.3.3 [0.3.4]: https://github.com/bheisler/criterion.rs/compare/0.3.3...0.3.4 [0.3.5]: https://github.com/bheisler/criterion.rs/compare/0.3.4...0.3.5 -[0.3.5]: https://github.com/bheisler/criterion.rs/compare/0.3.5...0.3.6 +[0.3.5]: https://github.com/bheisler/criterion.rs/compare/0.3.5...0.3.6 \ No newline at end of file diff --git a/benches/benchmarks/custom_measurement.rs b/benches/benchmarks/custom_measurement.rs index c685f382..449f9030 100644 --- a/benches/benchmarks/custom_measurement.rs +++ b/benches/benchmarks/custom_measurement.rs @@ -14,7 +14,7 @@ impl ValueFormatter for HalfSecFormatter { fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { match *throughput { - Throughput::Bytes(bytes) => { + Throughput::Bytes(bytes) | Throughput::BytesDecimal(bytes) => { format!("{} b/s/2", (bytes as f64) / (value * 2f64 * 10f64.powi(-9))) } Throughput::Elements(elems) => format!( @@ -39,7 +39,7 @@ impl ValueFormatter for HalfSecFormatter { values: &mut [f64], ) -> &'static str { match *throughput { - Throughput::Bytes(bytes) => { + Throughput::Bytes(bytes) | Throughput::BytesDecimal(bytes) => { for val in values { *val = (bytes as f64) / (*val * 2f64 * 10f64.powi(-9)) } diff --git a/benches/benchmarks/with_inputs.rs b/benches/benchmarks/with_inputs.rs index 8eaaf008..b0b12a89 100644 --- a/benches/benchmarks/with_inputs.rs +++ b/benches/benchmarks/with_inputs.rs @@ -13,6 +13,15 @@ fn from_elem(c: &mut Criterion) { }); } group.finish(); + + let mut group = c.benchmark_group("from_elem_decimal"); + for size in [KB, 2 * KB].iter() { + group.throughput(Throughput::BytesDecimal(*size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| { + b.iter(|| iter::repeat(0u8).take(size).collect::>()); + }); + } + group.finish(); } criterion_group!(benches, from_elem); diff --git a/src/lib.rs b/src/lib.rs index 19ecac92..16e79cc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1207,6 +1207,11 @@ pub enum Throughput { /// an input string or `&[u8]`. Bytes(u64), + /// Equivalent to Bytes, but the value will be reported in terms of + /// kilobytes (1000 bytes) per second instead of kibibytes (1024 bytes) per + /// second, megabytes instead of mibibytes, and gigabytes instead of gibibytes. + BytesDecimal(u64), + /// Measure throughput in terms of elements/second. The value should be the number of elements /// processed by one iteration of the benchmarked code. Typically, this would be the size of a /// collection, but could also be the number of lines of input text or the number of values to diff --git a/src/measurement.rs b/src/measurement.rs index e577dedd..63719753 100644 --- a/src/measurement.rs +++ b/src/measurement.rs @@ -124,6 +124,31 @@ impl DurationFormatter { unit } + fn bytes_per_second_decimal( + &self, + bytes: f64, + typical: f64, + values: &mut [f64], + ) -> &'static str { + let bytes_per_second = bytes * (1e9 / typical); + let (denominator, unit) = if bytes_per_second < 1000.0 { + (1.0, " B/s") + } else if bytes_per_second < 1000.0 * 1000.0 { + (1000.0, "KB/s") + } else if bytes_per_second < 1000.0 * 1000.0 * 1000.0 { + (1000.0 * 1000.0, "MB/s") + } else { + (1000.0 * 1000.0 * 1000.0, "GB/s") + }; + + for val in values { + let bytes_per_second = bytes * (1e9 / *val); + *val = bytes_per_second / denominator; + } + + unit + } + fn elements_per_second(&self, elems: f64, typical: f64, values: &mut [f64]) -> &'static str { let elems_per_second = elems * (1e9 / typical); let (denominator, unit) = if elems_per_second < 1000.0 { @@ -153,6 +178,9 @@ impl ValueFormatter for DurationFormatter { ) -> &'static str { match *throughput { Throughput::Bytes(bytes) => self.bytes_per_second(bytes as f64, typical, values), + Throughput::BytesDecimal(bytes) => { + self.bytes_per_second_decimal(bytes as f64, typical, values) + } Throughput::Elements(elems) => self.elements_per_second(elems as f64, typical, values), } } diff --git a/src/report.rs b/src/report.rs index 485ce4e9..9374c3e5 100644 --- a/src/report.rs +++ b/src/report.rs @@ -173,7 +173,9 @@ impl BenchmarkId { pub fn as_number(&self) -> Option { match self.throughput { - Some(Throughput::Bytes(n)) | Some(Throughput::Elements(n)) => Some(n as f64), + Some(Throughput::Bytes(n)) + | Some(Throughput::Elements(n)) + | Some(Throughput::BytesDecimal(n)) => Some(n as f64), None => self .value_str .as_ref() @@ -184,6 +186,7 @@ impl BenchmarkId { pub fn value_type(&self) -> Option { match self.throughput { Some(Throughput::Bytes(_)) => Some(ValueType::Bytes), + Some(Throughput::BytesDecimal(_)) => Some(ValueType::Bytes), Some(Throughput::Elements(_)) => Some(ValueType::Elements), None => self .value_str