| ... | ... | @@ -12,12 +12,13 @@ pub const epoch = @import("epoch.zig"); |
| 12 | 12 | |
| 13 | 13 | /// Sleep for the specified duration |
| 14 | 14 | pub fn sleep(seconds: usize, nanoseconds: usize) void { |
| 15 | | switch(builtin.os) { |
| 15 | switch (builtin.os) { |
| 16 | 16 | Os.linux, Os.macosx, Os.ios => { |
| 17 | 17 | posixSleep(u63(seconds), u63(nanoseconds)); |
| 18 | 18 | }, |
| 19 | 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 | 22 | windows.Sleep(windows.DWORD(milliseconds)); |
| 22 | 23 | }, |
| 23 | 24 | else => @compileError("Unsupported OS"), |
| ... | ... | @@ -57,7 +58,7 @@ pub fn timestamp() u64 { |
| 57 | 58 | } |
| 58 | 59 | |
| 59 | 60 | /// Get the posix timestamp, UTC, in milliseconds |
| 60 | | pub const milliTimestamp = switch(builtin.os) { |
| 61 | pub const milliTimestamp = switch (builtin.os) { |
| 61 | 62 | Os.windows => milliTimestampWindows, |
| 62 | 63 | Os.linux => milliTimestampPosix, |
| 63 | 64 | Os.macosx, Os.ios => milliTimestampDarwin, |
| ... | ... | @@ -80,20 +81,21 @@ fn milliTimestampDarwin() u64 { |
| 80 | 81 | var tv: darwin.timeval = undefined; |
| 81 | 82 | var err = darwin.gettimeofday(&tv, null); |
| 82 | 83 | debug.assert(err == 0); |
| 83 | | const sec_ms = tv.tv_sec * ms_per_s; |
| 84 | | const usec_ms = @divFloor(tv.tv_usec, (us_per_s / ms_per_s)); |
| 84 | const sec_ms = u64(tv.tv_sec) * ms_per_s; |
| 85 | const usec_ms = @divFloor(u64(tv.tv_usec), us_per_s / ms_per_s); |
| 85 | 86 | return u64(sec_ms) + u64(usec_ms); |
| 86 | 87 | } |
| 87 | 88 | |
| 88 | 89 | fn milliTimestampPosix() u64 { |
| 89 | 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 | 93 | var ts: posix.timespec = undefined; |
| 92 | 94 | const err = posix.clock_gettime(posix.CLOCK_REALTIME, &ts); |
| 93 | 95 | debug.assert(err == 0); |
| 94 | | const sec_ms = ts.tv_sec * ms_per_s; |
| 95 | | const nsec_ms = @divFloor(ts.tv_nsec, ns_per_s / ms_per_s); |
| 96 | | return u64(sec_ms) + u64(nsec_ms); |
| 96 | const sec_ms = u64(ts.tv_sec) * ms_per_s; |
| 97 | const nsec_ms = @divFloor(u64(ts.tv_nsec), ns_per_s / ms_per_s); |
| 98 | return sec_ms + nsec_ms; |
| 97 | 99 | } |
| 98 | 100 | |
| 99 | 101 | /// Divisions of a second |
| ... | ... | @@ -122,7 +124,7 @@ pub const Timer = struct { |
| 122 | 124 | //if we used resolution's value when performing the |
| 123 | 125 | // performance counter calc on windows/darwin, it would |
| 124 | 126 | // be less precise |
| 125 | | frequency: switch(builtin.os) { |
| 127 | frequency: switch (builtin.os) { |
| 126 | 128 | Os.windows => u64, |
| 127 | 129 | Os.macosx, Os.ios => darwin.mach_timebase_info_data, |
| 128 | 130 | else => void, |
| ... | ... | @@ -141,7 +143,8 @@ pub const Timer = struct { |
| 141 | 143 | //}; |
| 142 | 144 | const monotonic_clock_id = posix.CLOCK_MONOTONIC; |
| 143 | 145 | |
| 144 | | //Initialize the timer structure. |
| 146 | |
| 147 | /// Initialize the timer structure. |
| 145 | 148 | //This gives us an oportunity to grab the counter frequency in windows. |
| 146 | 149 | //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000. |
| 147 | 150 | //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not |
| ... | ... | @@ -149,32 +152,40 @@ pub const Timer = struct { |
| 149 | 152 | // impossible here barring cosmic rays or other such occurances of |
| 150 | 153 | // incredibly bad luck. |
| 151 | 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 | 156 | pub fn start() TimerError!Timer { |
| 154 | 157 | var self: Timer = undefined; |
| 155 | 158 | |
| 156 | | switch(builtin.os) { |
| 159 | switch (builtin.os) { |
| 157 | 160 | Os.windows => { |
| 158 | 161 | var freq: i64 = undefined; |
| 159 | 162 | var err = windows.QueryPerformanceFrequency(&freq); |
| 160 | | if(err == 0) return error.TimerUnsupported; |
| 163 | if (err == 0) return error.TimerUnsupported; |
| 161 | 164 | self.frequency = u64(freq); |
| 162 | 165 | self.resolution = @divFloor(ns_per_s, self.frequency); |
| 166 | |
| 163 | 167 | var start_time: i64 = undefined; |
| 164 | | _ = windows.QueryPerformanceCounter(&start_time); |
| 168 | err = windows.QueryPerformanceCounter(&start_time); |
| 169 | debug.assert(err != 0); |
| 165 | 170 | self.start_time = u64(start_time); |
| 166 | 171 | }, |
| 167 | 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 | 178 | var ts: posix.timespec = undefined; |
| 169 | 179 | var result = posix.clock_getres(monotonic_clock_id, &ts); |
| 170 | | switch(posix.getErrno(result)) { |
| 180 | switch (posix.getErrno(result)) { |
| 171 | 181 | 0 => {}, |
| 172 | 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); |
| 176 | | _ = posix.clock_gettime(monotonic_clock_id, &ts); |
| 177 | | self.start_time = 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); |
| 186 | result = posix.clock_gettime(monotonic_clock_id, &ts); |
| 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 | 190 | Os.macosx, Os.ios => { |
| 180 | 191 | darwin.mach_timebase_info(&self.frequency); |
| ... | ... | @@ -189,7 +200,7 @@ pub const Timer = struct { |
| 189 | 200 | /// Reads the timer value since start or the last reset in nanoseconds |
| 190 | 201 | pub fn read(self: &Timer) u64 { |
| 191 | 202 | var clock = clockNative() - self.start_time; |
| 192 | | return switch(builtin.os) { |
| 203 | return switch (builtin.os) { |
| 193 | 204 | Os.windows => @divFloor(clock * ns_per_s, self.frequency), |
| 194 | 205 | Os.linux => clock, |
| 195 | 206 | Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom), |
| ... | ... | @@ -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 | 227 | Os.windows => clockWindows, |
| 217 | 228 | Os.linux => clockLinux, |
| 218 | 229 | Os.macosx, Os.ios => clockDarwin, |
| ... | ... | @@ -234,7 +245,7 @@ pub const Timer = struct { |
| 234 | 245 | var ts: posix.timespec = undefined; |
| 235 | 246 | var result = posix.clock_gettime(monotonic_clock_id, &ts); |
| 236 | 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 | |