mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-11-02 09:01:25 +00:00
Merge pull request #962 from sharkdp/codex/quantity-module-layout
Group units, formatting, and statistics under quantity
This commit is contained in:
20 files changed
+266
-265
No files matched your search
@@ -2,8 +2,6 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::util::units::Second;
|
|
||||||
|
|
||||||
/// Set of values that will be exported.
|
/// Set of values that will be exported.
|
||||||
// NOTE: `serde` is used for JSON serialization, but not for CSV serialization due to the
|
// NOTE: `serde` is used for JSON serialization, but not for CSV serialization due to the
|
||||||
// `parameters` map. Update `src/hyperfine/export/csv.rs` with new fields, as appropriate.
|
// `parameters` map. Update `src/hyperfine/export/csv.rs` with new fields, as appropriate.
|
||||||
@@ -18,29 +16,29 @@ pub struct BenchmarkResult {
|
|||||||
pub command_with_unused_parameters: String,
|
pub command_with_unused_parameters: String,
|
||||||
|
|
||||||
/// The average run time
|
/// The average run time
|
||||||
pub mean: Second,
|
pub mean: f64,
|
||||||
|
|
||||||
/// The standard deviation of all run times. Not available if only one run has been performed
|
/// The standard deviation of all run times. Not available if only one run has been performed
|
||||||
pub stddev: Option<Second>,
|
pub stddev: Option<f64>,
|
||||||
|
|
||||||
/// The median run time
|
/// The median run time
|
||||||
pub median: Second,
|
pub median: f64,
|
||||||
|
|
||||||
/// Time spent in user mode
|
/// Time spent in user mode
|
||||||
pub user: Second,
|
pub user: f64,
|
||||||
|
|
||||||
/// Time spent in kernel mode
|
/// Time spent in kernel mode
|
||||||
pub system: Second,
|
pub system: f64,
|
||||||
|
|
||||||
/// Minimum of all measured times
|
/// Minimum of all measured times
|
||||||
pub min: Second,
|
pub min: f64,
|
||||||
|
|
||||||
/// Maximum of all measured times
|
/// Maximum of all measured times
|
||||||
pub max: Second,
|
pub max: f64,
|
||||||
|
|
||||||
/// All run time measurements
|
/// All run time measurements
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub times: Option<Vec<Second>>,
|
pub times: Option<Vec<f64>>,
|
||||||
|
|
||||||
/// Maximum memory usage of the process, in bytes
|
/// Maximum memory usage of the process, in bytes
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use std::process::ExitStatus;
|
use std::process::ExitStatus;
|
||||||
|
|
||||||
use crate::outlier_detection::modified_zscores;
|
use crate::quantity::statistics::{max, mean, median, min, modified_zscores, standard_deviation};
|
||||||
use crate::quantity::{second, Information, Time};
|
use crate::quantity::{second, Information, Time};
|
||||||
use crate::util::statistics::{max, mean, median, min, standard_deviation};
|
|
||||||
|
|
||||||
/// Performance measurements and exit status from running a single command
|
/// Performance measurements and exit status from running a single command
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ use crate::options::{
|
|||||||
};
|
};
|
||||||
use crate::outlier_detection::OUTLIER_THRESHOLD;
|
use crate::outlier_detection::OUTLIER_THRESHOLD;
|
||||||
use crate::output::console_writeln;
|
use crate::output::console_writeln;
|
||||||
use crate::output::format::{format_duration, format_duration_unit};
|
|
||||||
use crate::output::progress_bar::get_progress_bar;
|
use crate::output::progress_bar::get_progress_bar;
|
||||||
use crate::output::warnings::{OutlierWarningOptions, Warnings};
|
use crate::output::warnings::{OutlierWarningOptions, Warnings};
|
||||||
use crate::parameter::ParameterNameAndValue;
|
use crate::parameter::ParameterNameAndValue;
|
||||||
use crate::quantity::{byte, const_time_from_seconds, ratio, second, Time, Zero};
|
use crate::quantity::{
|
||||||
|
byte, const_time_from_seconds, format_duration, format_duration_unit, ratio, second, Time, Zero,
|
||||||
|
};
|
||||||
use crate::util::exit_code::extract_exit_code;
|
use crate::util::exit_code::extract_exit_code;
|
||||||
use benchmark_result::BenchmarkResult;
|
use benchmark_result::BenchmarkResult;
|
||||||
use measurement::{Measurement, Measurements};
|
use measurement::{Measurement, Measurements};
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use super::benchmark_result::BenchmarkResult;
|
use super::benchmark_result::BenchmarkResult;
|
||||||
use crate::{options::SortOrder, util::units::Scalar};
|
use crate::options::SortOrder;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BenchmarkResultWithRelativeSpeed<'a> {
|
pub struct BenchmarkResultWithRelativeSpeed<'a> {
|
||||||
pub result: &'a BenchmarkResult,
|
pub result: &'a BenchmarkResult,
|
||||||
pub relative_speed: Scalar,
|
pub relative_speed: f64,
|
||||||
pub relative_speed_stddev: Option<Scalar>,
|
pub relative_speed_stddev: Option<f64>,
|
||||||
pub is_reference: bool,
|
pub is_reference: bool,
|
||||||
// Less means faster
|
// Less means faster
|
||||||
pub relative_ordering: Ordering,
|
pub relative_ordering: Ordering,
|
||||||
@@ -119,7 +119,7 @@ pub fn compute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn create_result(name: &str, mean: Scalar) -> BenchmarkResult {
|
fn create_result(name: &str, mean: f64) -> BenchmarkResult {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
BenchmarkResult {
|
BenchmarkResult {
|
||||||
|
|||||||
+3
-3
@@ -5,7 +5,7 @@ use csv::WriterBuilder;
|
|||||||
use super::Exporter;
|
use super::Exporter;
|
||||||
use crate::benchmark::benchmark_result::BenchmarkResult;
|
use crate::benchmark::benchmark_result::BenchmarkResult;
|
||||||
use crate::options::SortOrder;
|
use crate::options::SortOrder;
|
||||||
use crate::util::units::Unit;
|
use crate::quantity::TimeUnit;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ impl Exporter for CsvExporter {
|
|||||||
fn serialize(
|
fn serialize(
|
||||||
&self,
|
&self,
|
||||||
results: &[BenchmarkResult],
|
results: &[BenchmarkResult],
|
||||||
_unit: Option<Unit>,
|
_unit: Option<TimeUnit>,
|
||||||
_sort_order: SortOrder,
|
_sort_order: SortOrder,
|
||||||
) -> Result<Vec<u8>> {
|
) -> Result<Vec<u8>> {
|
||||||
let mut writer = WriterBuilder::new().from_writer(vec![]);
|
let mut writer = WriterBuilder::new().from_writer(vec![]);
|
||||||
@@ -110,7 +110,7 @@ fn test_csv() {
|
|||||||
|
|
||||||
let actual = String::from_utf8(
|
let actual = String::from_utf8(
|
||||||
exporter
|
exporter
|
||||||
.serialize(&results, Some(Unit::Second), SortOrder::Command)
|
.serialize(&results, Some(TimeUnit::Second), SortOrder::Command)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
+2
-2
@@ -4,7 +4,7 @@ use serde_json::to_vec_pretty;
|
|||||||
use super::Exporter;
|
use super::Exporter;
|
||||||
use crate::benchmark::benchmark_result::BenchmarkResult;
|
use crate::benchmark::benchmark_result::BenchmarkResult;
|
||||||
use crate::options::SortOrder;
|
use crate::options::SortOrder;
|
||||||
use crate::util::units::Unit;
|
use crate::quantity::TimeUnit;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ impl Exporter for JsonExporter {
|
|||||||
fn serialize(
|
fn serialize(
|
||||||
&self,
|
&self,
|
||||||
results: &[BenchmarkResult],
|
results: &[BenchmarkResult],
|
||||||
_unit: Option<Unit>,
|
_unit: Option<TimeUnit>,
|
||||||
_sort_order: SortOrder,
|
_sort_order: SortOrder,
|
||||||
) -> Result<Vec<u8>> {
|
) -> Result<Vec<u8>> {
|
||||||
let mut output = to_vec_pretty(&HyperfineSummary { results });
|
let mut output = to_vec_pretty(&HyperfineSummary { results });
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use crate::benchmark::relative_speed::BenchmarkResultWithRelativeSpeed;
|
use crate::benchmark::relative_speed::BenchmarkResultWithRelativeSpeed;
|
||||||
use crate::benchmark::{benchmark_result::BenchmarkResult, relative_speed};
|
use crate::benchmark::{benchmark_result::BenchmarkResult, relative_speed};
|
||||||
use crate::options::SortOrder;
|
use crate::options::SortOrder;
|
||||||
use crate::output::format::format_duration_value;
|
use crate::quantity::{format_duration_value, TimeUnit};
|
||||||
use crate::util::units::Unit;
|
|
||||||
|
|
||||||
use super::Exporter;
|
use super::Exporter;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@@ -13,7 +12,11 @@ pub enum Alignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait MarkupExporter {
|
pub trait MarkupExporter {
|
||||||
fn table_results(&self, entries: &[BenchmarkResultWithRelativeSpeed], unit: Unit) -> String {
|
fn table_results(
|
||||||
|
&self,
|
||||||
|
entries: &[BenchmarkResultWithRelativeSpeed],
|
||||||
|
unit: TimeUnit,
|
||||||
|
) -> String {
|
||||||
// prepare table header strings
|
// prepare table header strings
|
||||||
let notation = format!("[{}]", unit.short_name());
|
let notation = format!("[{}]", unit.short_name());
|
||||||
|
|
||||||
@@ -95,13 +98,13 @@ pub trait MarkupExporter {
|
|||||||
fn command(&self, size: &str) -> String;
|
fn command(&self, size: &str) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_unit_from_results(results: &[BenchmarkResult]) -> Unit {
|
fn determine_unit_from_results(results: &[BenchmarkResult]) -> TimeUnit {
|
||||||
if let Some(first_result) = results.first() {
|
if let Some(first_result) = results.first() {
|
||||||
// Use the first BenchmarkResult entry to determine the unit for all entries.
|
// Use the first BenchmarkResult entry to determine the unit for all entries.
|
||||||
format_duration_value(first_result.mean, None).1
|
format_duration_value(first_result.mean, None).1
|
||||||
} else {
|
} else {
|
||||||
// Default to `Second`.
|
// Default to `Second`.
|
||||||
Unit::Second
|
TimeUnit::Second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +112,7 @@ impl<T: MarkupExporter> Exporter for T {
|
|||||||
fn serialize(
|
fn serialize(
|
||||||
&self,
|
&self,
|
||||||
results: &[BenchmarkResult],
|
results: &[BenchmarkResult],
|
||||||
unit: Option<Unit>,
|
unit: Option<TimeUnit>,
|
||||||
sort_order: SortOrder,
|
sort_order: SortOrder,
|
||||||
) -> Result<Vec<u8>> {
|
) -> Result<Vec<u8>> {
|
||||||
let unit = unit.unwrap_or_else(|| determine_unit_from_results(results));
|
let unit = unit.unwrap_or_else(|| determine_unit_from_results(results));
|
||||||
|
|||||||
+4
-4
@@ -19,7 +19,7 @@ use self::orgmode::OrgmodeExporter;
|
|||||||
use crate::benchmark::benchmark_result::BenchmarkResult;
|
use crate::benchmark::benchmark_result::BenchmarkResult;
|
||||||
use crate::options::SortOrder;
|
use crate::options::SortOrder;
|
||||||
use crate::output::console_writeln;
|
use crate::output::console_writeln;
|
||||||
use crate::util::units::Unit;
|
use crate::quantity::TimeUnit;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
@@ -49,7 +49,7 @@ trait Exporter {
|
|||||||
fn serialize(
|
fn serialize(
|
||||||
&self,
|
&self,
|
||||||
results: &[BenchmarkResult],
|
results: &[BenchmarkResult],
|
||||||
unit: Option<Unit>,
|
unit: Option<TimeUnit>,
|
||||||
sort_order: SortOrder,
|
sort_order: SortOrder,
|
||||||
) -> Result<Vec<u8>>;
|
) -> Result<Vec<u8>>;
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ struct ExporterWithTarget {
|
|||||||
/// Handles the management of multiple file exporters.
|
/// Handles the management of multiple file exporters.
|
||||||
pub struct ExportManager {
|
pub struct ExportManager {
|
||||||
exporters: Vec<ExporterWithTarget>,
|
exporters: Vec<ExporterWithTarget>,
|
||||||
time_unit: Option<Unit>,
|
time_unit: Option<TimeUnit>,
|
||||||
sort_order: SortOrder,
|
sort_order: SortOrder,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ impl ExportManager {
|
|||||||
/// in the given ArgMatches
|
/// in the given ArgMatches
|
||||||
pub fn from_cli_arguments(
|
pub fn from_cli_arguments(
|
||||||
matches: &ArgMatches,
|
matches: &ArgMatches,
|
||||||
time_unit: Option<Unit>,
|
time_unit: Option<TimeUnit>,
|
||||||
sort_order: SortOrder,
|
sort_order: SortOrder,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let mut export_manager = Self {
|
let mut export_manager = Self {
|
||||||
|
|||||||
+8
-8
@@ -2,13 +2,13 @@ use super::Exporter;
|
|||||||
use crate::benchmark::benchmark_result::BenchmarkResult;
|
use crate::benchmark::benchmark_result::BenchmarkResult;
|
||||||
use crate::export::asciidoc::AsciidocExporter;
|
use crate::export::asciidoc::AsciidocExporter;
|
||||||
use crate::export::orgmode::OrgmodeExporter;
|
use crate::export::orgmode::OrgmodeExporter;
|
||||||
use crate::util::units::Unit;
|
use crate::quantity::TimeUnit;
|
||||||
use crate::{export::markdown::MarkdownExporter, options::SortOrder};
|
use crate::{export::markdown::MarkdownExporter, options::SortOrder};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
fn get_output<E: Exporter + Default>(
|
fn get_output<E: Exporter + Default>(
|
||||||
results: &[BenchmarkResult],
|
results: &[BenchmarkResult],
|
||||||
unit: Option<Unit>,
|
unit: Option<TimeUnit>,
|
||||||
sort_order: SortOrder,
|
sort_order: SortOrder,
|
||||||
) -> String {
|
) -> String {
|
||||||
let exporter = E::default();
|
let exporter = E::default();
|
||||||
@@ -206,14 +206,14 @@ fn test_markup_export_manual_ms() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
insta::assert_snapshot!(get_output::<MarkdownExporter>(&timing_results, Some(Unit::MilliSecond), SortOrder::Command), @r#"
|
insta::assert_snapshot!(get_output::<MarkdownExporter>(&timing_results, Some(TimeUnit::MilliSecond), SortOrder::Command), @r#"
|
||||||
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
||||||
|:---|---:|---:|---:|---:|
|
|:---|---:|---:|---:|---:|
|
||||||
| `sleep 2` | 2005.0 ± 2.0 | 2002.0 | 2008.0 | 18.97 ± 0.29 |
|
| `sleep 2` | 2005.0 ± 2.0 | 2002.0 | 2008.0 | 18.97 ± 0.29 |
|
||||||
| `sleep 0.1` | 105.7 ± 1.6 | 102.3 | 108.0 | 1.00 |
|
| `sleep 0.1` | 105.7 ± 1.6 | 102.3 | 108.0 | 1.00 |
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
insta::assert_snapshot!(get_output::<AsciidocExporter>(&timing_results, Some(Unit::MilliSecond), SortOrder::Command), @r#"
|
insta::assert_snapshot!(get_output::<AsciidocExporter>(&timing_results, Some(TimeUnit::MilliSecond), SortOrder::Command), @r#"
|
||||||
[cols="<,>,>,>,>"]
|
[cols="<,>,>,>,>"]
|
||||||
|===
|
|===
|
||||||
| Command
|
| Command
|
||||||
@@ -236,7 +236,7 @@ fn test_markup_export_manual_ms() {
|
|||||||
|===
|
|===
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
insta::assert_snapshot!(get_output::<OrgmodeExporter>(&timing_results, Some(Unit::MilliSecond), SortOrder::Command), @r#"
|
insta::assert_snapshot!(get_output::<OrgmodeExporter>(&timing_results, Some(TimeUnit::MilliSecond), SortOrder::Command), @r#"
|
||||||
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
||||||
|--+--+--+--+--|
|
|--+--+--+--+--|
|
||||||
| =sleep 2= | 2005.0 ± 2.0 | 2002.0 | 2008.0 | 18.97 ± 0.29 |
|
| =sleep 2= | 2005.0 ± 2.0 | 2002.0 | 2008.0 | 18.97 ± 0.29 |
|
||||||
@@ -280,21 +280,21 @@ fn test_markup_export_manual_s() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
insta::assert_snapshot!(get_output::<MarkdownExporter>(&results, Some(Unit::Second), SortOrder::Command), @r#"
|
insta::assert_snapshot!(get_output::<MarkdownExporter>(&results, Some(TimeUnit::Second), SortOrder::Command), @r#"
|
||||||
| Command | Mean [s] | Min [s] | Max [s] | Relative |
|
| Command | Mean [s] | Min [s] | Max [s] | Relative |
|
||||||
|:---|---:|---:|---:|---:|
|
|:---|---:|---:|---:|---:|
|
||||||
| `sleep 2` | 2.005 ± 0.002 | 2.002 | 2.008 | 18.97 ± 0.29 |
|
| `sleep 2` | 2.005 ± 0.002 | 2.002 | 2.008 | 18.97 ± 0.29 |
|
||||||
| `sleep 0.1` | 0.106 ± 0.002 | 0.102 | 0.108 | 1.00 |
|
| `sleep 0.1` | 0.106 ± 0.002 | 0.102 | 0.108 | 1.00 |
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
insta::assert_snapshot!(get_output::<MarkdownExporter>(&results, Some(Unit::Second), SortOrder::MeanTime), @r#"
|
insta::assert_snapshot!(get_output::<MarkdownExporter>(&results, Some(TimeUnit::Second), SortOrder::MeanTime), @r#"
|
||||||
| Command | Mean [s] | Min [s] | Max [s] | Relative |
|
| Command | Mean [s] | Min [s] | Max [s] | Relative |
|
||||||
|:---|---:|---:|---:|---:|
|
|:---|---:|---:|---:|---:|
|
||||||
| `sleep 0.1` | 0.106 ± 0.002 | 0.102 | 0.108 | 1.00 |
|
| `sleep 0.1` | 0.106 ± 0.002 | 0.102 | 0.108 | 1.00 |
|
||||||
| `sleep 2` | 2.005 ± 0.002 | 2.002 | 2.008 | 18.97 ± 0.29 |
|
| `sleep 2` | 2.005 ± 0.002 | 2.002 | 2.008 | 18.97 ± 0.29 |
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
insta::assert_snapshot!(get_output::<AsciidocExporter>(&results, Some(Unit::Second), SortOrder::Command), @r#"
|
insta::assert_snapshot!(get_output::<AsciidocExporter>(&results, Some(TimeUnit::Second), SortOrder::Command), @r#"
|
||||||
[cols="<,>,>,>,>"]
|
[cols="<,>,>,>,>"]
|
||||||
|===
|
|===
|
||||||
| Command
|
| Command
|
||||||
|
|||||||
+7
-8
@@ -9,8 +9,7 @@ use clap::ArgMatches;
|
|||||||
|
|
||||||
use crate::command::Commands;
|
use crate::command::Commands;
|
||||||
use crate::error::OptionsError;
|
use crate::error::OptionsError;
|
||||||
use crate::quantity::{second, Time};
|
use crate::quantity::{second, Time, TimeUnit};
|
||||||
use crate::util::units::Unit;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
@@ -246,7 +245,7 @@ pub struct Options {
|
|||||||
pub command_output_policies: Vec<CommandOutputPolicy>,
|
pub command_output_policies: Vec<CommandOutputPolicy>,
|
||||||
|
|
||||||
/// Which time unit to use when displaying results
|
/// Which time unit to use when displaying results
|
||||||
pub time_unit: Option<Unit>,
|
pub time_unit: Option<TimeUnit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Options {
|
impl Default for Options {
|
||||||
@@ -430,11 +429,11 @@ impl Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options.time_unit = match matches.get_one::<String>("time-unit").map(|s| s.as_str()) {
|
options.time_unit = match matches.get_one::<String>("time-unit").map(|s| s.as_str()) {
|
||||||
Some("µs" | "us" | "microsecond" | "microseconds") => Some(Unit::MicroSecond),
|
Some("µs" | "us" | "microsecond" | "microseconds") => Some(TimeUnit::MicroSecond),
|
||||||
Some("ms" | "millisecond" | "milliseconds") => Some(Unit::MilliSecond),
|
Some("ms" | "millisecond" | "milliseconds") => Some(TimeUnit::MilliSecond),
|
||||||
Some("s" | "second" | "seconds") => Some(Unit::Second),
|
Some("s" | "second" | "seconds") => Some(TimeUnit::Second),
|
||||||
Some("min" | "minute" | "minutes") => Some(Unit::Minute),
|
Some("min" | "minute" | "minutes") => Some(TimeUnit::Minute),
|
||||||
Some("h" | "hour" | "hours") => Some(Unit::Hour),
|
Some("h" | "hour" | "hours") => Some(TimeUnit::Hour),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,42 +5,17 @@
|
|||||||
//! The ASQC Basic References in Quality Control: Statistical Techniques, Edward F. Mykytka,
|
//! The ASQC Basic References in Quality Control: Statistical Techniques, Edward F. Mykytka,
|
||||||
//! Ph.D., Editor.
|
//! Ph.D., Editor.
|
||||||
|
|
||||||
use crate::util::statistics::median;
|
|
||||||
|
|
||||||
/// Minimum modified Z-score for a datapoint to be an outlier. Here, 1.4826 is a factor that
|
/// Minimum modified Z-score for a datapoint to be an outlier. Here, 1.4826 is a factor that
|
||||||
/// converts the MAD to an estimator for the standard deviation. The second factor is the number
|
/// converts the MAD to an estimator for the standard deviation. The second factor is the number
|
||||||
/// of standard deviations.
|
/// of standard deviations.
|
||||||
pub const OUTLIER_THRESHOLD: f64 = 1.4826 * 10.0;
|
pub const OUTLIER_THRESHOLD: f64 = 1.4826 * 10.0;
|
||||||
|
|
||||||
/// Compute modifized Z-scores for a given sample. A (unmodified) Z-score is defined by
|
|
||||||
/// `(x_i - x_mean)/x_stddev` whereas the modified Z-score is defined by `(x_i - x_median)/MAD`
|
|
||||||
/// where MAD is the median absolute deviation.
|
|
||||||
///
|
|
||||||
/// References:
|
|
||||||
/// - <https://en.wikipedia.org/wiki/Median_absolute_deviation>
|
|
||||||
pub fn modified_zscores(xs: &[f64]) -> Vec<f64> {
|
|
||||||
assert!(!xs.is_empty());
|
|
||||||
|
|
||||||
// Compute sample median:
|
|
||||||
let x_median = median(xs.iter().copied());
|
|
||||||
|
|
||||||
// Compute the absolute deviations from the median:
|
|
||||||
let deviations: Vec<f64> = xs.iter().map(|x| (x - x_median).abs()).collect();
|
|
||||||
|
|
||||||
// Compute median absolute deviation:
|
|
||||||
let mad = median(deviations.iter().copied());
|
|
||||||
|
|
||||||
// Handle MAD == 0 case
|
|
||||||
let mad = if mad > 0.0 { mad } else { f64::EPSILON };
|
|
||||||
|
|
||||||
// Compute modified Z-scores (x_i - x_median) / MAD
|
|
||||||
xs.iter().map(|&x| (x - x_median) / mad).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the number of outliers in a given sample. Outliers are defined as data points with a
|
/// Return the number of outliers in a given sample. Outliers are defined as data points with a
|
||||||
/// modified Z-score that is larger than `OUTLIER_THRESHOLD`.
|
/// modified Z-score that is larger than `OUTLIER_THRESHOLD`.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn num_outliers(xs: &[f64]) -> usize {
|
pub fn num_outliers(xs: &[f64]) -> usize {
|
||||||
|
use crate::quantity::statistics::modified_zscores;
|
||||||
|
|
||||||
if xs.is_empty() {
|
if xs.is_empty() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
use crate::util::units::{Second, Unit};
|
|
||||||
|
|
||||||
/// Format the given duration as a string. The output-unit can be enforced by setting `unit` to
|
|
||||||
/// `Some(target_unit)`. If `unit` is `None`, it will be determined automatically.
|
|
||||||
pub fn format_duration(duration: Second, unit: Option<Unit>) -> String {
|
|
||||||
let (duration_fmt, _) = format_duration_unit(duration, unit);
|
|
||||||
duration_fmt
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like `format_duration`, but returns the target unit as well.
|
|
||||||
pub fn format_duration_unit(duration: Second, unit: Option<Unit>) -> (String, Unit) {
|
|
||||||
let (out_str, out_unit) = format_duration_value(duration, unit);
|
|
||||||
|
|
||||||
(format!("{} {}", out_str, out_unit.short_name()), out_unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like `format_duration`, but returns the target unit as well.
|
|
||||||
pub fn format_duration_value(duration: Second, unit: Option<Unit>) -> (String, Unit) {
|
|
||||||
if (duration < 0.001 && unit.is_none()) || unit == Some(Unit::MicroSecond) {
|
|
||||||
(Unit::MicroSecond.format(duration), Unit::MicroSecond)
|
|
||||||
} else if (duration < 1.0 && unit.is_none()) || unit == Some(Unit::MilliSecond) {
|
|
||||||
(Unit::MilliSecond.format(duration), Unit::MilliSecond)
|
|
||||||
} else {
|
|
||||||
let unit = unit.unwrap_or(Unit::Second);
|
|
||||||
(unit.format(duration), unit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_format_duration_unit_basic() {
|
|
||||||
let (out_str, out_unit) = format_duration_unit(1.3, None);
|
|
||||||
|
|
||||||
assert_eq!("1.300 s", out_str);
|
|
||||||
assert_eq!(Unit::Second, out_unit);
|
|
||||||
|
|
||||||
let (out_str, out_unit) = format_duration_unit(1.0, None);
|
|
||||||
|
|
||||||
assert_eq!("1.000 s", out_str);
|
|
||||||
assert_eq!(Unit::Second, out_unit);
|
|
||||||
|
|
||||||
let (out_str, out_unit) = format_duration_unit(0.999, None);
|
|
||||||
|
|
||||||
assert_eq!("999.0 ms", out_str);
|
|
||||||
assert_eq!(Unit::MilliSecond, out_unit);
|
|
||||||
|
|
||||||
let (out_str, out_unit) = format_duration_unit(0.0005, None);
|
|
||||||
|
|
||||||
assert_eq!("500.0 µs", out_str);
|
|
||||||
assert_eq!(Unit::MicroSecond, out_unit);
|
|
||||||
|
|
||||||
let (out_str, out_unit) = format_duration_unit(0.0, None);
|
|
||||||
|
|
||||||
assert_eq!("0.0 µs", out_str);
|
|
||||||
assert_eq!(Unit::MicroSecond, out_unit);
|
|
||||||
|
|
||||||
let (out_str, out_unit) = format_duration_unit(1000.0, None);
|
|
||||||
|
|
||||||
assert_eq!("1000.000 s", out_str);
|
|
||||||
assert_eq!(Unit::Second, out_unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_format_duration_unit_with_unit() {
|
|
||||||
let (out_str, out_unit) = format_duration_unit(1.3, Some(Unit::Second));
|
|
||||||
|
|
||||||
assert_eq!("1.300 s", out_str);
|
|
||||||
assert_eq!(Unit::Second, out_unit);
|
|
||||||
|
|
||||||
let (out_str, out_unit) = format_duration_unit(1.3, Some(Unit::MilliSecond));
|
|
||||||
|
|
||||||
assert_eq!("1300.0 ms", out_str);
|
|
||||||
assert_eq!(Unit::MilliSecond, out_unit);
|
|
||||||
|
|
||||||
let (out_str, out_unit) = format_duration_unit(1.3, Some(Unit::MicroSecond));
|
|
||||||
|
|
||||||
assert_eq!("1300000.0 µs", out_str);
|
|
||||||
assert_eq!(Unit::MicroSecond, out_unit);
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
pub mod format;
|
|
||||||
pub mod progress_bar;
|
pub mod progress_bar;
|
||||||
pub mod warnings;
|
pub mod warnings;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::benchmark::MIN_EXECUTION_TIME;
|
use crate::benchmark::MIN_EXECUTION_TIME;
|
||||||
use crate::output::format::format_duration;
|
use crate::quantity::{format_duration, second, Time};
|
||||||
use crate::quantity::{second, Time};
|
|
||||||
|
|
||||||
pub struct OutlierWarningOptions {
|
pub struct OutlierWarningOptions {
|
||||||
pub warmup_in_use: bool,
|
pub warmup_in_use: bool,
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
pub use uom::num_traits::Zero;
|
|
||||||
pub use uom::si::f64::{Information, Ratio, Time};
|
|
||||||
pub use uom::si::information::byte;
|
|
||||||
pub use uom::si::ratio::ratio;
|
|
||||||
pub use uom::si::time::{microsecond, nanosecond, second};
|
|
||||||
|
|
||||||
pub const fn const_time_from_seconds(value: f64) -> Time {
|
|
||||||
// Quantity::new in uom is not yet const: https://docs.rs/uom/0.36.0/uom/si/struct.Quantity.html
|
|
||||||
Time {
|
|
||||||
dimension: PhantomData,
|
|
||||||
units: PhantomData,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
use uom::si::{information::kibibyte, time::millisecond};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_time() {
|
|
||||||
let time = Time::new::<millisecond>(123.4);
|
|
||||||
assert_eq!(time.get::<millisecond>(), 123.4);
|
|
||||||
|
|
||||||
let time_s = time.get::<second>();
|
|
||||||
approx::assert_relative_eq!(time_s, 0.1234);
|
|
||||||
|
|
||||||
let time_us = time.get::<microsecond>();
|
|
||||||
approx::assert_relative_eq!(time_us, 123400.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_information() {
|
|
||||||
use uom::si::information::pebibyte;
|
|
||||||
|
|
||||||
let information = Information::new::<kibibyte>(8.);
|
|
||||||
assert_eq!(information.get::<byte>(), 8192.);
|
|
||||||
|
|
||||||
let information_kib = information.get::<kibibyte>();
|
|
||||||
assert_eq!(information_kib, 8.);
|
|
||||||
|
|
||||||
let largest_exactly_representable = Information::new::<byte>(9_007_199_254_740_992.);
|
|
||||||
assert_eq!(largest_exactly_representable.get::<pebibyte>(), 8.);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub use uom::num_traits::Zero;
|
||||||
|
pub use uom::si::f64::{Information, Ratio, Time};
|
||||||
|
pub use uom::si::information::byte;
|
||||||
|
pub use uom::si::ratio::ratio;
|
||||||
|
pub use uom::si::time::{microsecond, nanosecond, second};
|
||||||
|
|
||||||
|
pub use units::TimeUnit;
|
||||||
|
|
||||||
|
pub mod statistics;
|
||||||
|
mod units;
|
||||||
|
|
||||||
|
pub const fn const_time_from_seconds(value: f64) -> Time {
|
||||||
|
// Quantity::new in uom is not yet const: https://docs.rs/uom/0.36.0/uom/si/struct.Quantity.html
|
||||||
|
Time {
|
||||||
|
dimension: PhantomData,
|
||||||
|
units: PhantomData,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format the given duration as a string. The output-unit can be enforced by setting `unit` to
|
||||||
|
/// `Some(target_unit)`. If `unit` is `None`, it will be determined automatically.
|
||||||
|
pub fn format_duration(duration: f64, unit: Option<TimeUnit>) -> String {
|
||||||
|
let (duration_fmt, _) = format_duration_unit(duration, unit);
|
||||||
|
duration_fmt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `format_duration`, but returns the target unit as well.
|
||||||
|
pub fn format_duration_unit(duration: f64, unit: Option<TimeUnit>) -> (String, TimeUnit) {
|
||||||
|
let (out_str, out_unit) = format_duration_value(duration, unit);
|
||||||
|
|
||||||
|
(format!("{} {}", out_str, out_unit.short_name()), out_unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `format_duration`, but returns the target unit as well.
|
||||||
|
pub fn format_duration_value(duration: f64, unit: Option<TimeUnit>) -> (String, TimeUnit) {
|
||||||
|
if (duration < 0.001 && unit.is_none()) || unit == Some(TimeUnit::MicroSecond) {
|
||||||
|
(
|
||||||
|
TimeUnit::MicroSecond.format(duration),
|
||||||
|
TimeUnit::MicroSecond,
|
||||||
|
)
|
||||||
|
} else if (duration < 1.0 && unit.is_none()) || unit == Some(TimeUnit::MilliSecond) {
|
||||||
|
(
|
||||||
|
TimeUnit::MilliSecond.format(duration),
|
||||||
|
TimeUnit::MilliSecond,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let unit = unit.unwrap_or(TimeUnit::Second);
|
||||||
|
(unit.format(duration), unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use uom::si::{information::kibibyte, time::millisecond};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time() {
|
||||||
|
let time = Time::new::<millisecond>(123.4);
|
||||||
|
assert_eq!(time.get::<millisecond>(), 123.4);
|
||||||
|
|
||||||
|
let time_s = time.get::<second>();
|
||||||
|
approx::assert_relative_eq!(time_s, 0.1234);
|
||||||
|
|
||||||
|
let time_us = time.get::<microsecond>();
|
||||||
|
approx::assert_relative_eq!(time_us, 123400.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_information() {
|
||||||
|
use uom::si::information::pebibyte;
|
||||||
|
|
||||||
|
let information = Information::new::<kibibyte>(8.);
|
||||||
|
assert_eq!(information.get::<byte>(), 8192.);
|
||||||
|
|
||||||
|
let information_kib = information.get::<kibibyte>();
|
||||||
|
assert_eq!(information_kib, 8.);
|
||||||
|
|
||||||
|
let largest_exactly_representable = Information::new::<byte>(9_007_199_254_740_992.);
|
||||||
|
assert_eq!(largest_exactly_representable.get::<pebibyte>(), 8.);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_duration_unit_basic() {
|
||||||
|
let (out_str, out_unit) = format_duration_unit(1.3, None);
|
||||||
|
|
||||||
|
assert_eq!("1.300 s", out_str);
|
||||||
|
assert_eq!(TimeUnit::Second, out_unit);
|
||||||
|
|
||||||
|
let (out_str, out_unit) = format_duration_unit(1.0, None);
|
||||||
|
|
||||||
|
assert_eq!("1.000 s", out_str);
|
||||||
|
assert_eq!(TimeUnit::Second, out_unit);
|
||||||
|
|
||||||
|
let (out_str, out_unit) = format_duration_unit(0.999, None);
|
||||||
|
|
||||||
|
assert_eq!("999.0 ms", out_str);
|
||||||
|
assert_eq!(TimeUnit::MilliSecond, out_unit);
|
||||||
|
|
||||||
|
let (out_str, out_unit) = format_duration_unit(0.0005, None);
|
||||||
|
|
||||||
|
assert_eq!("500.0 µs", out_str);
|
||||||
|
assert_eq!(TimeUnit::MicroSecond, out_unit);
|
||||||
|
|
||||||
|
let (out_str, out_unit) = format_duration_unit(0.0, None);
|
||||||
|
|
||||||
|
assert_eq!("0.0 µs", out_str);
|
||||||
|
assert_eq!(TimeUnit::MicroSecond, out_unit);
|
||||||
|
|
||||||
|
let (out_str, out_unit) = format_duration_unit(1000.0, None);
|
||||||
|
|
||||||
|
assert_eq!("1000.000 s", out_str);
|
||||||
|
assert_eq!(TimeUnit::Second, out_unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_duration_unit_with_unit() {
|
||||||
|
let (out_str, out_unit) = format_duration_unit(1.3, Some(TimeUnit::Second));
|
||||||
|
|
||||||
|
assert_eq!("1.300 s", out_str);
|
||||||
|
assert_eq!(TimeUnit::Second, out_unit);
|
||||||
|
|
||||||
|
let (out_str, out_unit) = format_duration_unit(1.3, Some(TimeUnit::MilliSecond));
|
||||||
|
|
||||||
|
assert_eq!("1300.0 ms", out_str);
|
||||||
|
assert_eq!(TimeUnit::MilliSecond, out_unit);
|
||||||
|
|
||||||
|
let (out_str, out_unit) = format_duration_unit(1.3, Some(TimeUnit::MicroSecond));
|
||||||
|
|
||||||
|
assert_eq!("1300000.0 µs", out_str);
|
||||||
|
assert_eq!(TimeUnit::MicroSecond, out_unit);
|
||||||
|
}
|
||||||
@@ -106,6 +106,31 @@ pub fn standard_deviation<Q: UnsafeRawValue>(values: &[Q], mean: Q) -> Q {
|
|||||||
Q::unsafe_from_raw_value((sum / (values.len() as f64 - 1.0)).sqrt())
|
Q::unsafe_from_raw_value((sum / (values.len() as f64 - 1.0)).sqrt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute modifized Z-scores for a given sample. A (unmodified) Z-score is defined by
|
||||||
|
/// `(x_i - x_mean)/x_stddev` whereas the modified Z-score is defined by `(x_i - x_median)/MAD`
|
||||||
|
/// where MAD is the median absolute deviation.
|
||||||
|
///
|
||||||
|
/// References:
|
||||||
|
/// - <https://en.wikipedia.org/wiki/Median_absolute_deviation>
|
||||||
|
pub fn modified_zscores(xs: &[f64]) -> Vec<f64> {
|
||||||
|
assert!(!xs.is_empty());
|
||||||
|
|
||||||
|
// Compute sample median:
|
||||||
|
let x_median = median(xs.iter().copied());
|
||||||
|
|
||||||
|
// Compute the absolute deviations from the median:
|
||||||
|
let deviations: Vec<f64> = xs.iter().map(|x| (x - x_median).abs()).collect();
|
||||||
|
|
||||||
|
// Compute median absolute deviation:
|
||||||
|
let mad = median(deviations.iter().copied());
|
||||||
|
|
||||||
|
// Handle MAD == 0 case
|
||||||
|
let mad = if mad > 0.0 { mad } else { f64::EPSILON };
|
||||||
|
|
||||||
|
// Compute modified Z-scores (x_i - x_median) / MAD
|
||||||
|
xs.iter().map(|&x| (x - x_median) / mad).collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
//! This module contains common units.
|
||||||
|
|
||||||
|
/// Supported time units
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum TimeUnit {
|
||||||
|
Second,
|
||||||
|
MilliSecond,
|
||||||
|
MicroSecond,
|
||||||
|
Minute,
|
||||||
|
Hour,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimeUnit {
|
||||||
|
/// The abbreviation of the TimeUnit.
|
||||||
|
pub fn short_name(self) -> String {
|
||||||
|
match self {
|
||||||
|
TimeUnit::Second => String::from("s"),
|
||||||
|
TimeUnit::MilliSecond => String::from("ms"),
|
||||||
|
TimeUnit::MicroSecond => String::from("µs"),
|
||||||
|
TimeUnit::Minute => String::from("min"),
|
||||||
|
TimeUnit::Hour => String::from("h"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the value in seconds formatted for the TimeUnit.
|
||||||
|
pub fn format(self, value: f64) -> String {
|
||||||
|
match self {
|
||||||
|
TimeUnit::Second => format!("{value:.3}"),
|
||||||
|
TimeUnit::MilliSecond => format!("{:.1}", value * 1e3),
|
||||||
|
TimeUnit::MicroSecond => format!("{:.1}", value * 1e6),
|
||||||
|
TimeUnit::Minute => format!("{:.1}", value / 60.0),
|
||||||
|
TimeUnit::Hour => format!("{:.1}", value / 3600.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unit_short_name() {
|
||||||
|
assert_eq!("s", TimeUnit::Second.short_name());
|
||||||
|
assert_eq!("ms", TimeUnit::MilliSecond.short_name());
|
||||||
|
assert_eq!("µs", TimeUnit::MicroSecond.short_name());
|
||||||
|
assert_eq!("min", TimeUnit::Minute.short_name());
|
||||||
|
assert_eq!("h", TimeUnit::Hour.short_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note - the values are rounded when formatted.
|
||||||
|
#[test]
|
||||||
|
fn test_unit_format() {
|
||||||
|
let value: f64 = 123.456789;
|
||||||
|
assert_eq!("123.457", TimeUnit::Second.format(value));
|
||||||
|
assert_eq!("123456.8", TimeUnit::MilliSecond.format(value));
|
||||||
|
|
||||||
|
assert_eq!("1234.6", TimeUnit::MicroSecond.format(0.00123456));
|
||||||
|
assert_eq!("2.1", TimeUnit::Minute.format(value));
|
||||||
|
assert_eq!("0.0", TimeUnit::Hour.format(value));
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
pub mod exit_code;
|
pub mod exit_code;
|
||||||
pub mod number;
|
pub mod number;
|
||||||
pub mod randomized_environment_offset;
|
pub mod randomized_environment_offset;
|
||||||
pub mod statistics;
|
|
||||||
pub mod units;
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
//! This module contains common units.
|
|
||||||
|
|
||||||
pub type Scalar = f64;
|
|
||||||
|
|
||||||
/// Type alias for unit of time
|
|
||||||
pub type Second = Scalar;
|
|
||||||
|
|
||||||
/// Supported time units
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum Unit {
|
|
||||||
Second,
|
|
||||||
MilliSecond,
|
|
||||||
MicroSecond,
|
|
||||||
Minute,
|
|
||||||
Hour,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Unit {
|
|
||||||
/// The abbreviation of the Unit.
|
|
||||||
pub fn short_name(self) -> String {
|
|
||||||
match self {
|
|
||||||
Unit::Second => String::from("s"),
|
|
||||||
Unit::MilliSecond => String::from("ms"),
|
|
||||||
Unit::MicroSecond => String::from("µs"),
|
|
||||||
Unit::Minute => String::from("min"),
|
|
||||||
Unit::Hour => String::from("h"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the Second value formatted for the Unit.
|
|
||||||
pub fn format(self, value: Second) -> String {
|
|
||||||
match self {
|
|
||||||
Unit::Second => format!("{value:.3}"),
|
|
||||||
Unit::MilliSecond => format!("{:.1}", value * 1e3),
|
|
||||||
Unit::MicroSecond => format!("{:.1}", value * 1e6),
|
|
||||||
Unit::Minute => format!("{:.1}", value / 60.0),
|
|
||||||
Unit::Hour => format!("{:.1}", value / 3600.0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_unit_short_name() {
|
|
||||||
assert_eq!("s", Unit::Second.short_name());
|
|
||||||
assert_eq!("ms", Unit::MilliSecond.short_name());
|
|
||||||
assert_eq!("µs", Unit::MicroSecond.short_name());
|
|
||||||
assert_eq!("min", Unit::Minute.short_name());
|
|
||||||
assert_eq!("h", Unit::Hour.short_name());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note - the values are rounded when formatted.
|
|
||||||
#[test]
|
|
||||||
fn test_unit_format() {
|
|
||||||
let value: Second = 123.456789;
|
|
||||||
assert_eq!("123.457", Unit::Second.format(value));
|
|
||||||
assert_eq!("123456.8", Unit::MilliSecond.format(value));
|
|
||||||
|
|
||||||
assert_eq!("1234.6", Unit::MicroSecond.format(0.00123456));
|
|
||||||
assert_eq!("2.1", Unit::Minute.format(value));
|
|
||||||
assert_eq!("0.0", Unit::Hour.format(value));
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user