| author | |
| committer | |
| log | c693c3ae5008c6ed14c4c2eb653b274b238bf6f1 |
| tree | 6dc248d8606088f7a288c00f6ccef78290229cf4 |
| parent | 4b1a8464715a9b2af1d9024694282883f3346482 |
| parent | 53d011fa1a7bfb2389e3677e1f6fcbe7a678e05f |
closes #523713 files changed, 194 insertions(+), 137 deletions(-)
lib/std/event/batch.zig+1-1| ... | @@ -122,7 +122,7 @@ test "std.event.Batch" { | ... | @@ -122,7 +122,7 @@ test "std.event.Batch" { |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | fn sleepALittle(count: *usize) void { | 124 | fn sleepALittle(count: *usize) void { |
| 125 | std.time.sleep(1 * std.time.millisecond); | 125 | std.time.sleep(1 * std.time.ns_per_ms); |
| 126 | _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); | 126 | _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); |
| 127 | } | 127 | } |
| 128 | 128 |
lib/std/event/group.zig+1-1| ... | @@ -145,7 +145,7 @@ fn testGroup(allocator: *Allocator) callconv(.Async) void { | ... | @@ -145,7 +145,7 @@ fn testGroup(allocator: *Allocator) callconv(.Async) void { |
| 145 | testing.expectError(error.ItBroke, another.wait()); | 145 | testing.expectError(error.ItBroke, another.wait()); |
| 146 | } | 146 | } |
| 147 | fn sleepALittle(count: *usize) callconv(.Async) void { | 147 | fn sleepALittle(count: *usize) callconv(.Async) void { |
| 148 | std.time.sleep(1 * std.time.millisecond); | 148 | std.time.sleep(1 * std.time.ns_per_ms); |
| 149 | _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); | 149 | _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); |
| 150 | } | 150 | } |
| 151 | fn increaseByTen(count: *usize) callconv(.Async) void { | 151 | fn increaseByTen(count: *usize) callconv(.Async) void { |
lib/std/event/loop.zig+1-1| ... | @@ -457,7 +457,7 @@ pub const Loop = struct { | ... | @@ -457,7 +457,7 @@ pub const Loop = struct { |
| 457 | => { | 457 | => { |
| 458 | // Even poll() didn't work. The best we can do now is sleep for a | 458 | // Even poll() didn't work. The best we can do now is sleep for a |
| 459 | // small duration and then hope that something changed. | 459 | // small duration and then hope that something changed. |
| 460 | std.time.sleep(1 * std.time.millisecond); | 460 | std.time.sleep(1 * std.time.ns_per_ms); |
| 461 | }, | 461 | }, |
| 462 | }; | 462 | }; |
| 463 | resume @frame(); | 463 | resume @frame(); |
lib/std/fs/file.zig+11-13| ... | @@ -227,14 +227,12 @@ pub const File = struct { | ... | @@ -227,14 +227,12 @@ pub const File = struct { |
| 227 | size: u64, | 227 | size: u64, |
| 228 | mode: Mode, | 228 | mode: Mode, |
| 229 | 229 | ||
| 230 | /// access time in nanoseconds | 230 | /// Access time in nanoseconds, relative to UTC 1970-01-01. |
| 231 | atime: i64, | 231 | atime: i128, |
| 232 | 232 | /// Last modification time in nanoseconds, relative to UTC 1970-01-01. | |
| 233 | /// last modification time in nanoseconds | 233 | mtime: i128, |
| 234 | mtime: i64, | 234 | /// Creation time in nanoseconds, relative to UTC 1970-01-01. |
| 235 | 235 | ctime: i128, | |
| 236 | /// creation time in nanoseconds | ||
| 237 | ctime: i64, | ||
| 238 | }; | 236 | }; |
| 239 | 237 | ||
| 240 | pub const StatError = os.FStatError; | 238 | pub const StatError = os.FStatError; |
| ... | @@ -270,9 +268,9 @@ pub const File = struct { | ... | @@ -270,9 +268,9 @@ pub const File = struct { |
| 270 | .inode = st.ino, | 268 | .inode = st.ino, |
| 271 | .size = @bitCast(u64, st.size), | 269 | .size = @bitCast(u64, st.size), |
| 272 | .mode = st.mode, | 270 | .mode = st.mode, |
| 273 | .atime = @as(i64, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec, | 271 | .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec, |
| 274 | .mtime = @as(i64, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec, | 272 | .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec, |
| 275 | .ctime = @as(i64, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec, | 273 | .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec, |
| 276 | }; | 274 | }; |
| 277 | } | 275 | } |
| 278 | 276 | ||
| ... | @@ -286,9 +284,9 @@ pub const File = struct { | ... | @@ -286,9 +284,9 @@ pub const File = struct { |
| 286 | pub fn updateTimes( | 284 | pub fn updateTimes( |
| 287 | self: File, | 285 | self: File, |
| 288 | /// access timestamp in nanoseconds | 286 | /// access timestamp in nanoseconds |
| 289 | atime: i64, | 287 | atime: i128, |
| 290 | /// last modification timestamp in nanoseconds | 288 | /// last modification timestamp in nanoseconds |
| 291 | mtime: i64, | 289 | mtime: i128, |
| 292 | ) UpdateTimesError!void { | 290 | ) UpdateTimesError!void { |
| 293 | if (builtin.os.tag == .windows) { | 291 | if (builtin.os.tag == .windows) { |
| 294 | const atime_ft = windows.nanoSecondsToFileTime(atime); | 292 | const atime_ft = windows.nanoSecondsToFileTime(atime); |
lib/std/fs/test.zig+3-3| ... | @@ -10,7 +10,7 @@ test "openSelfExe" { | ... | @@ -10,7 +10,7 @@ test "openSelfExe" { |
| 10 | self_exe_file.close(); | 10 | self_exe_file.close(); |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | const FILE_LOCK_TEST_SLEEP_TIME = 5 * std.time.millisecond; | 13 | const FILE_LOCK_TEST_SLEEP_TIME = 5 * std.time.ns_per_ms; |
| 14 | 14 | ||
| 15 | test "open file with exclusive nonblocking lock twice" { | 15 | test "open file with exclusive nonblocking lock twice" { |
| 16 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 16 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| ... | @@ -142,8 +142,8 @@ const FileLockTestContext = struct { | ... | @@ -142,8 +142,8 @@ const FileLockTestContext = struct { |
| 142 | 142 | ||
| 143 | // Output variables | 143 | // Output variables |
| 144 | err: ?(File.OpenError || std.os.ReadError) = null, | 144 | err: ?(File.OpenError || std.os.ReadError) = null, |
| 145 | start_time: u64 = 0, | 145 | start_time: i64 = 0, |
| 146 | end_time: u64 = 0, | 146 | end_time: i64 = 0, |
| 147 | bytes_read: ?usize = null, | 147 | bytes_read: ?usize = null, |
| 148 | 148 | ||
| 149 | fn overlaps(self: *const @This(), other: *const @This()) bool { | 149 | fn overlaps(self: *const @This(), other: *const @This()) bool { |
lib/std/net.zig+2-2| ... | @@ -1135,13 +1135,13 @@ fn resMSendRc( | ... | @@ -1135,13 +1135,13 @@ fn resMSendRc( |
| 1135 | }}; | 1135 | }}; |
| 1136 | const retry_interval = timeout / attempts; | 1136 | const retry_interval = timeout / attempts; |
| 1137 | var next: u32 = 0; | 1137 | var next: u32 = 0; |
| 1138 | var t2: u64 = std.time.milliTimestamp(); | 1138 | var t2: u64 = @bitCast(u64, std.time.milliTimestamp()); |
| 1139 | var t0 = t2; | 1139 | var t0 = t2; |
| 1140 | var t1 = t2 - retry_interval; | 1140 | var t1 = t2 - retry_interval; |
| 1141 | 1141 | ||
| 1142 | var servfail_retry: usize = undefined; | 1142 | var servfail_retry: usize = undefined; |
| 1143 | 1143 | ||
| 1144 | outer: while (t2 - t0 < timeout) : (t2 = std.time.milliTimestamp()) { | 1144 | outer: while (t2 - t0 < timeout) : (t2 = @bitCast(u64, std.time.milliTimestamp())) { |
| 1145 | if (t2 - t1 >= retry_interval) { | 1145 | if (t2 - t1 >= retry_interval) { |
| 1146 | // Query all configured nameservers in parallel | 1146 | // Query all configured nameservers in parallel |
| 1147 | var i: usize = 0; | 1147 | var i: usize = 0; |
lib/std/os.zig+19| ... | @@ -3880,6 +3880,8 @@ pub fn dl_iterate_phdr( | ... | @@ -3880,6 +3880,8 @@ pub fn dl_iterate_phdr( |
| 3880 | 3880 | ||
| 3881 | pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; | 3881 | pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; |
| 3882 | 3882 | ||
| 3883 | /// TODO: change this to return the timespec as a return value | ||
| 3884 | /// TODO: look into making clk_id an enum | ||
| 3883 | pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { | 3885 | pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { |
| 3884 | if (std.Target.current.os.tag == .wasi) { | 3886 | if (std.Target.current.os.tag == .wasi) { |
| 3885 | var ts: timestamp_t = undefined; | 3887 | var ts: timestamp_t = undefined; |
| ... | @@ -3895,6 +3897,23 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { | ... | @@ -3895,6 +3897,23 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { |
| 3895 | } | 3897 | } |
| 3896 | return; | 3898 | return; |
| 3897 | } | 3899 | } |
| 3900 | if (std.Target.current.os.tag == .windows) { | ||
| 3901 | if (clk_id == CLOCK_REALTIME) { | ||
| 3902 | var ft: windows.FILETIME = undefined; | ||
| 3903 | windows.kernel32.GetSystemTimeAsFileTime(&ft); | ||
| 3904 | // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch. | ||
| 3905 | const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; | ||
| 3906 | const ft_per_s = std.time.ns_per_s / 100; | ||
| 3907 | tp.* = .{ | ||
| 3908 | .tv_sec = @intCast(i64, ft64 / ft_per_s) + std.time.epoch.windows, | ||
| 3909 | .tv_nsec = @intCast(c_long, ft64 % ft_per_s) * 100, | ||
| 3910 | }; | ||
| 3911 | return; | ||
| 3912 | } else { | ||
| 3913 | // TODO POSIX implementation of CLOCK_MONOTONIC on Windows. | ||
| 3914 | return error.UnsupportedClock; | ||
| 3915 | } | ||
| 3916 | } | ||
| 3898 | 3917 | ||
| 3899 | switch (errno(system.clock_gettime(clk_id, tp))) { | 3918 | switch (errno(system.clock_gettime(clk_id, tp))) { |
| 3900 | 0 => return, | 3919 | 0 => return, |
lib/std/os/bits/darwin.zig+9| ... | @@ -1456,3 +1456,12 @@ pub const POLLHUP = 0x010; | ... | @@ -1456,3 +1456,12 @@ pub const POLLHUP = 0x010; |
| 1456 | pub const POLLNVAL = 0x020; | 1456 | pub const POLLNVAL = 0x020; |
| 1457 | 1457 | ||
| 1458 | pub const POLLSTANDARD = POLLIN | POLLPRI | POLLOUT | POLLRDNORM | POLLRDBAND | POLLWRBAND | POLLERR | POLLHUP | POLLNVAL; | 1458 | pub const POLLSTANDARD = POLLIN | POLLPRI | POLLOUT | POLLRDNORM | POLLRDBAND | POLLWRBAND | POLLERR | POLLHUP | POLLNVAL; |
| 1459 | |||
| 1460 | pub const CLOCK_REALTIME = 0; | ||
| 1461 | pub const CLOCK_MONOTONIC = 6; | ||
| 1462 | pub const CLOCK_MONOTONIC_RAW = 4; | ||
| 1463 | pub const CLOCK_MONOTONIC_RAW_APPROX = 5; | ||
| 1464 | pub const CLOCK_UPTIME_RAW = 8; | ||
| 1465 | pub const CLOCK_UPTIME_RAW_APPROX = 9; | ||
| 1466 | pub const CLOCK_PROCESS_CPUTIME_ID = 12; | ||
| 1467 | pub const CLOCK_THREAD_CPUTIME_ID = 16; |
lib/std/os/windows.zig+7-7| ... | @@ -1193,23 +1193,23 @@ pub fn peb() *PEB { | ... | @@ -1193,23 +1193,23 @@ pub fn peb() *PEB { |
| 1193 | /// Universal Time (UTC). | 1193 | /// Universal Time (UTC). |
| 1194 | /// This function returns the number of nanoseconds since the canonical epoch, | 1194 | /// This function returns the number of nanoseconds since the canonical epoch, |
| 1195 | /// which is the POSIX one (Jan 01, 1970 AD). | 1195 | /// which is the POSIX one (Jan 01, 1970 AD). |
| 1196 | pub fn fromSysTime(hns: i64) i64 { | 1196 | pub fn fromSysTime(hns: i64) i128 { |
| 1197 | const adjusted_epoch = hns + std.time.epoch.windows * (std.time.ns_per_s / 100); | 1197 | const adjusted_epoch = @as(i128, hns + std.time.epoch.windows) * (std.time.ns_per_s / 100); |
| 1198 | return adjusted_epoch * 100; | 1198 | return adjusted_epoch * 100; |
| 1199 | } | 1199 | } |
| 1200 | 1200 | ||
| 1201 | pub fn toSysTime(ns: i64) i64 { | 1201 | pub fn toSysTime(ns: i128) i64 { |
| 1202 | const hns = @divFloor(ns, 100); | 1202 | const hns = @divFloor(ns, 100); |
| 1203 | return hns - std.time.epoch.windows * (std.time.ns_per_s / 100); | 1203 | return @intCast(i64, hns) - std.time.epoch.windows * (std.time.ns_per_s / 100); |
| 1204 | } | 1204 | } |
| 1205 | 1205 | ||
| 1206 | pub fn fileTimeToNanoSeconds(ft: FILETIME) i64 { | 1206 | pub fn fileTimeToNanoSeconds(ft: FILETIME) i128 { |
| 1207 | const hns = @bitCast(i64, (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime); | 1207 | const hns = (@as(i64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; |
| 1208 | return fromSysTime(hns); | 1208 | return fromSysTime(hns); |
| 1209 | } | 1209 | } |
| 1210 | 1210 | ||
| 1211 | /// Converts a number of nanoseconds since the POSIX epoch to a Windows FILETIME. | 1211 | /// Converts a number of nanoseconds since the POSIX epoch to a Windows FILETIME. |
| 1212 | pub fn nanoSecondsToFileTime(ns: i64) FILETIME { | 1212 | pub fn nanoSecondsToFileTime(ns: i128) FILETIME { |
| 1213 | const adjusted = @bitCast(u64, toSysTime(ns)); | 1213 | const adjusted = @bitCast(u64, toSysTime(ns)); |
| 1214 | return FILETIME{ | 1214 | return FILETIME{ |
| 1215 | .dwHighDateTime = @truncate(u32, adjusted >> 32), | 1215 | .dwHighDateTime = @truncate(u32, adjusted >> 32), |
lib/std/progress.zig+8-8| ... | @@ -31,10 +31,10 @@ pub const Progress = struct { | ... | @@ -31,10 +31,10 @@ pub const Progress = struct { |
| 31 | output_buffer: [100]u8 = undefined, | 31 | output_buffer: [100]u8 = undefined, |
| 32 | 32 | ||
| 33 | /// How many nanoseconds between writing updates to the terminal. | 33 | /// How many nanoseconds between writing updates to the terminal. |
| 34 | refresh_rate_ns: u64 = 50 * std.time.millisecond, | 34 | refresh_rate_ns: u64 = 50 * std.time.ns_per_ms, |
| 35 | 35 | ||
| 36 | /// How many nanoseconds to keep the output hidden | 36 | /// How many nanoseconds to keep the output hidden |
| 37 | initial_delay_ns: u64 = 500 * std.time.millisecond, | 37 | initial_delay_ns: u64 = 500 * std.time.ns_per_ms, |
| 38 | 38 | ||
| 39 | done: bool = true, | 39 | done: bool = true, |
| 40 | 40 | ||
| ... | @@ -282,24 +282,24 @@ test "basic functionality" { | ... | @@ -282,24 +282,24 @@ test "basic functionality" { |
| 282 | next_sub_task = (next_sub_task + 1) % sub_task_names.len; | 282 | next_sub_task = (next_sub_task + 1) % sub_task_names.len; |
| 283 | 283 | ||
| 284 | node.completeOne(); | 284 | node.completeOne(); |
| 285 | std.time.sleep(5 * std.time.millisecond); | 285 | std.time.sleep(5 * std.time.ns_per_ms); |
| 286 | node.completeOne(); | 286 | node.completeOne(); |
| 287 | node.completeOne(); | 287 | node.completeOne(); |
| 288 | std.time.sleep(5 * std.time.millisecond); | 288 | std.time.sleep(5 * std.time.ns_per_ms); |
| 289 | node.completeOne(); | 289 | node.completeOne(); |
| 290 | node.completeOne(); | 290 | node.completeOne(); |
| 291 | std.time.sleep(5 * std.time.millisecond); | 291 | std.time.sleep(5 * std.time.ns_per_ms); |
| 292 | 292 | ||
| 293 | node.end(); | 293 | node.end(); |
| 294 | 294 | ||
| 295 | std.time.sleep(5 * std.time.millisecond); | 295 | std.time.sleep(5 * std.time.ns_per_ms); |
| 296 | } | 296 | } |
| 297 | { | 297 | { |
| 298 | var node = root_node.start("this is a really long name designed to activate the truncation code. let's find out if it works", null); | 298 | var node = root_node.start("this is a really long name designed to activate the truncation code. let's find out if it works", null); |
| 299 | node.activate(); | 299 | node.activate(); |
| 300 | std.time.sleep(10 * std.time.millisecond); | 300 | std.time.sleep(10 * std.time.ns_per_ms); |
| 301 | progress.refresh(); | 301 | progress.refresh(); |
| 302 | std.time.sleep(10 * std.time.millisecond); | 302 | std.time.sleep(10 * std.time.ns_per_ms); |
| 303 | node.end(); | 303 | node.end(); |
| 304 | } | 304 | } |
| 305 | } | 305 | } |
lib/std/reset_event.zig+5-5| ... | @@ -152,15 +152,15 @@ const PosixEvent = struct { | ... | @@ -152,15 +152,15 @@ const PosixEvent = struct { |
| 152 | if (comptime std.Target.current.isDarwin()) { | 152 | if (comptime std.Target.current.isDarwin()) { |
| 153 | var tv: os.darwin.timeval = undefined; | 153 | var tv: os.darwin.timeval = undefined; |
| 154 | assert(os.darwin.gettimeofday(&tv, null) == 0); | 154 | assert(os.darwin.gettimeofday(&tv, null) == 0); |
| 155 | timeout_abs += @intCast(u64, tv.tv_sec) * time.second; | 155 | timeout_abs += @intCast(u64, tv.tv_sec) * time.ns_per_s; |
| 156 | timeout_abs += @intCast(u64, tv.tv_usec) * time.microsecond; | 156 | timeout_abs += @intCast(u64, tv.tv_usec) * time.us_per_s; |
| 157 | } else { | 157 | } else { |
| 158 | os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable; | 158 | os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable; |
| 159 | timeout_abs += @intCast(u64, ts.tv_sec) * time.second; | 159 | timeout_abs += @intCast(u64, ts.tv_sec) * time.ns_per_s; |
| 160 | timeout_abs += @intCast(u64, ts.tv_nsec); | 160 | timeout_abs += @intCast(u64, ts.tv_nsec); |
| 161 | } | 161 | } |
| 162 | ts.tv_sec = @intCast(@TypeOf(ts.tv_sec), @divFloor(timeout_abs, time.second)); | 162 | ts.tv_sec = @intCast(@TypeOf(ts.tv_sec), @divFloor(timeout_abs, time.ns_per_s)); |
| 163 | ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), @mod(timeout_abs, time.second)); | 163 | ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), @mod(timeout_abs, time.ns_per_s)); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | while (!self.is_set) { | 166 | while (!self.is_set) { |
lib/std/time.zig+104-84| ... | @@ -4,16 +4,14 @@ const assert = std.debug.assert; | ... | @@ -4,16 +4,14 @@ const assert = std.debug.assert; |
| 4 | const testing = std.testing; | 4 | const testing = std.testing; |
| 5 | const os = std.os; | 5 | const os = std.os; |
| 6 | const math = std.math; | 6 | const math = std.math; |
| 7 | const is_windows = std.Target.current.os.tag == .windows; | ||
| 7 | 8 | ||
| 8 | pub const epoch = @import("time/epoch.zig"); | 9 | pub const epoch = @import("time/epoch.zig"); |
| 9 | 10 | ||
| 10 | const is_windows = std.Target.current.os.tag == .windows; | ||
| 11 | |||
| 12 | /// Spurious wakeups are possible and no precision of timing is guaranteed. | 11 | /// Spurious wakeups are possible and no precision of timing is guaranteed. |
| 13 | /// TODO integrate with evented I/O | 12 | /// TODO integrate with evented I/O |
| 14 | pub fn sleep(nanoseconds: u64) void { | 13 | pub fn sleep(nanoseconds: u64) void { |
| 15 | if (is_windows) { | 14 | if (is_windows) { |
| 16 | const ns_per_ms = ns_per_s / ms_per_s; | ||
| 17 | const big_ms_from_ns = nanoseconds / ns_per_ms; | 15 | const big_ms_from_ns = nanoseconds / ns_per_ms; |
| 18 | const ms = math.cast(os.windows.DWORD, big_ms_from_ns) catch math.maxInt(os.windows.DWORD); | 16 | const ms = math.cast(os.windows.DWORD, big_ms_from_ns) catch math.maxInt(os.windows.DWORD); |
| 19 | os.windows.kernel32.Sleep(ms); | 17 | os.windows.kernel32.Sleep(ms); |
| ... | @@ -49,69 +47,78 @@ pub fn sleep(nanoseconds: u64) void { | ... | @@ -49,69 +47,78 @@ pub fn sleep(nanoseconds: u64) void { |
| 49 | std.os.nanosleep(s, ns); | 47 | std.os.nanosleep(s, ns); |
| 50 | } | 48 | } |
| 51 | 49 | ||
| 52 | /// Get the posix timestamp, UTC, in seconds | 50 | /// Get a calendar timestamp, in seconds, relative to UTC 1970-01-01. |
| 53 | /// TODO audit this function. is it possible to return an error? | 51 | /// Precision of timing depends on the hardware and operating system. |
| 54 | pub fn timestamp() u64 { | 52 | /// The return value is signed because it is possible to have a date that is |
| 55 | return @divFloor(milliTimestamp(), ms_per_s); | 53 | /// before the epoch. |
| 54 | /// See `std.os.clock_gettime` for a POSIX timestamp. | ||
| 55 | pub fn timestamp() i64 { | ||
| 56 | return @divFloor(milliTimestamp(), ns_per_s); | ||
| 57 | } | ||
| 58 | |||
| 59 | /// Get a calendar timestamp, in milliseconds, relative to UTC 1970-01-01. | ||
| 60 | /// Precision of timing depends on the hardware and operating system. | ||
| 61 | /// The return value is signed because it is possible to have a date that is | ||
| 62 | /// before the epoch. | ||
| 63 | /// See `std.os.clock_gettime` for a POSIX timestamp. | ||
| 64 | pub fn milliTimestamp() i64 { | ||
| 65 | return @intCast(i64, @divFloor(nanoTimestamp(), ns_per_ms)); | ||
| 56 | } | 66 | } |
| 57 | 67 | ||
| 58 | /// Get the posix timestamp, UTC, in milliseconds | 68 | /// Get a calendar timestamp, in nanoseconds, relative to UTC 1970-01-01. |
| 59 | /// TODO audit this function. is it possible to return an error? | 69 | /// Precision of timing depends on the hardware and operating system. |
| 60 | pub fn milliTimestamp() u64 { | 70 | /// On Windows this has a maximum granularity of 100 nanoseconds. |
| 71 | /// The return value is signed because it is possible to have a date that is | ||
| 72 | /// before the epoch. | ||
| 73 | /// See `std.os.clock_gettime` for a POSIX timestamp. | ||
| 74 | pub fn nanoTimestamp() i128 { | ||
| 61 | if (is_windows) { | 75 | if (is_windows) { |
| 62 | //FileTime has a granularity of 100 nanoseconds | 76 | // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch, |
| 63 | // and uses the NTFS/Windows epoch | 77 | // which is 1601-01-01. |
| 78 | const epoch_adj = epoch.windows * (ns_per_s / 100); | ||
| 64 | var ft: os.windows.FILETIME = undefined; | 79 | var ft: os.windows.FILETIME = undefined; |
| 65 | os.windows.kernel32.GetSystemTimeAsFileTime(&ft); | 80 | os.windows.kernel32.GetSystemTimeAsFileTime(&ft); |
| 66 | const hns_per_ms = (ns_per_s / 100) / ms_per_s; | ||
| 67 | const epoch_adj = epoch.windows * ms_per_s; | ||
| 68 | |||
| 69 | const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; | 81 | const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; |
| 70 | return @divFloor(ft64, hns_per_ms) - -epoch_adj; | 82 | return @as(i128, @bitCast(i64, ft64) + epoch_adj) * 100; |
| 71 | } | 83 | } |
| 72 | if (builtin.os.tag == .wasi and !builtin.link_libc) { | 84 | if (builtin.os.tag == .wasi and !builtin.link_libc) { |
| 73 | var ns: os.wasi.timestamp_t = undefined; | 85 | var ns: os.wasi.timestamp_t = undefined; |
| 74 | |||
| 75 | // TODO: Verify that precision is ignored | ||
| 76 | const err = os.wasi.clock_time_get(os.wasi.CLOCK_REALTIME, 1, &ns); | 86 | const err = os.wasi.clock_time_get(os.wasi.CLOCK_REALTIME, 1, &ns); |
| 77 | assert(err == os.wasi.ESUCCESS); | 87 | assert(err == os.wasi.ESUCCESS); |
| 78 | 88 | return ns; | |
| 79 | const ns_per_ms = 1000; | ||
| 80 | return @divFloor(ns, ns_per_ms); | ||
| 81 | } | ||
| 82 | if (comptime std.Target.current.isDarwin()) { | ||
| 83 | var tv: os.darwin.timeval = undefined; | ||
| 84 | var err = os.darwin.gettimeofday(&tv, null); | ||
| 85 | assert(err == 0); | ||
| 86 | const sec_ms = tv.tv_sec * ms_per_s; | ||
| 87 | const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s); | ||
| 88 | return @intCast(u64, sec_ms + usec_ms); | ||
| 89 | } | 89 | } |
| 90 | var ts: os.timespec = undefined; | 90 | var ts: os.timespec = undefined; |
| 91 | //From what I can tell there's no reason clock_gettime | 91 | os.clock_gettime(os.CLOCK_REALTIME, &ts) catch |err| switch (err) { |
| 92 | // should ever fail for us with CLOCK_REALTIME, | 92 | error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS". |
| 93 | // seccomp aside. | 93 | }; |
| 94 | os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable; | 94 | return (@as(i128, ts.tv_sec) * ns_per_s) + ts.tv_nsec; |
| 95 | const sec_ms = @intCast(u64, ts.tv_sec) * ms_per_s; | ||
| 96 | const nsec_ms = @divFloor(@intCast(u64, ts.tv_nsec), ns_per_s / ms_per_s); | ||
| 97 | return sec_ms + nsec_ms; | ||
| 98 | } | 95 | } |
| 99 | 96 | ||
| 100 | /// Multiples of a base unit (nanoseconds) | 97 | // Divisions of a nanosecond. |
| 101 | pub const nanosecond = 1; | 98 | pub const ns_per_us = 1000; |
| 102 | pub const microsecond = 1000 * nanosecond; | 99 | pub const ns_per_ms = 1000 * ns_per_us; |
| 103 | pub const millisecond = 1000 * microsecond; | 100 | pub const ns_per_s = 1000 * ns_per_ms; |
| 104 | pub const second = 1000 * millisecond; | 101 | pub const ns_per_min = 60 * ns_per_s; |
| 105 | pub const minute = 60 * second; | 102 | pub const ns_per_hour = 60 * ns_per_min; |
| 106 | pub const hour = 60 * minute; | 103 | pub const ns_per_day = 24 * ns_per_hour; |
| 107 | 104 | pub const ns_per_week = 7 * ns_per_day; | |
| 108 | /// Divisions of a second | 105 | |
| 109 | pub const ns_per_s = 1000000000; | 106 | // Divisions of a microsecond. |
| 110 | pub const us_per_s = 1000000; | 107 | pub const us_per_ms = 1000; |
| 108 | pub const us_per_s = 1000 * us_per_ms; | ||
| 109 | pub const us_per_min = 60 * us_per_s; | ||
| 110 | pub const us_per_hour = 60 * us_per_min; | ||
| 111 | pub const us_per_day = 24 * us_per_hour; | ||
| 112 | pub const us_per_week = 7 * us_per_day; | ||
| 113 | |||
| 114 | // Divisions of a millisecond. | ||
| 111 | pub const ms_per_s = 1000; | 115 | pub const ms_per_s = 1000; |
| 112 | pub const cs_per_s = 100; | 116 | pub const ms_per_min = 60 * ms_per_s; |
| 117 | pub const ms_per_hour = 60 * ms_per_min; | ||
| 118 | pub const ms_per_day = 24 * ms_per_hour; | ||
| 119 | pub const ms_per_week = 7 * ms_per_day; | ||
| 113 | 120 | ||
| 114 | /// Common time divisions | 121 | // Divisions of a second. |
| 115 | pub const s_per_min = 60; | 122 | pub const s_per_min = 60; |
| 116 | pub const s_per_hour = s_per_min * 60; | 123 | pub const s_per_hour = s_per_min * 60; |
| 117 | pub const s_per_day = s_per_hour * 24; | 124 | pub const s_per_day = s_per_hour * 24; |
| ... | @@ -119,12 +126,12 @@ pub const s_per_week = s_per_day * 7; | ... | @@ -119,12 +126,12 @@ pub const s_per_week = s_per_day * 7; |
| 119 | 126 | ||
| 120 | /// A monotonic high-performance timer. | 127 | /// A monotonic high-performance timer. |
| 121 | /// Timer.start() must be called to initialize the struct, which captures | 128 | /// Timer.start() must be called to initialize the struct, which captures |
| 122 | /// the counter frequency on windows and darwin, records the resolution, | 129 | /// the counter frequency on windows and darwin, records the resolution, |
| 123 | /// and gives the user an opportunity to check for the existnece of | 130 | /// and gives the user an opportunity to check for the existnece of |
| 124 | /// monotonic clocks without forcing them to check for error on each read. | 131 | /// monotonic clocks without forcing them to check for error on each read. |
| 125 | /// .resolution is in nanoseconds on all platforms but .start_time's meaning | 132 | /// .resolution is in nanoseconds on all platforms but .start_time's meaning |
| 126 | /// depends on the OS. On Windows and Darwin it is a hardware counter | 133 | /// depends on the OS. On Windows and Darwin it is a hardware counter |
| 127 | /// value that requires calculation to convert to a meaninful unit. | 134 | /// value that requires calculation to convert to a meaninful unit. |
| 128 | pub const Timer = struct { | 135 | pub const Timer = struct { |
| 129 | ///if we used resolution's value when performing the | 136 | ///if we used resolution's value when performing the |
| 130 | /// performance counter calc on windows/darwin, it would | 137 | /// performance counter calc on windows/darwin, it would |
| ... | @@ -137,43 +144,58 @@ pub const Timer = struct { | ... | @@ -137,43 +144,58 @@ pub const Timer = struct { |
| 137 | resolution: u64, | 144 | resolution: u64, |
| 138 | start_time: u64, | 145 | start_time: u64, |
| 139 | 146 | ||
| 140 | const Error = error{TimerUnsupported}; | 147 | pub const Error = error{TimerUnsupported}; |
| 141 | 148 | ||
| 142 | ///At some point we may change our minds on RAW, but for now we're | 149 | /// At some point we may change our minds on RAW, but for now we're |
| 143 | /// sticking with posix standard MONOTONIC. For more information, see: | 150 | /// sticking with posix standard MONOTONIC. For more information, see: |
| 144 | /// https://github.com/ziglang/zig/pull/933 | 151 | /// https://github.com/ziglang/zig/pull/933 |
| 145 | const monotonic_clock_id = os.CLOCK_MONOTONIC; | 152 | const monotonic_clock_id = os.CLOCK_MONOTONIC; |
| 153 | |||
| 146 | /// Initialize the timer structure. | 154 | /// Initialize the timer structure. |
| 147 | //This gives us an opportunity to grab the counter frequency in windows. | 155 | /// Can only fail when running in a hostile environment that intentionally injects |
| 148 | //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000. | 156 | /// error values into syscalls, such as using seccomp on Linux to intercept |
| 149 | //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not | 157 | /// `clock_gettime`. |
| 150 | // supported, or if the timespec pointer is out of bounds, which should be | ||
| 151 | // impossible here barring cosmic rays or other such occurrences of | ||
| 152 | // incredibly bad luck. | ||
| 153 | //On Darwin: This cannot fail, as far as I am able to tell. | ||
| 154 | pub fn start() Error!Timer { | 158 | pub fn start() Error!Timer { |
| 155 | var self: Timer = undefined; | 159 | // This gives us an opportunity to grab the counter frequency in windows. |
| 156 | 160 | // On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000. | |
| 161 | // On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not | ||
| 162 | // supported, or if the timespec pointer is out of bounds, which should be | ||
| 163 | // impossible here barring cosmic rays or other such occurrences of | ||
| 164 | // incredibly bad luck. | ||
| 165 | // On Darwin: This cannot fail, as far as I am able to tell. | ||
| 157 | if (is_windows) { | 166 | if (is_windows) { |
| 158 | self.frequency = os.windows.QueryPerformanceFrequency(); | 167 | const freq = os.windows.QueryPerformanceFrequency(); |
| 159 | self.resolution = @divFloor(ns_per_s, self.frequency); | 168 | return Timer{ |
| 160 | self.start_time = os.windows.QueryPerformanceCounter(); | 169 | .frequency = freq, |
| 170 | .resolution = @divFloor(ns_per_s, freq), | ||
| 171 | .start_time = os.windows.QueryPerformanceCounter(), | ||
| 172 | }; | ||
| 161 | } else if (comptime std.Target.current.isDarwin()) { | 173 | } else if (comptime std.Target.current.isDarwin()) { |
| 162 | os.darwin.mach_timebase_info(&self.frequency); | 174 | var freq: os.darwin.mach_timebase_info_data = undefined; |
| 163 | self.resolution = @divFloor(self.frequency.numer, self.frequency.denom); | 175 | os.darwin.mach_timebase_info(&freq); |
| 164 | self.start_time = os.darwin.mach_absolute_time(); | 176 | |
| 177 | return Timer{ | ||
| 178 | .frequency = freq, | ||
| 179 | .resolution = @divFloor(freq.numer, freq.denom), | ||
| 180 | .start_time = os.darwin.mach_absolute_time(), | ||
| 181 | }; | ||
| 165 | } else { | 182 | } else { |
| 166 | //On Linux, seccomp can do arbitrary things to our ability to call | 183 | // On Linux, seccomp can do arbitrary things to our ability to call |
| 167 | // syscalls, including return any errno value it wants and | 184 | // syscalls, including return any errno value it wants and |
| 168 | // inconsistently throwing errors. Since we can't account for | 185 | // inconsistently throwing errors. Since we can't account for |
| 169 | // abuses of seccomp in a reasonable way, we'll assume that if | 186 | // abuses of seccomp in a reasonable way, we'll assume that if |
| 170 | // seccomp is going to block us it will at least do so consistently | 187 | // seccomp is going to block us it will at least do so consistently |
| 171 | var ts: os.timespec = undefined; | 188 | var res: os.timespec = undefined; |
| 172 | os.clock_getres(monotonic_clock_id, &ts) catch return error.TimerUnsupported; | 189 | os.clock_getres(monotonic_clock_id, &res) catch return error.TimerUnsupported; |
| 173 | self.resolution = @intCast(u64, ts.tv_sec) * @as(u64, ns_per_s) + @intCast(u64, ts.tv_nsec); | ||
| 174 | 190 | ||
| 191 | var ts: os.timespec = undefined; | ||
| 175 | os.clock_gettime(monotonic_clock_id, &ts) catch return error.TimerUnsupported; | 192 | os.clock_gettime(monotonic_clock_id, &ts) catch return error.TimerUnsupported; |
| 176 | self.start_time = @intCast(u64, ts.tv_sec) * @as(u64, ns_per_s) + @intCast(u64, ts.tv_nsec); | 193 | |
| 194 | return Timer{ | ||
| 195 | .resolution = @intCast(u64, res.tv_sec) * ns_per_s + @intCast(u64, res.tv_nsec), | ||
| 196 | .start_time = @intCast(u64, ts.tv_sec) * ns_per_s + @intCast(u64, ts.tv_nsec), | ||
| 197 | .frequency = {}, | ||
| 198 | }; | ||
| 177 | } | 199 | } |
| 178 | 200 | ||
| 179 | return self; | 201 | return self; |
| ... | @@ -226,7 +248,6 @@ test "sleep" { | ... | @@ -226,7 +248,6 @@ test "sleep" { |
| 226 | } | 248 | } |
| 227 | 249 | ||
| 228 | test "timestamp" { | 250 | test "timestamp" { |
| 229 | const ns_per_ms = (ns_per_s / ms_per_s); | ||
| 230 | const margin = ns_per_ms * 50; | 251 | const margin = ns_per_ms * 50; |
| 231 | 252 | ||
| 232 | const time_0 = milliTimestamp(); | 253 | const time_0 = milliTimestamp(); |
| ... | @@ -237,7 +258,6 @@ test "timestamp" { | ... | @@ -237,7 +258,6 @@ test "timestamp" { |
| 237 | } | 258 | } |
| 238 | 259 | ||
| 239 | test "Timer" { | 260 | test "Timer" { |
| 240 | const ns_per_ms = (ns_per_s / ms_per_s); | ||
| 241 | const margin = ns_per_ms * 150; | 261 | const margin = ns_per_ms * 150; |
| 242 | 262 | ||
| 243 | var timer = try Timer.start(); | 263 | var timer = try Timer.start(); |
lib/std/time/epoch.zig+23-12| ... | @@ -1,15 +1,26 @@ | ... | @@ -1,15 +1,26 @@ |
| 1 | /// Epoch reference times in terms of their difference from | 1 | //! Epoch reference times in terms of their difference from |
| 2 | /// posix epoch in seconds. | 2 | //! UTC 1970-01-01 in seconds. |
| 3 | pub const posix = 0; //Jan 01, 1970 AD | 3 | |
| 4 | pub const dos = 315532800; //Jan 01, 1980 AD | 4 | /// Jan 01, 1970 AD |
| 5 | pub const ios = 978307200; //Jan 01, 2001 AD | 5 | pub const posix = 0; |
| 6 | pub const openvms = -3506716800; //Nov 17, 1858 AD | 6 | /// Jan 01, 1980 AD |
| 7 | pub const zos = -2208988800; //Jan 01, 1900 AD | 7 | pub const dos = 315532800; |
| 8 | pub const windows = -11644473600; //Jan 01, 1601 AD | 8 | /// Jan 01, 2001 AD |
| 9 | pub const amiga = 252460800; //Jan 01, 1978 AD | 9 | pub const ios = 978307200; |
| 10 | pub const pickos = -63244800; //Dec 31, 1967 AD | 10 | /// Nov 17, 1858 AD |
| 11 | pub const gps = 315964800; //Jan 06, 1980 AD | 11 | pub const openvms = -3506716800; |
| 12 | pub const clr = -62135769600; //Jan 01, 0001 AD | 12 | /// Jan 01, 1900 AD |
| 13 | pub const zos = -2208988800; | ||
| 14 | /// Jan 01, 1601 AD | ||
| 15 | pub const windows = -11644473600; | ||
| 16 | /// Jan 01, 1978 AD | ||
| 17 | pub const amiga = 252460800; | ||
| 18 | /// Dec 31, 1967 AD | ||
| 19 | pub const pickos = -63244800; | ||
| 20 | /// Jan 06, 1980 AD | ||
| 21 | pub const gps = 315964800; | ||
| 22 | /// Jan 01, 0001 AD | ||
| 23 | pub const clr = -62135769600; | ||
| 13 | 24 | ||
| 14 | pub const unix = posix; | 25 | pub const unix = posix; |
| 15 | pub const android = posix; | 26 | pub const android = posix; |