Skip to content

Commit 6b61655

Browse files
Rollup merge of #157328 - mathisbot:opt-std-windows-time, r=ChrisDenton
windows: Elide division-by-zero checks in Instant::now() This PR teaches LLVM that the frequency of the performance counter is non null so it is able to remove division by zero checks. This removes the panic path in `mul_div_u64` and should make calls to `Instant::now()` (very slightly) faster. As seen in the assembly (see godbolt below), telling LLVM that the frequency is non zero suffices to get the optimization, but I don't know if it could be a great idea to also update the signature of `mul_div_u64`? MSDN page for [QueryPerformanceFrequency](https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency): > On systems that run Windows XP or later, the function will always succeed when given valid parameters and will thus never return zero. Godbolt: https://rust.godbolt.org/z/xr6x8MrPE
2 parents cf688f2 + c2b9f39 commit 6b61655

1 file changed

Lines changed: 14 additions & 5 deletions

File tree

  • library/std/src/sys/pal/windows

library/std/src/sys/pal/windows/time.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub fn intervals2dur(intervals: u64) -> Duration {
2020

2121
pub mod perf_counter {
2222
use super::NANOS_PER_SEC;
23-
use crate::sync::atomic::{Atomic, AtomicU64, Ordering};
23+
use crate::sync::atomic::{AtomicI64, Ordering};
2424
use crate::sys::{c, cvt};
2525
use crate::time::Duration;
2626

@@ -32,23 +32,32 @@ pub mod perf_counter {
3232

3333
pub fn frequency() -> i64 {
3434
// Either the cached result of `QueryPerformanceFrequency` or `0` for
35-
// uninitialized. Storing this as a single `AtomicU64` allows us to use
35+
// uninitialized. Storing this as a single `AtomicI64` allows us to use
3636
// `Relaxed` operations, as we are only interested in the effects on a
3737
// single memory location.
38-
static FREQUENCY: Atomic<u64> = AtomicU64::new(0);
38+
static FREQUENCY: AtomicI64 = AtomicI64::new(0);
3939

4040
let cached = FREQUENCY.load(Ordering::Relaxed);
4141
// If a previous thread has filled in this global state, use that.
4242
if cached != 0 {
43-
return cached as i64;
43+
return cached;
4444
}
4545
// ... otherwise learn for ourselves ...
46+
frequency_init(&FREQUENCY)
47+
}
48+
49+
#[cold]
50+
fn frequency_init(cache: &AtomicI64) -> i64 {
4651
let mut frequency = 0;
4752
unsafe {
4853
cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap();
4954
}
5055

51-
FREQUENCY.store(frequency as u64, Ordering::Relaxed);
56+
// SAFETY: According to the MSDN entry for `QueryPerformanceFrequency`,
57+
// a value of 0 will never be returned starting from Windows XP.
58+
unsafe { crate::hint::assert_unchecked(frequency != 0) }
59+
60+
cache.store(frequency, Ordering::Relaxed);
5261
frequency
5362
}
5463

0 commit comments

Comments
 (0)