Skip to content

Commit e4be00f

Browse files
std.Io.Threaded: fix QueryPerformanceCounter usage
Co-authored-by: Andrew Kelley <andrew@ziglang.org>
1 parent 5816646 commit e4be00f

File tree

1 file changed

+16
-1
lines changed

1 file changed

+16
-1
lines changed

lib/std/Io/Threaded.zig

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2956,7 +2956,22 @@ fn nowWindows(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestam
29562956
},
29572957
.awake, .boot => {
29582958
// QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
2959-
return .{ .nanoseconds = windows.QueryPerformanceCounter() };
2959+
const qpc = windows.QueryPerformanceCounter();
2960+
// We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA
2961+
// (a read-only page of info updated and mapped by the kernel to all processes):
2962+
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
2963+
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
2964+
const qpf = windows.QueryPerformanceFrequency();
2965+
2966+
// 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
2967+
// https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
2968+
const common_qpf = 10_000_000;
2969+
if (qpf == common_qpf) return .{ .nanoseconds = qpc * (std.time.ns_per_s / common_qpf) };
2970+
2971+
// Convert to ns using fixed point.
2972+
const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf));
2973+
const result = (@as(u96, qpc) * scale) >> 32;
2974+
return .{ .nanoseconds = @intCast(result) };
29602975
},
29612976
.cpu_process,
29622977
.cpu_thread,

0 commit comments

Comments
 (0)