time.c++ (9609B)
1 // Copyright (c) 2014 Google Inc. (contributed by Remy Blank <rblank@google.com>) 2 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 3 // Licensed under the MIT License: 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 #if _WIN32 24 #include "win32-api-version.h" 25 #endif 26 27 #include "time.h" 28 #include "debug.h" 29 #include <set> 30 31 #if _WIN32 32 #include <windows.h> 33 #else 34 #include <time.h> 35 #endif 36 37 namespace kj { 38 39 const Clock& nullClock() { 40 class NullClock final: public Clock { 41 public: 42 Date now() const override { return UNIX_EPOCH; } 43 }; 44 static KJ_CONSTEXPR(const) NullClock NULL_CLOCK = NullClock(); 45 return NULL_CLOCK; 46 } 47 48 #if _WIN32 49 50 namespace { 51 52 static constexpr int64_t WIN32_EPOCH_OFFSET = 116444736000000000ull; 53 // Number of 100ns intervals from Jan 1, 1601 to Jan 1, 1970. 54 55 static Date toKjDate(FILETIME t) { 56 int64_t value = (static_cast<uint64_t>(t.dwHighDateTime) << 32) | t.dwLowDateTime; 57 return (value - WIN32_EPOCH_OFFSET) * (100 * kj::NANOSECONDS) + UNIX_EPOCH; 58 } 59 60 class Win32CoarseClock: public Clock { 61 public: 62 Date now() const override { 63 FILETIME ft; 64 GetSystemTimeAsFileTime(&ft); 65 return toKjDate(ft); 66 } 67 }; 68 69 class Win32PreciseClock: public Clock { 70 typedef VOID WINAPI GetSystemTimePreciseAsFileTimeFunc(LPFILETIME); 71 public: 72 Date now() const override { 73 static GetSystemTimePreciseAsFileTimeFunc* const getSystemTimePreciseAsFileTimePtr = 74 getGetSystemTimePreciseAsFileTime(); 75 FILETIME ft; 76 if (getSystemTimePreciseAsFileTimePtr == nullptr) { 77 // We can't use QueryPerformanceCounter() to get any more precision because we have no way 78 // of knowing when the calendar clock jumps. So I guess we're stuck. 79 GetSystemTimeAsFileTime(&ft); 80 } else { 81 getSystemTimePreciseAsFileTimePtr(&ft); 82 } 83 return toKjDate(ft); 84 } 85 86 private: 87 static GetSystemTimePreciseAsFileTimeFunc* getGetSystemTimePreciseAsFileTime() { 88 // Dynamically look up the function GetSystemTimePreciseAsFileTimeFunc(). This was only 89 // introduced as of Windows 8, so it might be missing. 90 #if __GNUC__ && !__clang__ && __GNUC__ >= 8 91 // GCC 8 warns that our reinterpret_cast of a function pointer below is casting between 92 // incompatible types. Yes, GCC, we know that. This is the nature of GetProcAddress(); it returns 93 // everything as `long long int (*)()` and we have to cast to the actual type. 94 #pragma GCC diagnostic push 95 #pragma GCC diagnostic ignored "-Wcast-function-type" 96 #endif 97 return reinterpret_cast<GetSystemTimePreciseAsFileTimeFunc*>(GetProcAddress( 98 GetModuleHandleA("kernel32.dll"), 99 "GetSystemTimePreciseAsFileTime")); 100 } 101 }; 102 103 class Win32CoarseMonotonicClock: public MonotonicClock { 104 public: 105 TimePoint now() const override { 106 return kj::origin<TimePoint>() + GetTickCount64() * kj::MILLISECONDS; 107 } 108 }; 109 110 class Win32PreciseMonotonicClock: public MonotonicClock { 111 // Precise clock implemented using QueryPerformanceCounter(). 112 // 113 // TODO(someday): Windows 10 has QueryUnbiasedInterruptTime() and 114 // QueryUnbiasedInterruptTimePrecise(), a new API for monotonic timing that isn't as difficult. 115 // Is there any benefit to dynamically checking for these and using them if available? 116 117 public: 118 TimePoint now() const override { 119 static const QpcProperties props; 120 121 LARGE_INTEGER now; 122 QueryPerformanceCounter(&now); 123 uint64_t adjusted = now.QuadPart - props.origin; 124 uint64_t ns = mulDiv64(adjusted, 1'000'000'000, props.frequency); 125 return kj::origin<TimePoint>() + ns * kj::NANOSECONDS; 126 } 127 128 private: 129 struct QpcProperties { 130 uint64_t origin; 131 // What QueryPerformanceCounter() would have returned at the time when GetTickCount64() returned 132 // zero. Used to ensure that the coarse and precise timers return similar values. 133 134 uint64_t frequency; 135 // From QueryPerformanceFrequency(). 136 137 QpcProperties() { 138 LARGE_INTEGER now, freqLi; 139 uint64_t ticks = GetTickCount64(); 140 QueryPerformanceCounter(&now); 141 142 QueryPerformanceFrequency(&freqLi); 143 frequency = freqLi.QuadPart; 144 145 // Convert the millisecond tick count into performance counter ticks. 146 uint64_t ticksAsQpc = mulDiv64(ticks, freqLi.QuadPart, 1000); 147 148 origin = now.QuadPart - ticksAsQpc; 149 } 150 }; 151 152 static inline uint64_t mulDiv64(uint64_t value, uint64_t numer, uint64_t denom) { 153 // Inspired by: 154 // https://github.com/rust-lang/rust/pull/22788/files#diff-24f054cd23f65af3b574c6ce8aa5a837R54 155 // Computes (value*numer)/denom without overflow, as long as both 156 // (numer*denom) and the overall result fit into 64 bits. 157 uint64_t q = value / denom; 158 uint64_t r = value % denom; 159 return q * numer + r * numer / denom; 160 } 161 }; 162 163 } // namespace 164 165 const Clock& systemCoarseCalendarClock() { 166 static constexpr Win32CoarseClock clock; 167 return clock; 168 } 169 const Clock& systemPreciseCalendarClock() { 170 static constexpr Win32PreciseClock clock; 171 return clock; 172 } 173 174 const MonotonicClock& systemCoarseMonotonicClock() { 175 static constexpr Win32CoarseMonotonicClock clock; 176 return clock; 177 } 178 const MonotonicClock& systemPreciseMonotonicClock() { 179 static constexpr Win32PreciseMonotonicClock clock; 180 return clock; 181 } 182 183 #else 184 185 namespace { 186 187 class PosixClock: public Clock { 188 public: 189 constexpr PosixClock(clockid_t clockId): clockId(clockId) {} 190 191 Date now() const override { 192 struct timespec ts; 193 KJ_SYSCALL(clock_gettime(clockId, &ts)); 194 return UNIX_EPOCH + ts.tv_sec * kj::SECONDS + ts.tv_nsec * kj::NANOSECONDS; 195 } 196 197 private: 198 clockid_t clockId; 199 }; 200 201 class PosixMonotonicClock: public MonotonicClock { 202 public: 203 constexpr PosixMonotonicClock(clockid_t clockId): clockId(clockId) {} 204 205 TimePoint now() const override { 206 struct timespec ts; 207 KJ_SYSCALL(clock_gettime(clockId, &ts)); 208 return kj::origin<TimePoint>() + ts.tv_sec * kj::SECONDS + ts.tv_nsec * kj::NANOSECONDS; 209 } 210 211 private: 212 clockid_t clockId; 213 }; 214 215 } // namespace 216 217 // FreeBSD has "_PRECISE", but Linux just defaults to precise. 218 #ifndef CLOCK_REALTIME_PRECISE 219 #define CLOCK_REALTIME_PRECISE CLOCK_REALTIME 220 #endif 221 222 #ifndef CLOCK_MONOTONIC_PRECISE 223 #define CLOCK_MONOTONIC_PRECISE CLOCK_MONOTONIC 224 #endif 225 226 // FreeBSD has "_FAST", Linux has "_COARSE". 227 // MacOS has an "_APPROX" but only for CLOCK_MONOTONIC_RAW, which isn't helpful. 228 #ifndef CLOCK_REALTIME_COARSE 229 #ifdef CLOCK_REALTIME_FAST 230 #define CLOCK_REALTIME_COARSE CLOCK_REALTIME_FAST 231 #else 232 #define CLOCK_REALTIME_COARSE CLOCK_REALTIME 233 #endif 234 #endif 235 236 #ifndef CLOCK_MONOTONIC_COARSE 237 #ifdef CLOCK_MONOTONIC_FAST 238 #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST 239 #else 240 #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC 241 #endif 242 #endif 243 244 const Clock& systemCoarseCalendarClock() { 245 static constexpr PosixClock clock(CLOCK_REALTIME_COARSE); 246 return clock; 247 } 248 const Clock& systemPreciseCalendarClock() { 249 static constexpr PosixClock clock(CLOCK_REALTIME_PRECISE); 250 return clock; 251 } 252 253 const MonotonicClock& systemCoarseMonotonicClock() { 254 static constexpr PosixMonotonicClock clock(CLOCK_MONOTONIC_COARSE); 255 return clock; 256 } 257 const MonotonicClock& systemPreciseMonotonicClock() { 258 static constexpr PosixMonotonicClock clock(CLOCK_MONOTONIC_PRECISE); 259 return clock; 260 } 261 262 #endif 263 264 CappedArray<char, sizeof(int64_t) * 3 + 2 + 4> KJ_STRINGIFY(TimePoint t) { 265 return kj::toCharSequence(t - kj::origin<TimePoint>()); 266 } 267 CappedArray<char, sizeof(int64_t) * 3 + 2 + 4> KJ_STRINGIFY(Date d) { 268 return kj::toCharSequence(d - UNIX_EPOCH); 269 } 270 CappedArray<char, sizeof(int64_t) * 3 + 2 + 4> KJ_STRINGIFY(Duration d) { 271 auto digits = kj::toCharSequence(d / kj::NANOSECONDS); 272 ArrayPtr<char> arr = digits; 273 274 size_t point; 275 kj::StringPtr suffix; 276 kj::Duration unit; 277 if (digits.size() > 9) { 278 point = arr.size() - 9; 279 suffix = "s"; 280 unit = kj::SECONDS; 281 } else if (digits.size() > 6) { 282 point = arr.size() - 6; 283 suffix = "ms"; 284 unit = kj::MILLISECONDS; 285 } else if (digits.size() > 3) { 286 point = arr.size() - 3; 287 suffix = "μs"; 288 unit = kj::MICROSECONDS; 289 } else { 290 point = arr.size(); 291 suffix = "ns"; 292 unit = kj::NANOSECONDS; 293 } 294 295 CappedArray<char, sizeof(int64_t) * 3 + 2 + 4> result; 296 char *end; 297 if (d % unit == 0 * kj::NANOSECONDS) { 298 end = _::fillLimited(result.begin(), result.end(), arr.slice(0, point), suffix); 299 } else { 300 while (arr.back() == '0') { 301 arr = arr.slice(0, arr.size() - 1); 302 } 303 KJ_DASSERT(arr.size() > point); 304 end = _::fillLimited(result.begin(), result.end(), arr.slice(0, point), "."_kj, 305 arr.slice(point, arr.size()), suffix); 306 } 307 result.setSize(end - result.begin()); 308 return result; 309 } 310 311 } // namespace kj