2018-01-14 20:14:10 +01:00
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
|
use indicatif::{ProgressBar, ProgressStyle};
|
|
|
|
|
|
|
|
|
|
/// Type alias for unit of time
|
|
|
|
|
pub type Second = f64;
|
|
|
|
|
|
|
|
|
|
/// Threshold for warning about fast execution time
|
|
|
|
|
pub const MIN_EXECUTION_TIME: Second = 5e-3;
|
|
|
|
|
|
2018-01-18 18:39:17 +01:00
|
|
|
/// Action to take when an executed command fails.
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub enum CmdFailureAction {
|
|
|
|
|
/// Exit with an error message
|
|
|
|
|
RaiseError,
|
|
|
|
|
|
|
|
|
|
/// Simply ignore the non-zero exit code
|
|
|
|
|
Ignore,
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-14 20:14:10 +01:00
|
|
|
/// A set of options for hyperfine
|
|
|
|
|
pub struct HyperfineOptions {
|
|
|
|
|
/// Number of warmup runs
|
|
|
|
|
pub warmup_count: u64,
|
|
|
|
|
|
|
|
|
|
/// Minimum number of benchmark runs
|
|
|
|
|
pub min_runs: u64,
|
|
|
|
|
|
|
|
|
|
/// Minimum benchmarking time
|
|
|
|
|
pub min_time_sec: Second,
|
|
|
|
|
|
|
|
|
|
/// Whether or not to ignore non-zero exit codes
|
2018-01-18 18:39:17 +01:00
|
|
|
pub failure_action: CmdFailureAction,
|
2018-01-16 21:26:14 +01:00
|
|
|
|
2018-01-18 18:13:12 +01:00
|
|
|
/// Command to run before each timing run
|
|
|
|
|
pub preparation_command: Option<String>,
|
2018-01-14 20:14:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for HyperfineOptions {
|
|
|
|
|
fn default() -> HyperfineOptions {
|
|
|
|
|
HyperfineOptions {
|
|
|
|
|
warmup_count: 0,
|
|
|
|
|
min_runs: 10,
|
|
|
|
|
min_time_sec: 3.0,
|
2018-01-18 18:39:17 +01:00
|
|
|
failure_action: CmdFailureAction::RaiseError,
|
2018-01-18 18:13:12 +01:00
|
|
|
preparation_command: None,
|
2018-01-14 20:14:10 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return a pre-configured progress bar
|
|
|
|
|
pub fn get_progress_bar(length: u64, msg: &str) -> ProgressBar {
|
|
|
|
|
let progressbar_style = ProgressStyle::default_spinner()
|
|
|
|
|
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
|
|
|
|
|
.template(" {spinner} {msg:<30} {wide_bar} ETA {eta_precise}");
|
|
|
|
|
|
|
|
|
|
let bar = ProgressBar::new(length);
|
|
|
|
|
bar.set_style(progressbar_style.clone());
|
|
|
|
|
bar.enable_steady_tick(80);
|
|
|
|
|
bar.set_message(msg);
|
|
|
|
|
|
|
|
|
|
bar
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Possible benchmark warnings
|
|
|
|
|
pub enum Warnings {
|
|
|
|
|
FastExecutionTime,
|
|
|
|
|
NonZeroExitCode,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Warnings {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
match self {
|
|
|
|
|
&Warnings::FastExecutionTime => write!(
|
|
|
|
|
f,
|
|
|
|
|
"Command took less than {:.0} ms to complete. Results might be inaccurate.",
|
|
|
|
|
MIN_EXECUTION_TIME * 1e3
|
|
|
|
|
),
|
|
|
|
|
&Warnings::NonZeroExitCode => write!(f, "Ignoring non-zero exit code."),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-14 21:43:29 +01:00
|
|
|
|
|
|
|
|
/// A max function for f64's without NaNs
|
|
|
|
|
pub fn max(vals: &[f64]) -> f64 {
|
|
|
|
|
vals.iter()
|
|
|
|
|
.max_by(|a, b| a.partial_cmp(b).unwrap())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.clone()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A min function for f64's without NaNs
|
|
|
|
|
pub fn min(vals: &[f64]) -> f64 {
|
|
|
|
|
vals.iter()
|
|
|
|
|
.min_by(|a, b| a.partial_cmp(b).unwrap())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.clone()
|
|
|
|
|
}
|
2018-01-18 18:58:51 +01:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_max() {
|
|
|
|
|
assert_eq!(1.0, max(&[1.0]));
|
|
|
|
|
assert_eq!(-1.0, max(&[-1.0]));
|
|
|
|
|
assert_eq!(-1.0, max(&[-2.0, -1.0]));
|
|
|
|
|
assert_eq!(1.0, max(&[-1.0, 1.0]));
|
|
|
|
|
assert_eq!(1.0, max(&[-1.0, 1.0, 0.0]));
|
|
|
|
|
}
|