Skip to content

Commit 0e8a1a4

Browse files
committed
Auto merge of #1294 - JOE1994:windows_instant, r=RalfJung
Add support for 'std::time::Instant' in Windows Add support for creating `std::time::Instant` in Windows Includes shims for `QueryPerformanceCounter` & `QueryPerformanceFrequency` in Windows, which are both called in Windows when `std::time::Instant` is created. Windows docs page ["Acquiring high-resolution time stamps"](https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps) was helpful in learning how `QueryPerformanceCounter` & `QueryPerformanceFrequency` work. closes #1291
2 parents 147ea8f + d5de67a commit 0e8a1a4

File tree

3 files changed

+53
-21
lines changed

3 files changed

+53
-21
lines changed

src/shims/foreign_items/windows.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2626
let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?;
2727
this.write_scalar(Scalar::from_u32(result), dest)?;
2828
}
29-
3029
"SetEnvironmentVariableW" => {
3130
let result = this.SetEnvironmentVariableW(args[0], args[1])?;
3231
this.write_scalar(Scalar::from_i32(result), dest)?;
3332
}
34-
3533
"GetEnvironmentStringsW" => {
3634
let result = this.GetEnvironmentStringsW()?;
3735
this.write_scalar(result, dest)?;
3836
}
39-
4037
"FreeEnvironmentStringsW" => {
4138
let result = this.FreeEnvironmentStringsW(args[0])?;
4239
this.write_scalar(Scalar::from_i32(result), dest)?;
4340
}
44-
4541
"GetCurrentDirectoryW" => {
4642
let result = this.GetCurrentDirectoryW(args[0], args[1])?;
4743
this.write_scalar(Scalar::from_u32(result), dest)?;
4844
}
49-
5045
"SetCurrentDirectoryW" => {
5146
let result = this.SetCurrentDirectoryW(args[0])?;
5247
this.write_scalar(Scalar::from_i32(result), dest)?;
@@ -173,6 +168,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
173168
"GetSystemTimeAsFileTime" => {
174169
this.GetSystemTimeAsFileTime(args[0])?;
175170
}
171+
"QueryPerformanceCounter" => {
172+
let result = this.QueryPerformanceCounter(args[0])?;
173+
this.write_scalar(Scalar::from_i32(result), dest)?;
174+
}
175+
"QueryPerformanceFrequency" => {
176+
let result = this.QueryPerformanceFrequency(args[0])?;
177+
this.write_scalar(Scalar::from_i32(result), dest)?;
178+
}
176179

177180
// Miscellaneous
178181
"SystemFunction036" => {

src/shims/time.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
115115
Ok(())
116116
}
117117

118+
#[allow(non_snake_case)]
119+
fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
120+
let this = self.eval_context_mut();
121+
122+
this.assert_target_os("windows", "QueryPerformanceCounter");
123+
this.check_no_isolation("QueryPerformanceCounter")?;
124+
125+
// QueryPerformanceCounter uses a hardware counter as its basis.
126+
// Miri will emulate a counter with a resolution of 1 nanosecond.
127+
let duration = Instant::now().duration_since(this.machine.time_anchor);
128+
let qpc = i64::try_from(duration.as_nanos())
129+
.map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?;
130+
this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?;
131+
Ok(-1) // return non-zero on success
132+
}
133+
134+
#[allow(non_snake_case)]
135+
fn QueryPerformanceFrequency(&mut self, lpFrequency_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
136+
let this = self.eval_context_mut();
137+
138+
this.assert_target_os("windows", "QueryPerformanceFrequency");
139+
this.check_no_isolation("QueryPerformanceFrequency")?;
140+
141+
// Retrieves the frequency of the hardware performance counter.
142+
// The frequency of the performance counter is fixed at system boot and
143+
// is consistent across all processors.
144+
// Miri emulates a "hardware" performance counter with a resolution of 1ns,
145+
// and thus 10^9 counts per second.
146+
this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?;
147+
Ok(-1) // Return non-zero on success
148+
}
149+
118150
fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
119151
let this = self.eval_context_ref();
120152

tests/run-pass/time.rs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,19 @@ fn main() {
1919
assert!(2020 <= year && year < 2100);
2020

2121
// Check `Instant`.
22-
#[cfg(not(windows))] // `Instant` shims not yet implemented on Windows
23-
{
24-
let now1 = Instant::now();
25-
// Do some work to make time pass.
26-
for _ in 0..10 { drop(vec![42]); }
27-
let now2 = Instant::now();
28-
assert!(now2 > now1);
22+
let now1 = Instant::now();
23+
// Do some work to make time pass.
24+
for _ in 0..10 { drop(vec![42]); }
25+
let now2 = Instant::now();
26+
assert!(now2 > now1);
2927

30-
#[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction
31-
{
32-
let diff = now2.duration_since(now1);
33-
assert_eq!(now1 + diff, now2);
34-
assert_eq!(now2 - diff, now1);
35-
// Sanity-check the difference we got.
36-
assert!(diff.as_micros() > 1);
37-
assert!(diff.as_micros() < 1_000_000);
38-
}
28+
#[cfg(not(target_os = "macos"))] // TODO: macOS does not support Instant subtraction
29+
{
30+
let diff = now2.duration_since(now1);
31+
assert_eq!(now1 + diff, now2);
32+
assert_eq!(now2 - diff, now1);
33+
// Sanity-check the difference we got.
34+
assert!(diff.as_micros() > 1);
35+
assert!(diff.as_micros() < 1_000_000);
3936
}
4037
}

0 commit comments

Comments
 (0)