Rollup merge of #22788 - vadimcn:fix-precise_time_ns, r=pnkfelix

which starts happening after ~2 hours of machine uptime.
Closes #17845
This commit is contained in:
Manish Goregaokar 2015-02-27 11:43:51 +05:30
commit fb92e312d9

View file

@ -12,6 +12,8 @@
use time::Duration;
use sync::{Once, ONCE_INIT};
const NANOS_PER_SEC: i64 = 1_000_000_000;
pub struct SteadyTime {
t: libc::LARGE_INTEGER,
}
@ -24,7 +26,7 @@ pub fn now() -> SteadyTime {
}
pub fn ns(&self) -> u64 {
self.t as u64 * 1_000_000_000 / frequency() as u64
mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64
}
}
@ -45,6 +47,27 @@ impl<'a> Sub for &'a SteadyTime {
fn sub(self, other: &SteadyTime) -> Duration {
let diff = self.t as i64 - other.t as i64;
Duration::microseconds(diff * 1_000_000 / frequency() as i64)
Duration::nanoseconds(mul_div_i64(diff, NANOS_PER_SEC, frequency() as i64))
}
}
// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 {
let q = value / denom;
let r = value % denom;
// Decompose value as (value/denom*denom + value%denom),
// substitute into (value*numer)/denom and simplify.
// r < denom, so (denom*numer) is the upper bound of (r*numer)
q * numer + r * numer / denom
}
#[test]
fn test_muldiv() {
assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000);
assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), -1_000_000_000_001_000);
assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 1_000_000_000_001_000);
assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), -1_000_000_000_001_000);
assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 1_000_000_000_001_000);
}