diff options
| author | Linus Groh <mail@linusgroh.de> | 2025-03-02 22:31:47 +0000 |
|---|---|---|
| committer | Linus Groh <mail@linusgroh.de> | 2025-03-02 23:16:34 +0000 |
| commit | 3bea47883aae5c7585a27d4b751d656dd723576d (patch) | |
| tree | 713474f6d4397ee82c11482c1e6fb2e3b9797120 /lib | |
| parent | 1a03b8c8992d1a739363f289566334ba2a970cca (diff) | |
| download | zig-3bea47883aae5c7585a27d4b751d656dd723576d.tar.gz zig-3bea47883aae5c7585a27d4b751d656dd723576d.zip | |
std.time: Make Instant.since() work on UEFI
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/std/time.zig | 64 |
1 files changed, 33 insertions, 31 deletions
diff --git a/lib/std/time.zig b/lib/std/time.zig index b4fd271205..b9808cf747 100644 --- a/lib/std/time.zig +++ b/lib/std/time.zig @@ -135,7 +135,7 @@ pub const Instant = struct { const clock_id = switch (builtin.os.tag) { .windows => { // QPC on windows doesn't fail on >= XP/2000 and includes time suspended. - return Instant{ .timestamp = windows.QueryPerformanceCounter() }; + return .{ .timestamp = windows.QueryPerformanceCounter() }; }, .wasi => { var ns: std.os.wasi.timestamp_t = undefined; @@ -147,7 +147,7 @@ pub const Instant = struct { var value: std.os.uefi.Time = undefined; const status = std.os.uefi.system_table.runtime_services.getTime(&value, null); if (status != .success) return error.Unsupported; - return Instant{ .timestamp = value.toEpoch() }; + return .{ .timestamp = value.toEpoch() }; }, // On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while // suspended. @@ -185,36 +185,38 @@ pub const Instant = struct { /// This assumes that the `earlier` Instant represents a moment in time before or equal to `self`. /// This also assumes that the time that has passed between both Instants fits inside a u64 (~585 yrs). pub fn since(self: Instant, earlier: Instant) u64 { - if (builtin.os.tag == .windows) { - // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA - // (a read-only page of info updated and mapped by the kernel to all processes): - // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data - // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm - const qpc = self.timestamp - earlier.timestamp; - const qpf = windows.QueryPerformanceFrequency(); - - // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it. - // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701 - const common_qpf = 10_000_000; - if (qpf == common_qpf) { - return qpc * (ns_per_s / common_qpf); - } - - // Convert to ns using fixed point. - const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf)); - const result = (@as(u96, qpc) * scale) >> 32; - return @as(u64, @truncate(result)); - } - - // WASI timestamps are directly in nanoseconds - if (builtin.os.tag == .wasi) { - return self.timestamp - earlier.timestamp; + switch (builtin.os.tag) { + .windows => { + // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA + // (a read-only page of info updated and mapped by the kernel to all processes): + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data + // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm + const qpc = self.timestamp - earlier.timestamp; + const qpf = windows.QueryPerformanceFrequency(); + + // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it. + // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701 + const common_qpf = 10_000_000; + if (qpf == common_qpf) { + return qpc * (ns_per_s / common_qpf); + } + + // Convert to ns using fixed point. + const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf)); + const result = (@as(u96, qpc) * scale) >> 32; + return @as(u64, @truncate(result)); + }, + .uefi, .wasi => { + // UEFI and WASI timestamps are directly in nanoseconds + return self.timestamp - earlier.timestamp; + }, + else => { + // Convert timespec diff to ns + const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec)); + const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec)); + return elapsed - @as(u32, @intCast(earlier.timestamp.nsec)); + }, } - - // Convert timespec diff to ns - const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec)); - const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec)); - return elapsed - @as(u32, @intCast(earlier.timestamp.nsec)); } }; |
