diff options
| author | Manish Goregaokar <manishsmail@gmail.com> | 2015-02-27 11:43:51 +0530 |
|---|---|---|
| committer | Manish Goregaokar <manishsmail@gmail.com> | 2015-02-27 22:07:02 +0530 |
| commit | fb92e312d96be99610a45ae82d0c59ebe9306b31 (patch) | |
| tree | 1db9b42de0183ee9f2e259cfbdc309e7b1caa5ac /src/libstd/sys/windows | |
| parent | 08c25f37df936cf08cefd92baf08da9d0e2a1e09 (diff) | |
| parent | 5dd001b2fc06526222c89a8563b25e4850646c15 (diff) | |
| download | rust-fb92e312d96be99610a45ae82d0c59ebe9306b31.tar.gz rust-fb92e312d96be99610a45ae82d0c59ebe9306b31.zip | |
Rollup merge of #22788 - vadimcn:fix-precise_time_ns, r=pnkfelix
which starts happening after ~2 hours of machine uptime. Closes #17845
Diffstat (limited to 'src/libstd/sys/windows')
| -rw-r--r-- | src/libstd/sys/windows/time.rs | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 20ceff0aa69..209460df10b 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -12,6 +12,8 @@ use ops::Sub; 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 @@ impl 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); +} |
