Try to somehow implement clock_res_get on Windows. (#124)
* Implement clock_time_get on Windows. Also update misc_testsuite to include latest clock_time_get test changes. * Try to somehow implement clock_res_get on Windows. * Fix 55ms * Cache the perf counter resolution * Fix integration tests
This commit is contained in:
committed by
Jakub Konka
parent
3757b8b1c2
commit
22494057df
@@ -50,6 +50,9 @@ cranelift-codegen = "0.46.1"
|
|||||||
target-lexicon = "0.8.1"
|
target-lexicon = "0.8.1"
|
||||||
pretty_env_logger = "0.3.0"
|
pretty_env_logger = "0.3.0"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
# this is just a temp fix to make the tests build and run; I hope this to be
|
||||||
|
# completely removed when we merge `wasi-common` into `wasmtime`
|
||||||
|
faerie = "=0.11.0"
|
||||||
|
|
||||||
[patch."https://github.com/CraneStation/wasi-common"]
|
[patch."https://github.com/CraneStation/wasi-common"]
|
||||||
wasi-common = { path = "." }
|
wasi-common = { path = "." }
|
||||||
|
|||||||
@@ -13,10 +13,57 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
|||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref START_MONOTONIC: Instant = Instant::now();
|
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> {
|
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> {
|
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> {
|
fn get_thread_cputime() -> Result<Duration> {
|
||||||
Ok(ThreadTime::try_now()?.as_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
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
|
||||||
pub mod file;
|
pub mod file;
|
||||||
|
pub mod time;
|
||||||
pub mod winerror;
|
pub mod winerror;
|
||||||
|
|
||||||
use winerror::WinError;
|
use winerror::WinError;
|
||||||
|
|||||||
10
winx/src/time.rs
Normal file
10
winx/src/time.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
use cvt::cvt;
|
||||||
|
use winapi::um::{profileapi::QueryPerformanceFrequency, winnt::LARGE_INTEGER};
|
||||||
|
|
||||||
|
pub fn perf_counter_frequency() -> std::io::Result<u64> {
|
||||||
|
unsafe {
|
||||||
|
let mut frequency: LARGE_INTEGER = std::mem::zeroed();
|
||||||
|
cvt(QueryPerformanceFrequency(&mut frequency))?;
|
||||||
|
Ok(*frequency.QuadPart() as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user