authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-24 21:40:23-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-24 21:40:23-04:00
logc693c3ae5008c6ed14c4c2eb653b274b238bf6f1
tree6dc248d8606088f7a288c00f6ccef78290229cf4
parent4b1a8464715a9b2af1d9024694282883f3346482
parent53d011fa1a7bfb2389e3677e1f6fcbe7a678e05f

Merge branch 'leroycep-feature-nano-timestamp'

closes #5237

13 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}
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+104-84
...@@ -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,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}
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);
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.
64pub fn milliTimestamp() i64 {
65 return @intCast(i64, @divFloor(nanoTimestamp(), ns_per_ms));
56}66}
5767
58/// Get the posix timestamp, UTC, in milliseconds68/// 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.
60pub 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.
74pub fn nanoTimestamp() i128 {
61 if (is_windows) {75 if (is_windows) {
62 //FileTime has a granularity of 100 nanoseconds76 // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
63 // and uses the NTFS/Windows epoch77 // 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);
7888 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_gettime91 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}
9996
100/// Multiples of a base unit (nanoseconds)97// Divisions of a nanosecond.
101pub const nanosecond = 1;98pub const ns_per_us = 1000;
102pub const microsecond = 1000 * nanosecond;99pub const ns_per_ms = 1000 * ns_per_us;
103pub const millisecond = 1000 * microsecond;100pub const ns_per_s = 1000 * ns_per_ms;
104pub const second = 1000 * millisecond;101pub const ns_per_min = 60 * ns_per_s;
105pub const minute = 60 * second;102pub const ns_per_hour = 60 * ns_per_min;
106pub const hour = 60 * minute;103pub const ns_per_day = 24 * ns_per_hour;
107104pub const ns_per_week = 7 * ns_per_day;
108/// Divisions of a second105
109pub const ns_per_s = 1000000000;106// Divisions of a microsecond.
110pub 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.
111pub const ms_per_s = 1000;115pub const ms_per_s = 1000;
112pub 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;
113120
114/// Common time divisions121// Divisions of a second.
115pub const s_per_min = 60;122pub const s_per_min = 60;
116pub const s_per_hour = s_per_min * 60;123pub const s_per_hour = s_per_min * 60;
117pub const s_per_day = s_per_hour * 24;124pub 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;
119126
120/// A monotonic high-performance timer.127/// A monotonic high-performance timer.
121/// Timer.start() must be called to initialize the struct, which captures128/// 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 of130/// 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 meaning132/// .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 counter133/// 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.
128pub const Timer = struct {135pub const Timer = struct {
129 ///if we used resolution's value when performing the136 ///if we used resolution's value when performing the
130 /// performance counter calc on windows/darwin, it would137 /// 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,
139146
140 const Error = error{TimerUnsupported};147 pub const Error = error{TimerUnsupported};
141148
142 ///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
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/933151 /// 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 not157 /// `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.
156160 // 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 call183 // On Linux, seccomp can do arbitrary things to our ability to call
167 // syscalls, including return any errno value it wants and184 // syscalls, including return any errno value it wants and
168 // inconsistently throwing errors. Since we can't account for185 // inconsistently throwing errors. Since we can't account for
169 // abuses of seccomp in a reasonable way, we'll assume that if186 // 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 consistently187 // 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);
174190
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 }
178200
179 return self;201 return self;
...@@ -226,7 +248,6 @@ test "sleep" {...@@ -226,7 +248,6 @@ test "sleep" {
226}248}
227249
228test "timestamp" {250test "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;
231252
232 const time_0 = milliTimestamp();253 const time_0 = milliTimestamp();
...@@ -237,7 +258,6 @@ test "timestamp" {...@@ -237,7 +258,6 @@ test "timestamp" {
237}258}
238259
239test "Timer" {260test "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;
242262
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 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;