From 8ef3e227198f6ff674b1626d0862c4112358c1a1 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Wed, 14 May 2014 17:54:36 -0700 Subject: [PATCH] Optimize and fix time::precise_time_ns() on macos Use sync::one::Once to fetch the mach_timebase_info only once when running precise_time_ns(). This helps because mach_timebase_info() is surprisingly inefficient. Also fix the order of operations when applying the timebase to the mach absolute time value. This improves the time on my machine from ``` test tests::bench_precise_time_ns ... bench: 157 ns/iter (+/- 4) ``` to ``` test tests::bench_precise_time_ns ... bench: 38 ns/iter (+/- 3) ``` and it will get even faster once #14174 lands. --- mk/crates.mk | 2 +- src/libtime/lib.rs | 23 +++++++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 895819a5a50..4ac4abe9063 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -83,7 +83,7 @@ DEPS_fourcc := syntax std DEPS_hexfloat := syntax std DEPS_num := std rand DEPS_test := std collections getopts serialize term time regex -DEPS_time := std serialize +DEPS_time := std serialize sync DEPS_rand := std DEPS_url := std collections DEPS_workcache := std serialize collections log diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index 87a87641fc0..812985dd199 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -24,6 +24,8 @@ #[cfg(test)] #[phase(syntax, link)] extern crate log; extern crate serialize; extern crate libc; +#[cfg(target_os = "macos")] +extern crate sync; use std::io::BufReader; use std::num; @@ -159,10 +161,16 @@ pub fn precise_time_ns() -> u64 { #[cfg(target_os = "macos")] fn os_precise_time_ns() -> u64 { - let time = unsafe { imp::mach_absolute_time() }; - let mut info = libc::mach_timebase_info { numer: 0, denom: 0 }; - unsafe { imp::mach_timebase_info(&mut info); } - return time * ((info.numer / info.denom) as u64); + static mut TIMEBASE: libc::mach_timebase_info = libc::mach_timebase_info { numer: 0, + denom: 0 }; + static mut ONCE: sync::one::Once = sync::one::ONCE_INIT; + unsafe { + ONCE.doit(|| { + imp::mach_timebase_info(&mut TIMEBASE); + }); + let time = imp::mach_absolute_time(); + time * TIMEBASE.numer as u64 / TIMEBASE.denom as u64 + } } #[cfg(not(windows), not(target_os = "macos"))] @@ -1080,11 +1088,13 @@ pub fn strftime(format: &str, tm: &Tm) -> StrBuf { #[cfg(test)] mod tests { + extern crate test; use super::{Timespec, get_time, precise_time_ns, precise_time_s, tzset, at_utc, at, strptime}; use std::f64; use std::result::{Err, Ok}; + use self::test::Bencher; #[cfg(windows)] fn set_time_zone() { @@ -1520,4 +1530,9 @@ mod tests { test_strftime(); test_timespec_eq_ord(); } + + #[bench] + fn bench_precise_time_ns(b: &mut Bencher) { + b.iter(|| precise_time_ns()) + } }