Skip to content

Commit 8ef3e22

Browse files
committed
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 rust-lang#14174 lands.
1 parent 25c5422 commit 8ef3e22

File tree

2 files changed

+20
-5
lines changed

2 files changed

+20
-5
lines changed

mk/crates.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ DEPS_fourcc := syntax std
8383
DEPS_hexfloat := syntax std
8484
DEPS_num := std rand
8585
DEPS_test := std collections getopts serialize term time regex
86-
DEPS_time := std serialize
86+
DEPS_time := std serialize sync
8787
DEPS_rand := std
8888
DEPS_url := std collections
8989
DEPS_workcache := std serialize collections log

src/libtime/lib.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#[cfg(test)] #[phase(syntax, link)] extern crate log;
2525
extern crate serialize;
2626
extern crate libc;
27+
#[cfg(target_os = "macos")]
28+
extern crate sync;
2729

2830
use std::io::BufReader;
2931
use std::num;
@@ -159,10 +161,16 @@ pub fn precise_time_ns() -> u64 {
159161

160162
#[cfg(target_os = "macos")]
161163
fn os_precise_time_ns() -> u64 {
162-
let time = unsafe { imp::mach_absolute_time() };
163-
let mut info = libc::mach_timebase_info { numer: 0, denom: 0 };
164-
unsafe { imp::mach_timebase_info(&mut info); }
165-
return time * ((info.numer / info.denom) as u64);
164+
static mut TIMEBASE: libc::mach_timebase_info = libc::mach_timebase_info { numer: 0,
165+
denom: 0 };
166+
static mut ONCE: sync::one::Once = sync::one::ONCE_INIT;
167+
unsafe {
168+
ONCE.doit(|| {
169+
imp::mach_timebase_info(&mut TIMEBASE);
170+
});
171+
let time = imp::mach_absolute_time();
172+
time * TIMEBASE.numer as u64 / TIMEBASE.denom as u64
173+
}
166174
}
167175

168176
#[cfg(not(windows), not(target_os = "macos"))]
@@ -1080,11 +1088,13 @@ pub fn strftime(format: &str, tm: &Tm) -> StrBuf {
10801088

10811089
#[cfg(test)]
10821090
mod tests {
1091+
extern crate test;
10831092
use super::{Timespec, get_time, precise_time_ns, precise_time_s, tzset,
10841093
at_utc, at, strptime};
10851094

10861095
use std::f64;
10871096
use std::result::{Err, Ok};
1097+
use self::test::Bencher;
10881098

10891099
#[cfg(windows)]
10901100
fn set_time_zone() {
@@ -1520,4 +1530,9 @@ mod tests {
15201530
test_strftime();
15211531
test_timespec_eq_ord();
15221532
}
1533+
1534+
#[bench]
1535+
fn bench_precise_time_ns(b: &mut Bencher) {
1536+
b.iter(|| precise_time_ns())
1537+
}
15231538
}

0 commit comments

Comments
 (0)