authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-24 20:06:56-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-24 21:40:08-04:00
log53d011fa1a7bfb2389e3677e1f6fcbe7a678e05f
tree6dc248d8606088f7a288c00f6ccef78290229cf4
parentc6e7d0fcfdf83531c5c931433528c540eee62e56

(breaking) std.time fixups and API changes

Remove the constants that assume a base unit in favor of explicit x_per_y constants. nanosecond calendar timestamps now use i128 for the type. This affects fs.File.Stat, std.time.nanoTimestamp, and fs.File.updateTimes. calendar timestamps are now signed, because the value can be less than the epoch (the user can set their computer time to whatever they wish). implement std.os.clock_gettime for Windows when clock id is CLOCK_CALENDAR.

13 files changed, 191 insertions(+), 170 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}
123123
124fn sleepALittle(count: *usize) void {124fn 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}
128128
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}
147fn sleepALittle(count: *usize) callconv(.Async) void {147fn 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}
151fn increaseByTen(count: *usize) callconv(.Async) void {151fn 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 a458 // 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,
229229
230 /// access time in nanoseconds230 /// Access time in nanoseconds, relative to UTC 1970-01-01.
231 atime: i64,231 atime: i128,
232232 /// Last modification time in nanoseconds, relative to UTC 1970-01-01.
233 /// last modification time in nanoseconds233 mtime: i128,
234 mtime: i64,234 /// Creation time in nanoseconds, relative to UTC 1970-01-01.
235235 ctime: i128,
236 /// creation time in nanoseconds
237 ctime: i64,
238 };236 };
239237
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 }
278276
...@@ -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 nanoseconds286 /// access timestamp in nanoseconds
289 atime: i64,287 atime: i128,
290 /// last modification timestamp in nanoseconds288 /// 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}
1212
13const FILE_LOCK_TEST_SLEEP_TIME = 5 * std.time.millisecond;13const FILE_LOCK_TEST_SLEEP_TIME = 5 * std.time.ns_per_ms;
1414
15test "open file with exclusive nonblocking lock twice" {15test "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 {
142142
143 // Output variables143 // 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,
148148
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;
11411141
1142 var servfail_retry: usize = undefined;1142 var servfail_retry: usize = undefined;
11431143
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 parallel1146 // 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(
38803880
3881pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;3881pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
38823882
3883/// TODO: change this to return the timespec as a return value
3884/// TODO: look into making clk_id an enum
3883pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {3885pub 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 }
38983917
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;
1456pub const POLLNVAL = 0x020;1456pub const POLLNVAL = 0x020;
14571457
1458pub const POLLSTANDARD = POLLIN | POLLPRI | POLLOUT | POLLRDNORM | POLLRDBAND | POLLWRBAND | POLLERR | POLLHUP | POLLNVAL;1458pub const POLLSTANDARD = POLLIN | POLLPRI | POLLOUT | POLLRDNORM | POLLRDBAND | POLLWRBAND | POLLERR | POLLHUP | POLLNVAL;
1459
1460pub const CLOCK_REALTIME = 0;
1461pub const CLOCK_MONOTONIC = 6;
1462pub const CLOCK_MONOTONIC_RAW = 4;
1463pub const CLOCK_MONOTONIC_RAW_APPROX = 5;
1464pub const CLOCK_UPTIME_RAW = 8;
1465pub const CLOCK_UPTIME_RAW_APPROX = 9;
1466pub const CLOCK_PROCESS_CPUTIME_ID = 12;
1467pub 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).
1196pub fn fromSysTime(hns: i64) i64 {1196pub 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}
12001200
1201pub fn toSysTime(ns: i64) i64 {1201pub 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}
12051205
1206pub fn fileTimeToNanoSeconds(ft: FILETIME) i64 {1206pub 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}
12101210
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.
1212pub fn nanoSecondsToFileTime(ns: i64) FILETIME {1212pub 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,
3232
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,
3535
36 /// How many nanoseconds to keep the output hidden36 /// 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,
3838
39 done: bool = true,39 done: bool = true,
4040
...@@ -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;
283283
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);
292292
293 node.end();293 node.end();
294294
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 }
165165
166 while (!self.is_set) {166 while (!self.is_set) {
lib/std/time.zig+101-117
...@@ -4,16 +4,14 @@ const assert = std.debug.assert;...@@ -4,16 +4,14 @@ const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const os = std.os;5const os = std.os;
6const math = std.math;6const math = std.math;
7const is_windows = std.Target.current.os.tag == .windows;
78
8pub const epoch = @import("time/epoch.zig");9pub const epoch = @import("time/epoch.zig");
910
10const 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/O12/// TODO integrate with evented I/O
14pub fn sleep(nanoseconds: u64) void {13pub 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,105 +47,78 @@ pub fn sleep(nanoseconds: u64) void {...@@ -49,105 +47,78 @@ pub fn sleep(nanoseconds: u64) void {
49 std.os.nanosleep(s, ns);47 std.os.nanosleep(s, ns);
50}48}
5149
52/// Get the posix timestamp, UTC, in seconds50/// 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.
54pub 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.
55pub fn timestamp() i64 {
56 return @divFloor(milliTimestamp(), ns_per_s);
56}57}
5758
58/// Get the posix timestamp, UTC, in milliseconds59/// Get a calendar timestamp, in milliseconds, relative to UTC 1970-01-01.
59/// TODO audit this function. is it possible to return an error?60/// Precision of timing depends on the hardware and operating system.
60pub fn milliTimestamp() u64 {61/// The return value is signed because it is possible to have a date that is
61 return @divFloor(nanoTimestamp(), millisecond);62/// before the epoch.
63/// See `std.os.clock_gettime` for a POSIX timestamp.
64pub fn milliTimestamp() i64 {
65 return @intCast(i64, @divFloor(nanoTimestamp(), ns_per_ms));
62}66}
6367
64const DarwinTimeStart = struct {68/// Get a calendar timestamp, in nanoseconds, relative to UTC 1970-01-01.
65 timebase: os.darwin.mach_timebase_info_data,69/// Precision of timing depends on the hardware and operating system.
66 inittime: os.darwin.timespec,70/// On Windows this has a maximum granularity of 100 nanoseconds.
67 initclock: u64,71/// The return value is signed because it is possible to have a date that is
68};72/// before the epoch.
6973/// See `std.os.clock_gettime` for a POSIX timestamp.
70var global_timestart: DarwinTimeStart = undefined;74pub fn nanoTimestamp() i128 {
71var init_global_timestart_once = std.once(init_global_timestart);
72
73pub fn init_global_timestart() void {
74 var micro: os.darwin.timeval = undefined;
75 var timestart: DarwinTimeStart = undefined;
76
77 os.darwin.mach_timebase_info(&timestart.timebase);
78
79 const err = os.darwin.gettimeofday(&micro, null);
80 assert(err == 0);
81
82 timestart.initclock = os.darwin.mach_absolute_time();
83 timestart.inittime.tv_sec = micro.tv_sec;
84 timestart.inittime.tv_nsec = micro.tv_usec * 1000;
85
86 global_timestart = timestart;
87}
88
89/// Get the posix timestamp, UTC, in nanoseconds
90///
91/// On windows this only has a granularity of 100 nanoseconds.
92///
93/// TODO audit this function. is it possible to return an error?
94pub fn nanoTimestamp() u64 {
95 if (is_windows) {75 if (is_windows) {
96 //FileTime has a granularity of 100 nanoseconds76 // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
97 // and uses the NTFS/Windows epoch77 // which is 1601-01-01.
78 const epoch_adj = epoch.windows * (ns_per_s / 100);
98 var ft: os.windows.FILETIME = undefined;79 var ft: os.windows.FILETIME = undefined;
99 os.windows.kernel32.GetSystemTimeAsFileTime(&ft);80 os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
100 const ns_per_hns = 100;
101 const epoch_adj = epoch.windows * ns_per_s;
102
103 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;81 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
104 return (ft64 * ns_per_hns) - -epoch_adj;82 return @as(i128, @bitCast(i64, ft64) + epoch_adj) * 100;
105 }83 }
106 if (builtin.os.tag == .wasi and !builtin.link_libc) {84 if (builtin.os.tag == .wasi and !builtin.link_libc) {
107 var ns: os.wasi.timestamp_t = undefined;85 var ns: os.wasi.timestamp_t = undefined;
108
109 // TODO: Verify that precision is ignored
110 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);
111 assert(err == os.wasi.ESUCCESS);87 assert(err == os.wasi.ESUCCESS);
112
113 return ns;88 return ns;
114 }89 }
115 if (comptime std.Target.current.isDarwin()) {
116 // https://stackoverflow.com/a/21352348
117 init_global_timestart_once.call();
118
119 const clock: u64 = os.darwin.mach_absolute_time() - global_timestart.initclock;
120 const nano = @divFloor(clock * @as(u64, global_timestart.timebase.numer), @as(u64, global_timestart.timebase.denom));
121
122 const tv_sec_nsec = @intCast(u64, global_timestart.inittime.tv_sec) * ns_per_s;
123 const tv_nsec = @intCast(u64, global_timestart.inittime.tv_nsec);
124
125 return tv_sec_nsec + tv_nsec + nano;
126 }
127 var ts: os.timespec = undefined;90 var ts: os.timespec = undefined;
128 //From what I can tell there's no reason clock_gettime91 os.clock_gettime(os.CLOCK_REALTIME, &ts) catch |err| switch (err) {
129 // should ever fail for us with CLOCK_REALTIME,92 error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
130 // seccomp aside.93 };
131 os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable;94 return (@as(i128, ts.tv_sec) * ns_per_s) + ts.tv_nsec;
132 const sec_ns = @intCast(u64, ts.tv_sec) * ns_per_s;
133 return sec_ns + @intCast(u64, ts.tv_nsec);
134}95}
13596
136/// Multiples of a base unit (nanoseconds)97// Divisions of a nanosecond.
137pub const nanosecond = 1;98pub const ns_per_us = 1000;
138pub const microsecond = 1000 * nanosecond;99pub const ns_per_ms = 1000 * ns_per_us;
139pub const millisecond = 1000 * microsecond;100pub const ns_per_s = 1000 * ns_per_ms;
140pub const second = 1000 * millisecond;101pub const ns_per_min = 60 * ns_per_s;
141pub const minute = 60 * second;102pub const ns_per_hour = 60 * ns_per_min;
142pub const hour = 60 * minute;103pub const ns_per_day = 24 * ns_per_hour;
143104pub const ns_per_week = 7 * ns_per_day;
144/// Divisions of a second105
145pub const ns_per_s = 1000000000;106// Divisions of a microsecond.
146pub const us_per_s = 1000000;107pub const us_per_ms = 1000;
108pub const us_per_s = 1000 * us_per_ms;
109pub const us_per_min = 60 * us_per_s;
110pub const us_per_hour = 60 * us_per_min;
111pub const us_per_day = 24 * us_per_hour;
112pub const us_per_week = 7 * us_per_day;
113
114// Divisions of a millisecond.
147pub const ms_per_s = 1000;115pub const ms_per_s = 1000;
148pub const cs_per_s = 100;116pub const ms_per_min = 60 * ms_per_s;
117pub const ms_per_hour = 60 * ms_per_min;
118pub const ms_per_day = 24 * ms_per_hour;
119pub const ms_per_week = 7 * ms_per_day;
149120
150/// Common time divisions121// Divisions of a second.
151pub const s_per_min = 60;122pub const s_per_min = 60;
152pub const s_per_hour = s_per_min * 60;123pub const s_per_hour = s_per_min * 60;
153pub const s_per_day = s_per_hour * 24;124pub const s_per_day = s_per_hour * 24;
...@@ -155,12 +126,12 @@ pub const s_per_week = s_per_day * 7;...@@ -155,12 +126,12 @@ pub const s_per_week = s_per_day * 7;
155126
156/// A monotonic high-performance timer.127/// A monotonic high-performance timer.
157/// Timer.start() must be called to initialize the struct, which captures128/// Timer.start() must be called to initialize the struct, which captures
158/// the counter frequency on windows and darwin, records the resolution,129/// the counter frequency on windows and darwin, records the resolution,
159/// and gives the user an opportunity to check for the existnece of130/// and gives the user an opportunity to check for the existnece of
160/// 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.
161/// .resolution is in nanoseconds on all platforms but .start_time's meaning132/// .resolution is in nanoseconds on all platforms but .start_time's meaning
162/// depends on the OS. On Windows and Darwin it is a hardware counter133/// depends on the OS. On Windows and Darwin it is a hardware counter
163/// value that requires calculation to convert to a meaninful unit.134/// value that requires calculation to convert to a meaninful unit.
164pub const Timer = struct {135pub const Timer = struct {
165 ///if we used resolution's value when performing the136 ///if we used resolution's value when performing the
166 /// performance counter calc on windows/darwin, it would137 /// performance counter calc on windows/darwin, it would
...@@ -173,43 +144,58 @@ pub const Timer = struct {...@@ -173,43 +144,58 @@ pub const Timer = struct {
173 resolution: u64,144 resolution: u64,
174 start_time: u64,145 start_time: u64,
175146
176 const Error = error{TimerUnsupported};147 pub const Error = error{TimerUnsupported};
177148
178 ///At some point we may change our minds on RAW, but for now we're149 /// At some point we may change our minds on RAW, but for now we're
179 /// sticking with posix standard MONOTONIC. For more information, see:150 /// sticking with posix standard MONOTONIC. For more information, see:
180 /// https://github.com/ziglang/zig/pull/933151 /// https://github.com/ziglang/zig/pull/933
181 const monotonic_clock_id = os.CLOCK_MONOTONIC;152 const monotonic_clock_id = os.CLOCK_MONOTONIC;
153
182 /// Initialize the timer structure.154 /// Initialize the timer structure.
183 //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
184 //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.156 /// error values into syscalls, such as using seccomp on Linux to intercept
185 //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not157 /// `clock_gettime`.
186 // supported, or if the timespec pointer is out of bounds, which should be
187 // impossible here barring cosmic rays or other such occurrences of
188 // incredibly bad luck.
189 //On Darwin: This cannot fail, as far as I am able to tell.
190 pub fn start() Error!Timer {158 pub fn start() Error!Timer {
191 var self: Timer = undefined;159 // This gives us an opportunity to grab the counter frequency in windows.
192160 // 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.
193 if (is_windows) {166 if (is_windows) {
194 self.frequency = os.windows.QueryPerformanceFrequency();167 const freq = os.windows.QueryPerformanceFrequency();
195 self.resolution = @divFloor(ns_per_s, self.frequency);168 return Timer{
196 self.start_time = os.windows.QueryPerformanceCounter();169 .frequency = freq,
170 .resolution = @divFloor(ns_per_s, freq),
171 .start_time = os.windows.QueryPerformanceCounter(),
172 };
197 } else if (comptime std.Target.current.isDarwin()) {173 } else if (comptime std.Target.current.isDarwin()) {
198 os.darwin.mach_timebase_info(&self.frequency);174 var freq: os.darwin.mach_timebase_info_data = undefined;
199 self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);175 os.darwin.mach_timebase_info(&freq);
200 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 };
201 } else {182 } else {
202 //On Linux, seccomp can do arbitrary things to our ability to call183 // On Linux, seccomp can do arbitrary things to our ability to call
203 // syscalls, including return any errno value it wants and184 // syscalls, including return any errno value it wants and
204 // inconsistently throwing errors. Since we can't account for185 // inconsistently throwing errors. Since we can't account for
205 // abuses of seccomp in a reasonable way, we'll assume that if186 // abuses of seccomp in a reasonable way, we'll assume that if
206 // seccomp is going to block us it will at least do so consistently187 // seccomp is going to block us it will at least do so consistently
207 var ts: os.timespec = undefined;188 var res: os.timespec = undefined;
208 os.clock_getres(monotonic_clock_id, &ts) catch return error.TimerUnsupported;189 os.clock_getres(monotonic_clock_id, &res) catch return error.TimerUnsupported;
209 self.resolution = @intCast(u64, ts.tv_sec) * @as(u64, ns_per_s) + @intCast(u64, ts.tv_nsec);
210190
191 var ts: os.timespec = undefined;
211 os.clock_gettime(monotonic_clock_id, &ts) catch return error.TimerUnsupported;192 os.clock_gettime(monotonic_clock_id, &ts) catch return error.TimerUnsupported;
212 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 };
213 }199 }
214200
215 return self;201 return self;
...@@ -262,7 +248,6 @@ test "sleep" {...@@ -262,7 +248,6 @@ test "sleep" {
262}248}
263249
264test "timestamp" {250test "timestamp" {
265 const ns_per_ms = (ns_per_s / ms_per_s);
266 const margin = ns_per_ms * 50;251 const margin = ns_per_ms * 50;
267252
268 const time_0 = milliTimestamp();253 const time_0 = milliTimestamp();
...@@ -273,7 +258,6 @@ test "timestamp" {...@@ -273,7 +258,6 @@ test "timestamp" {
273}258}
274259
275test "Timer" {260test "Timer" {
276 const ns_per_ms = (ns_per_s / ms_per_s);
277 const margin = ns_per_ms * 150;261 const margin = ns_per_ms * 150;
278262
279 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 from1//! Epoch reference times in terms of their difference from
2/// posix epoch in seconds.2//! UTC 1970-01-01 in seconds.
3pub const posix = 0; //Jan 01, 1970 AD3
4pub const dos = 315532800; //Jan 01, 1980 AD4/// Jan 01, 1970 AD
5pub const ios = 978307200; //Jan 01, 2001 AD5pub const posix = 0;
6pub const openvms = -3506716800; //Nov 17, 1858 AD6/// Jan 01, 1980 AD
7pub const zos = -2208988800; //Jan 01, 1900 AD7pub const dos = 315532800;
8pub const windows = -11644473600; //Jan 01, 1601 AD8/// Jan 01, 2001 AD
9pub const amiga = 252460800; //Jan 01, 1978 AD9pub const ios = 978307200;
10pub const pickos = -63244800; //Dec 31, 1967 AD10/// Nov 17, 1858 AD
11pub const gps = 315964800; //Jan 06, 1980 AD11pub const openvms = -3506716800;
12pub const clr = -62135769600; //Jan 01, 0001 AD12/// Jan 01, 1900 AD
13pub const zos = -2208988800;
14/// Jan 01, 1601 AD
15pub const windows = -11644473600;
16/// Jan 01, 1978 AD
17pub const amiga = 252460800;
18/// Dec 31, 1967 AD
19pub const pickos = -63244800;
20/// Jan 06, 1980 AD
21pub const gps = 315964800;
22/// Jan 01, 0001 AD
23pub const clr = -62135769600;
1324
14pub const unix = posix;25pub const unix = posix;
15pub const android = posix;26pub const android = posix;