| ... | @@ -12,12 +12,13 @@ pub const epoch = @import("epoch.zig"); | ... | @@ -12,12 +12,13 @@ pub const epoch = @import("epoch.zig"); |
| 12 | | 12 | |
| 13 | /// Sleep for the specified duration | 13 | /// Sleep for the specified duration |
| 14 | pub fn sleep(seconds: usize, nanoseconds: usize) void { | 14 | pub fn sleep(seconds: usize, nanoseconds: usize) void { |
| 15 | switch(builtin.os) { | 15 | switch (builtin.os) { |
| 16 | Os.linux, Os.macosx, Os.ios => { | 16 | Os.linux, Os.macosx, Os.ios => { |
| 17 | posixSleep(u63(seconds), u63(nanoseconds)); | 17 | posixSleep(u63(seconds), u63(nanoseconds)); |
| 18 | }, | 18 | }, |
| 19 | Os.windows => { | 19 | Os.windows => { |
| 20 | const milliseconds = seconds * ms_per_s + nanoseconds / (ns_per_s / ms_per_s); | 20 | const ns_per_ms = ns_per_s / ms_per_s; |
| | 21 | const milliseconds = seconds * ms_per_s + nanoseconds / ns_per_ms; |
| 21 | windows.Sleep(windows.DWORD(milliseconds)); | 22 | windows.Sleep(windows.DWORD(milliseconds)); |
| 22 | }, | 23 | }, |
| 23 | else => @compileError("Unsupported OS"), | 24 | else => @compileError("Unsupported OS"), |
| ... | @@ -57,7 +58,7 @@ pub fn timestamp() u64 { | ... | @@ -57,7 +58,7 @@ pub fn timestamp() u64 { |
| 57 | } | 58 | } |
| 58 | | 59 | |
| 59 | /// Get the posix timestamp, UTC, in milliseconds | 60 | /// Get the posix timestamp, UTC, in milliseconds |
| 60 | pub const milliTimestamp = switch(builtin.os) { | 61 | pub const milliTimestamp = switch (builtin.os) { |
| 61 | Os.windows => milliTimestampWindows, | 62 | Os.windows => milliTimestampWindows, |
| 62 | Os.linux => milliTimestampPosix, | 63 | Os.linux => milliTimestampPosix, |
| 63 | Os.macosx, Os.ios => milliTimestampDarwin, | 64 | Os.macosx, Os.ios => milliTimestampDarwin, |
| ... | @@ -80,20 +81,21 @@ fn milliTimestampDarwin() u64 { | ... | @@ -80,20 +81,21 @@ fn milliTimestampDarwin() u64 { |
| 80 | var tv: darwin.timeval = undefined; | 81 | var tv: darwin.timeval = undefined; |
| 81 | var err = darwin.gettimeofday(&tv, null); | 82 | var err = darwin.gettimeofday(&tv, null); |
| 82 | debug.assert(err == 0); | 83 | debug.assert(err == 0); |
| 83 | const sec_ms = tv.tv_sec * ms_per_s; | 84 | const sec_ms = u64(tv.tv_sec) * ms_per_s; |
| 84 | const usec_ms = @divFloor(tv.tv_usec, (us_per_s / ms_per_s)); | 85 | const usec_ms = @divFloor(u64(tv.tv_usec), us_per_s / ms_per_s); |
| 85 | return u64(sec_ms) + u64(usec_ms); | 86 | return u64(sec_ms) + u64(usec_ms); |
| 86 | } | 87 | } |
| 87 | | 88 | |
| 88 | fn milliTimestampPosix() u64 { | 89 | fn milliTimestampPosix() u64 { |
| 89 | //From what I can tell there's no reason clock_gettime | 90 | //From what I can tell there's no reason clock_gettime |
| 90 | // should ever fail for us with CLOCK_REALTIME | 91 | // should ever fail for us with CLOCK_REALTIME, |
| | 92 | // seccomp aside. |
| 91 | var ts: posix.timespec = undefined; | 93 | var ts: posix.timespec = undefined; |
| 92 | const err = posix.clock_gettime(posix.CLOCK_REALTIME, &ts); | 94 | const err = posix.clock_gettime(posix.CLOCK_REALTIME, &ts); |
| 93 | debug.assert(err == 0); | 95 | debug.assert(err == 0); |
| 94 | const sec_ms = ts.tv_sec * ms_per_s; | 96 | const sec_ms = u64(ts.tv_sec) * ms_per_s; |
| 95 | const nsec_ms = @divFloor(ts.tv_nsec, ns_per_s / ms_per_s); | 97 | const nsec_ms = @divFloor(u64(ts.tv_nsec), ns_per_s / ms_per_s); |
| 96 | return u64(sec_ms) + u64(nsec_ms); | 98 | return sec_ms + nsec_ms; |
| 97 | } | 99 | } |
| 98 | | 100 | |
| 99 | /// Divisions of a second | 101 | /// Divisions of a second |
| ... | @@ -122,7 +124,7 @@ pub const Timer = struct { | ... | @@ -122,7 +124,7 @@ pub const Timer = struct { |
| 122 | //if we used resolution's value when performing the | 124 | //if we used resolution's value when performing the |
| 123 | // performance counter calc on windows/darwin, it would | 125 | // performance counter calc on windows/darwin, it would |
| 124 | // be less precise | 126 | // be less precise |
| 125 | frequency: switch(builtin.os) { | 127 | frequency: switch (builtin.os) { |
| 126 | Os.windows => u64, | 128 | Os.windows => u64, |
| 127 | Os.macosx, Os.ios => darwin.mach_timebase_info_data, | 129 | Os.macosx, Os.ios => darwin.mach_timebase_info_data, |
| 128 | else => void, | 130 | else => void, |
| ... | @@ -141,7 +143,8 @@ pub const Timer = struct { | ... | @@ -141,7 +143,8 @@ pub const Timer = struct { |
| 141 | //}; | 143 | //}; |
| 142 | const monotonic_clock_id = posix.CLOCK_MONOTONIC; | 144 | const monotonic_clock_id = posix.CLOCK_MONOTONIC; |
| 143 | | 145 | |
| 144 | //Initialize the timer structure. | 146 | |
| | 147 | /// Initialize the timer structure. |
| 145 | //This gives us an oportunity to grab the counter frequency in windows. | 148 | //This gives us an oportunity to grab the counter frequency in windows. |
| 146 | //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000. | 149 | //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000. |
| 147 | //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not | 150 | //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not |
| ... | @@ -149,32 +152,40 @@ pub const Timer = struct { | ... | @@ -149,32 +152,40 @@ pub const Timer = struct { |
| 149 | // impossible here barring cosmic rays or other such occurances of | 152 | // impossible here barring cosmic rays or other such occurances of |
| 150 | // incredibly bad luck. | 153 | // incredibly bad luck. |
| 151 | //On Darwin: This cannot fail, as far as I am able to tell. | 154 | //On Darwin: This cannot fail, as far as I am able to tell. |
| 152 | const TimerError = error{TimerUnsupported}; | 155 | const TimerError = error{TimerUnsupported, UnexpectedErrnoValue}; |
| 153 | pub fn start() TimerError!Timer { | 156 | pub fn start() TimerError!Timer { |
| 154 | var self: Timer = undefined; | 157 | var self: Timer = undefined; |
| 155 | | 158 | |
| 156 | switch(builtin.os) { | 159 | switch (builtin.os) { |
| 157 | Os.windows => { | 160 | Os.windows => { |
| 158 | var freq: i64 = undefined; | 161 | var freq: i64 = undefined; |
| 159 | var err = windows.QueryPerformanceFrequency(&freq); | 162 | var err = windows.QueryPerformanceFrequency(&freq); |
| 160 | if(err == 0) return error.TimerUnsupported; | 163 | if (err == 0) return error.TimerUnsupported; |
| 161 | self.frequency = u64(freq); | 164 | self.frequency = u64(freq); |
| 162 | self.resolution = @divFloor(ns_per_s, self.frequency); | 165 | self.resolution = @divFloor(ns_per_s, self.frequency); |
| | 166 | |
| 163 | var start_time: i64 = undefined; | 167 | var start_time: i64 = undefined; |
| 164 | _ = windows.QueryPerformanceCounter(&start_time); | 168 | err = windows.QueryPerformanceCounter(&start_time); |
| | 169 | debug.assert(err != 0); |
| 165 | self.start_time = u64(start_time); | 170 | self.start_time = u64(start_time); |
| 166 | }, | 171 | }, |
| 167 | Os.linux => { | 172 | Os.linux => { |
| | 173 | //On Linux, seccomp can do arbitrary things to our ability to call |
| | 174 | // syscalls, including return any errno value it wants and |
| | 175 | // inconsistently throwing errors. Since we can't account for |
| | 176 | // abuses of seccomp in a reasonable way, we'll assume that if |
| | 177 | // seccomp is going to block us it will at least do so consistently |
| 168 | var ts: posix.timespec = undefined; | 178 | var ts: posix.timespec = undefined; |
| 169 | var result = posix.clock_getres(monotonic_clock_id, &ts); | 179 | var result = posix.clock_getres(monotonic_clock_id, &ts); |
| 170 | switch(posix.getErrno(result)) { | 180 | switch (posix.getErrno(result)) { |
| 171 | 0 => {}, | 181 | 0 => {}, |
| 172 | posix.EINVAL => return error.TimerUnsupported, | 182 | posix.EINVAL => return error.TimerUnsupported, |
| 173 | else => unreachable, | 183 | else => return error.UnexpectedErrnoValue, |
| 174 | } | 184 | } |
| 175 | self.resolution = u64(ts.tv_sec * ns_per_s + ts.tv_nsec); | 185 | self.resolution = u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec); |
| 176 | _ = posix.clock_gettime(monotonic_clock_id, &ts); | 186 | result = posix.clock_gettime(monotonic_clock_id, &ts); |
| 177 | self.start_time = u64(ts.tv_sec * ns_per_s + ts.tv_nsec); | 187 | if (posix.getErrno(result) != 0) return error.UnexpectedErrnoValue; |
| | 188 | self.start_time = u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec); |
| 178 | }, | 189 | }, |
| 179 | Os.macosx, Os.ios => { | 190 | Os.macosx, Os.ios => { |
| 180 | darwin.mach_timebase_info(&self.frequency); | 191 | darwin.mach_timebase_info(&self.frequency); |
| ... | @@ -189,7 +200,7 @@ pub const Timer = struct { | ... | @@ -189,7 +200,7 @@ pub const Timer = struct { |
| 189 | /// Reads the timer value since start or the last reset in nanoseconds | 200 | /// Reads the timer value since start or the last reset in nanoseconds |
| 190 | pub fn read(self: &Timer) u64 { | 201 | pub fn read(self: &Timer) u64 { |
| 191 | var clock = clockNative() - self.start_time; | 202 | var clock = clockNative() - self.start_time; |
| 192 | return switch(builtin.os) { | 203 | return switch (builtin.os) { |
| 193 | Os.windows => @divFloor(clock * ns_per_s, self.frequency), | 204 | Os.windows => @divFloor(clock * ns_per_s, self.frequency), |
| 194 | Os.linux => clock, | 205 | Os.linux => clock, |
| 195 | Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom), | 206 | Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom), |
| ... | @@ -212,7 +223,7 @@ pub const Timer = struct { | ... | @@ -212,7 +223,7 @@ pub const Timer = struct { |
| 212 | } | 223 | } |
| 213 | | 224 | |
| 214 | | 225 | |
| 215 | const clockNative = switch(builtin.os) { | 226 | const clockNative = switch (builtin.os) { |
| 216 | Os.windows => clockWindows, | 227 | Os.windows => clockWindows, |
| 217 | Os.linux => clockLinux, | 228 | Os.linux => clockLinux, |
| 218 | Os.macosx, Os.ios => clockDarwin, | 229 | Os.macosx, Os.ios => clockDarwin, |
| ... | @@ -234,7 +245,7 @@ pub const Timer = struct { | ... | @@ -234,7 +245,7 @@ pub const Timer = struct { |
| 234 | var ts: posix.timespec = undefined; | 245 | var ts: posix.timespec = undefined; |
| 235 | var result = posix.clock_gettime(monotonic_clock_id, &ts); | 246 | var result = posix.clock_gettime(monotonic_clock_id, &ts); |
| 236 | debug.assert(posix.getErrno(result) == 0); | 247 | debug.assert(posix.getErrno(result) == 0); |
| 237 | return u64(ts.tv_sec * ns_per_s + ts.tv_nsec); | 248 | return u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec); |
| 238 | } | 249 | } |
| 239 | }; | 250 | }; |
| 240 | | 251 | |