authorgravatar for mail@linusgroh.deLinus Groh <mail@linusgroh.de> 2025-03-02 22:31:47+00:00
committergravatar for mail@linusgroh.deLinus Groh <mail@linusgroh.de> 2025-03-02 23:16:34+00:00
log3bea47883aae5c7585a27d4b751d656dd723576d
tree713474f6d4397ee82c11482c1e6fb2e3b9797120
parent1a03b8c8992d1a739363f289566334ba2a970cca

std.time: Make Instant.since() work on UEFI


1 files changed, 33 insertions(+), 31 deletions(-)

lib/std/time.zig+33-31
......@@ -135,7 +135,7 @@ pub const Instant = struct {
135135 const clock_id = switch (builtin.os.tag) {
136136 .windows => {
137137 // QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
138 return Instant{ .timestamp = windows.QueryPerformanceCounter() };
138 return .{ .timestamp = windows.QueryPerformanceCounter() };
139139 },
140140 .wasi => {
141141 var ns: std.os.wasi.timestamp_t = undefined;
......@@ -147,7 +147,7 @@ pub const Instant = struct {
147147 var value: std.os.uefi.Time = undefined;
148148 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
149149 if (status != .success) return error.Unsupported;
150 return Instant{ .timestamp = value.toEpoch() };
150 return .{ .timestamp = value.toEpoch() };
151151 },
152152 // On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while
153153 // suspended.
......@@ -185,36 +185,38 @@ pub const Instant = struct {
185185 /// This assumes that the `earlier` Instant represents a moment in time before or equal to `self`.
186186 /// This also assumes that the time that has passed between both Instants fits inside a u64 (~585 yrs).
187187 pub fn since(self: Instant, earlier: Instant) u64 {
188 if (builtin.os.tag == .windows) {
189 // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA
190 // (a read-only page of info updated and mapped by the kernel to all processes):
191 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
192 // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
193 const qpc = self.timestamp - earlier.timestamp;
194 const qpf = windows.QueryPerformanceFrequency();
195
196 // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
197 // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
198 const common_qpf = 10_000_000;
199 if (qpf == common_qpf) {
200 return qpc * (ns_per_s / common_qpf);
201 }
202
203 // Convert to ns using fixed point.
204 const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf));
205 const result = (@as(u96, qpc) * scale) >> 32;
206 return @as(u64, @truncate(result));
207 }
208
209 // WASI timestamps are directly in nanoseconds
210 if (builtin.os.tag == .wasi) {
211 return self.timestamp - earlier.timestamp;
188 switch (builtin.os.tag) {
189 .windows => {
190 // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA
191 // (a read-only page of info updated and mapped by the kernel to all processes):
192 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
193 // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
194 const qpc = self.timestamp - earlier.timestamp;
195 const qpf = windows.QueryPerformanceFrequency();
196
197 // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
198 // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
199 const common_qpf = 10_000_000;
200 if (qpf == common_qpf) {
201 return qpc * (ns_per_s / common_qpf);
202 }
203
204 // Convert to ns using fixed point.
205 const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf));
206 const result = (@as(u96, qpc) * scale) >> 32;
207 return @as(u64, @truncate(result));
208 },
209 .uefi, .wasi => {
210 // UEFI and WASI timestamps are directly in nanoseconds
211 return self.timestamp - earlier.timestamp;
212 },
213 else => {
214 // Convert timespec diff to ns
215 const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec));
216 const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec));
217 return elapsed - @as(u32, @intCast(earlier.timestamp.nsec));
218 },
212219 }
213
214 // Convert timespec diff to ns
215 const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec));
216 const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec));
217 return elapsed - @as(u32, @intCast(earlier.timestamp.nsec));
218220 }
219221};
220222