diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
commit | 837b550238aa671a591ccf282dddeab29cadb206 (patch) | |
tree | 914b6b8862bace72bd3245ca184d374b08d8a672 /vendor/criterion/src/measurement.rs | |
parent | Adding debian version 1.70.0+dfsg2-1. (diff) | |
download | rustc-837b550238aa671a591ccf282dddeab29cadb206.tar.xz rustc-837b550238aa671a591ccf282dddeab29cadb206.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/criterion/src/measurement.rs')
-rwxr-xr-x | vendor/criterion/src/measurement.rs | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/vendor/criterion/src/measurement.rs b/vendor/criterion/src/measurement.rs new file mode 100755 index 000000000..3e1e24c4b --- /dev/null +++ b/vendor/criterion/src/measurement.rs @@ -0,0 +1,212 @@ +//! This module defines a set of traits that can be used to plug different measurements (eg. +//! Unix's Processor Time, CPU or GPU performance counters, etc.) into Criterion.rs. It also +//! includes the [WallTime](struct.WallTime.html) struct which defines the default wall-clock time +//! measurement. + +use crate::format::short; +use crate::DurationExt; +use crate::Throughput; +use std::time::{Duration, Instant}; + +/// Trait providing functions to format measured values to string so that they can be displayed on +/// the command line or in the reports. The functions of this trait take measured values in f64 +/// form; implementors can assume that the values are of the same scale as those produced by the +/// associated [MeasuredValue](trait.MeasuredValue.html) (eg. if your measurement produces values in +/// nanoseconds, the values passed to the formatter will be in nanoseconds). +/// +/// Implementors are encouraged to format the values in a way that is intuitive for humans and +/// uses the SI prefix system. For example, the format used by [WallTime](struct.WallTime.html) +/// can display the value in units ranging from picoseconds to seconds depending on the magnitude +/// of the elapsed time in nanoseconds. +pub trait ValueFormatter { + /// Format the value (with appropriate unit) and return it as a string. + fn format_value(&self, value: f64) -> String { + let mut values = [value]; + let unit = self.scale_values(value, &mut values); + format!("{:>6} {}", short(values[0]), unit) + } + + /// Format the value as a throughput measurement. The value represents the measurement value; + /// the implementor will have to calculate bytes per second, iterations per cycle, etc. + fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { + let mut values = [value]; + let unit = self.scale_throughputs(value, throughput, &mut values); + format!("{:>6} {}", short(values[0]), unit) + } + + /// Scale the given values to some appropriate unit and return the unit string. + /// + /// The given typical value should be used to choose the unit. This function may be called + /// multiple times with different datasets; the typical value will remain the same to ensure + /// that the units remain consistent within a graph. The typical value will not be NaN. + /// Values will not contain NaN as input, and the transformed values must not contain NaN. + fn scale_values(&self, typical_value: f64, values: &mut [f64]) -> &'static str; + + /// Convert the given measured values into throughput numbers based on the given throughput + /// value, scale them to some appropriate unit, and return the unit string. + /// + /// The given typical value should be used to choose the unit. This function may be called + /// multiple times with different datasets; the typical value will remain the same to ensure + /// that the units remain consistent within a graph. The typical value will not be NaN. + /// Values will not contain NaN as input, and the transformed values must not contain NaN. + fn scale_throughputs( + &self, + typical_value: f64, + throughput: &Throughput, + values: &mut [f64], + ) -> &'static str; + + /// Scale the values and return a unit string designed for machines. + /// + /// For example, this is used for the CSV file output. Implementations should modify the given + /// values slice to apply the desired scaling (if any) and return a string representing the unit + /// the modified values are in. + fn scale_for_machines(&self, values: &mut [f64]) -> &'static str; +} + +/// Trait for all types which define something Criterion.rs can measure. The only measurement +/// currently provided is [WallTime](struct.WallTime.html), but third party crates or benchmarks +/// may define more. +/// +/// This trait defines two core methods, `start` and `end`. `start` is called at the beginning of +/// a measurement to produce some intermediate value (for example, the wall-clock time at the start +/// of that set of iterations) and `end` is called at the end of the measurement with the value +/// returned by `start`. +/// +pub trait Measurement { + /// This type represents an intermediate value for the measurements. It will be produced by the + /// start function and passed to the end function. An example might be the wall-clock time as + /// of the `start` call. + type Intermediate; + + /// This type is the measured value. An example might be the elapsed wall-clock time between the + /// `start` and `end` calls. + type Value; + + /// Criterion.rs will call this before iterating the benchmark. + fn start(&self) -> Self::Intermediate; + + /// Criterion.rs will call this after iterating the benchmark to get the measured value. + fn end(&self, i: Self::Intermediate) -> Self::Value; + + /// Combine two values. Criterion.rs sometimes needs to perform measurements in multiple batches + /// of iterations, so the value from one batch must be added to the sum of the previous batches. + fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value; + + /// Return a "zero" value for the Value type which can be added to another value. + fn zero(&self) -> Self::Value; + + /// Converts the measured value to f64 so that it can be used in statistical analysis. + fn to_f64(&self, value: &Self::Value) -> f64; + + /// Return a trait-object reference to the value formatter for this measurement. + fn formatter(&self) -> &dyn ValueFormatter; +} + +pub(crate) struct DurationFormatter; +impl DurationFormatter { + fn bytes_per_second(&self, bytes: f64, typical: f64, values: &mut [f64]) -> &'static str { + let bytes_per_second = bytes * (1e9 / typical); + let (denominator, unit) = if bytes_per_second < 1024.0 { + (1.0, " B/s") + } else if bytes_per_second < 1024.0 * 1024.0 { + (1024.0, "KiB/s") + } else if bytes_per_second < 1024.0 * 1024.0 * 1024.0 { + (1024.0 * 1024.0, "MiB/s") + } else { + (1024.0 * 1024.0 * 1024.0, "GiB/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 { + (1.0, " elem/s") + } else if elems_per_second < 1000.0 * 1000.0 { + (1000.0, "Kelem/s") + } else if elems_per_second < 1000.0 * 1000.0 * 1000.0 { + (1000.0 * 1000.0, "Melem/s") + } else { + (1000.0 * 1000.0 * 1000.0, "Gelem/s") + }; + + for val in values { + let elems_per_second = elems * (1e9 / *val); + *val = elems_per_second / denominator; + } + + unit + } +} +impl ValueFormatter for DurationFormatter { + fn scale_throughputs( + &self, + typical: f64, + throughput: &Throughput, + values: &mut [f64], + ) -> &'static str { + match *throughput { + Throughput::Bytes(bytes) => self.bytes_per_second(bytes as f64, typical, values), + Throughput::Elements(elems) => self.elements_per_second(elems as f64, typical, values), + } + } + + fn scale_values(&self, ns: f64, values: &mut [f64]) -> &'static str { + let (factor, unit) = if ns < 10f64.powi(0) { + (10f64.powi(3), "ps") + } else if ns < 10f64.powi(3) { + (10f64.powi(0), "ns") + } else if ns < 10f64.powi(6) { + (10f64.powi(-3), "µs") + } else if ns < 10f64.powi(9) { + (10f64.powi(-6), "ms") + } else { + (10f64.powi(-9), "s") + }; + + for val in values { + *val *= factor; + } + + unit + } + + fn scale_for_machines(&self, _values: &mut [f64]) -> &'static str { + // no scaling is needed + "ns" + } +} + +/// `WallTime` is the default measurement in Criterion.rs. It measures the elapsed time from the +/// beginning of a series of iterations to the end. +pub struct WallTime; +impl Measurement for WallTime { + 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 { + val.to_nanos() as f64 + } + fn formatter(&self) -> &dyn ValueFormatter { + &DurationFormatter + } +} |