// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use libc; 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, } impl SteadyTime { pub fn now() -> SteadyTime { let mut t = SteadyTime { t: 0 }; unsafe { libc::QueryPerformanceCounter(&mut t.t); } t } pub fn ns(&self) -> u64 { mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64 } } fn frequency() -> libc::LARGE_INTEGER { static mut FREQUENCY: libc::LARGE_INTEGER = 0; static ONCE: Once = ONCE_INIT; unsafe { ONCE.call_once(|| { libc::QueryPerformanceFrequency(&mut FREQUENCY); }); FREQUENCY } } impl<'a> Sub for &'a SteadyTime { type Output = Duration; fn sub(self, other: &SteadyTime) -> Duration { let diff = self.t as i64 - other.t 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); }