ci: deflake `Measurement` tests (#31812)

* measure: test timer and conversion separately

* measure: test `timing::duration_as_*()` directly...
This commit is contained in:
Trent Nelson 2023-05-25 12:46:46 -06:00 committed by GitHub
parent 5fde26fe6f
commit 5572d23efa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 54 deletions

View File

@ -85,69 +85,31 @@ impl fmt::Display for Measure {
#[cfg(test)]
mod tests {
use {
super::*,
std::{fmt::Debug, thread::sleep},
};
use {super::*, std::thread::sleep};
#[test]
fn test_measure() {
let test_duration = Duration::from_millis(100);
let mut measure = Measure::start("test");
sleep(Duration::from_millis(100));
sleep(test_duration);
measure.stop();
// We have observed failures with margins of 10%, when CI machines are very busy, running
// multiple tests in parallel. As we are not testing the timer functionality itself, it is
// probably OK to increase the margins to 20%.
assert!(measure.as_s() >= 0.08f32 && measure.as_s() <= 0.12f32);
assert!(measure.as_ms() >= 80 && measure.as_ms() <= 120);
assert!(measure.as_us() >= 80_000 && measure.as_us() <= 120_000);
assert!(measure.as_ns() >= 80_000_000 && measure.as_ns() <= 120_000_000);
assert!(
measure.as_duration() >= Duration::from_millis(90)
&& measure.as_duration() <= Duration::from_millis(110)
);
assert!(measure.as_duration() >= test_duration);
}
#[test]
fn test_measure_end_as() {
#[track_caller]
fn test_end_as<Res>(method: fn(Measure) -> Res, sleep_ms: u64, lower: Res, upper: Res)
where
Res: PartialOrd + Debug,
{
let measure = Measure::start("test");
sleep(Duration::from_millis(sleep_ms));
let result = method(measure);
assert!(
result >= lower,
"Result below the expected bound.\n\
Lower bound: {lower:?}\n\
Result: {result:?}"
);
assert!(
result <= upper,
"Result above the expected bound.\n\
Upper bound: {upper:?}\n\
Result: {result:?}"
);
}
fn test_measure_as() {
let test_duration = Duration::from_millis(100);
let measure = Measure {
name: "test",
start: Instant::now(),
duration: test_duration.as_nanos() as u64,
};
// We have observed failures with margins of 10%, when CI machines are very busy, running
// multiple tests in parallel. As we are not testing the timer functionality itself, it is
// probably OK to increase the margins to 20%.
test_end_as(Measure::end_as_s, 100, 0.08f32, 0.12f32);
test_end_as(Measure::end_as_ms, 100, 80, 120);
test_end_as(Measure::end_as_us, 100, 80_000, 120_000);
test_end_as(Measure::end_as_ns, 100, 80_000_000, 120_000_000);
test_end_as(
Measure::end_as_duration,
100,
Duration::from_millis(80),
Duration::from_millis(120),
);
assert!(f32::abs(measure.as_s() - 0.1f32) <= f32::EPSILON);
assert_eq!(measure.as_ms(), 100);
assert_eq!(measure.as_us(), 100_000);
assert_eq!(measure.as_ns(), 100_000_000);
assert_eq!(measure.as_duration(), test_duration);
}
#[test]

View File

@ -168,4 +168,59 @@ mod test {
Duration::from_millis(1000) * ticks_per_slot
);
}
#[test]
fn test_duration_as() {
// zero
let test_zero = Duration::from_nanos(0);
assert_eq!(duration_as_ns(&test_zero), 0);
assert_eq!(duration_as_us(&test_zero), 0);
assert_eq!(duration_as_ms(&test_zero), 0);
assert!((duration_as_s(&test_zero) - 0f32) <= f32::EPSILON);
// min non-zero for each unit
let test_1ns = Duration::from_nanos(1);
assert_eq!(duration_as_ns(&test_1ns), 1);
assert_eq!(duration_as_us(&test_1ns), 0);
assert_eq!(duration_as_ms(&test_1ns), 0);
assert!((duration_as_s(&test_1ns) - 0.000_000_001f32) <= f32::EPSILON);
let test_1ns = Duration::from_micros(1);
assert_eq!(duration_as_ns(&test_1ns), 1_000);
assert_eq!(duration_as_us(&test_1ns), 1);
assert_eq!(duration_as_ms(&test_1ns), 0);
assert!((duration_as_s(&test_1ns) - 0.000_001f32) <= f32::EPSILON);
let test_1ns = Duration::from_millis(1);
assert_eq!(duration_as_ns(&test_1ns), 1_000_000);
assert_eq!(duration_as_us(&test_1ns), 1_000);
assert_eq!(duration_as_ms(&test_1ns), 1);
assert!((duration_as_s(&test_1ns) - 0.001f32) <= f32::EPSILON);
let test_1ns = Duration::from_secs(1);
assert_eq!(duration_as_ns(&test_1ns), 1_000_000_000);
assert_eq!(duration_as_us(&test_1ns), 1_000_000);
assert_eq!(duration_as_ms(&test_1ns), 1_000);
assert!((duration_as_s(&test_1ns) - 1f32) <= f32::EPSILON);
// max without error for each unit (except secs, 'cause if you use floats
// you deserve to get got)
const DUR_MAX_SECS: u64 = Duration::MAX.as_secs();
const NS_PER_SEC: u64 = 1_000_000_000;
let max_as_ns_secs = DUR_MAX_SECS / NS_PER_SEC;
let max_as_ns_ns = (DUR_MAX_SECS % NS_PER_SEC) as u32;
let max_as_ns = Duration::new(max_as_ns_secs, max_as_ns_ns);
assert_eq!(max_as_ns_secs, 18_446_744_073);
assert_eq!(max_as_ns_ns, 709_551_615);
assert_eq!(duration_as_ns(&max_as_ns), u64::MAX);
const US_PER_SEC: u64 = 1_000_000;
let max_as_us_secs = DUR_MAX_SECS / US_PER_SEC;
let max_as_us_ns = (DUR_MAX_SECS % US_PER_SEC) as u32;
let max_as_us = Duration::new(max_as_us_secs, max_as_us_ns * 1_000);
assert_eq!(max_as_us_secs, 18_446_744_073_709);
assert_eq!(max_as_us_ns, 551_615);
assert_eq!(duration_as_us(&max_as_us), u64::MAX);
const MS_PER_SEC: u64 = 1_000;
let max_as_ms_secs = DUR_MAX_SECS / MS_PER_SEC;
let max_as_ms_ns = (DUR_MAX_SECS % MS_PER_SEC) as u32;
let max_as_ms = Duration::new(max_as_ms_secs, max_as_ms_ns * 1_000_000);
assert_eq!(max_as_ms_secs, 18_446_744_073_709_551);
assert_eq!(max_as_ms_ns, 615);
assert_eq!(duration_as_ms(&max_as_ms), u64::MAX);
}
}