@ -13,10 +13,57 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
lazy_static ! {
static ref START_MONOTONIC : Instant = Instant ::now ( ) ;
static ref PERF_COUNTER_RES : u64 = get_perf_counter_resolution_ns ( ) ;
}
// Timer resolution on Windows is really hard. We may consider exposing the resolution of the respective
// timers as an associated function in the future.
pub ( crate ) fn clock_res_get ( clock_id : wasi ::__wasi_clockid_t ) -> Result < wasi ::__wasi_timestamp_t > {
unimplemented ! ( "clock_res_get" )
Ok ( match clock_id {
// This is the best that we can do with std::time::SystemTime.
// Rust uses GetSystemTimeAsFileTime, which is said to have the resolution of
// 10ms or 55ms, [1] but MSDN doesn't confirm this in any way.
// Even the MSDN article on high resolution timestamps doesn't even mention the precision
// for this method. [3]
//
// The timer resolution can be queried using one of the functions: [2, 5]
// * NtQueryTimerResolution, which is undocumented and thus not exposed by the winapi crate
// * timeGetDevCaps, which returns the upper and lower bound for the precision, in ms.
// While the upper bound seems like something we could use, it's typically too high to be meaningful.
// For instance, the intervals return by the syscall are:
// * [1, 65536] on Wine
// * [1, 1000000] on Windows 10, which is up to (sic) 1000 seconds.
//
// It's possible to manually set the timer resolution, but this sounds like something which should
// only be done temporarily. [5]
//
// Alternatively, we could possibly use GetSystemTimePreciseAsFileTime in clock_time_get, but
// this syscall is only available starting from Windows 8.
// (we could possibly emulate it on earlier versions of Windows, see [4])
// The MSDN are not clear on the resolution of GetSystemTimePreciseAsFileTime either, but a
// Microsoft devblog entry [1] suggests that it kind of combines GetSystemTimeAsFileTime with
// QueryPeformanceCounter, which probably means that those two should have the same resolution.
//
// See also this discussion about the use of GetSystemTimePreciseAsFileTime in Python stdlib,
// which in particular contains some resolution benchmarks.
//
// [1] https://devblogs.microsoft.com/oldnewthing/20170921-00/?p=97057
// [2] http://www.windowstimestamp.com/description
// [3] https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps?redirectedfrom=MSDN
// [4] https://www.codeproject.com/Tips/1011902/High-Resolution-Time-For-Windows
// [5] https://stackoverflow.com/questions/7685762/windows-7-timing-functions-how-to-use-getsystemtimeadjustment-correctly
// [6] https://bugs.python.org/issue19007
wasi ::__WASI_CLOCK_REALTIME = > 55_000_000 ,
// std::time::Instant uses QueryPerformanceCounter & QueryPerformanceFrequency internally
wasi ::__WASI_CLOCK_MONOTONIC = > * PERF_COUNTER_RES ,
// The best we can do is to hardcode the value from the docs.
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes
wasi ::__WASI_CLOCK_PROCESS_CPUTIME_ID = > 100 ,
// The best we can do is to hardcode the value from the docs.
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes
wasi ::__WASI_CLOCK_THREAD_CPUTIME_ID = > 100 ,
_ = > return Err ( Error ::EINVAL ) ,
} )
}
pub ( crate ) fn clock_time_get ( clock_id : wasi ::__wasi_clockid_t ) -> Result < wasi ::__wasi_timestamp_t > {
@ -61,3 +108,12 @@ fn get_proc_cputime() -> Result<Duration> {
fn get_thread_cputime ( ) -> Result < Duration > {
Ok ( ThreadTime ::try_now ( ) ? . as_duration ( ) )
}
fn get_perf_counter_resolution_ns ( ) -> u64 {
use winx ::time ::perf_counter_frequency ;
const NANOS_PER_SEC : u64 = 1_000_000_000 ;
// This should always succeed starting from Windows XP, so it's fine to panic in case of an error.
let freq = perf_counter_frequency ( ) . expect ( "QueryPerformanceFrequency returned an error" ) ;
let epsilon = NANOS_PER_SEC / freq ;
epsilon
}