TimeStamp.h (20732B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_TimeStamp_h 8 #define mozilla_TimeStamp_h 9 10 #include "mozilla/Assertions.h" 11 #include "mozilla/Attributes.h" 12 #include "mozilla/FloatingPoint.h" 13 #include "mozilla/Types.h" 14 #include <algorithm> // for std::min, std::max 15 #include <ostream> 16 #include <stdint.h> 17 #include <type_traits> 18 19 namespace IPC { 20 template <typename T> 21 struct ParamTraits; 22 } // namespace IPC 23 24 namespace mozilla { 25 26 using TimeStampValue = uint64_t; 27 28 class TimeStamp; 29 class TimeStampTests; 30 31 /** 32 * Platform-specific implementation details of BaseTimeDuration. 33 */ 34 class BaseTimeDurationPlatformUtils { 35 public: 36 static MFBT_API double ToSeconds(int64_t aTicks); 37 static MFBT_API int64_t TicksFromMilliseconds(double aMilliseconds); 38 }; 39 40 /** 41 * Instances of this class represent the length of an interval of time. 42 * Negative durations are allowed, meaning the end is before the start. 43 * 44 * Internally the duration is stored as a system-dependent unit. 45 * 46 * The ValueCalculator template parameter determines how arithmetic 47 * operations are performed on the integer count of ticks (mValue). 48 */ 49 template <typename ValueCalculator> 50 class BaseTimeDuration { 51 public: 52 // The default duration is 0. 53 constexpr BaseTimeDuration() : mValue(0) {} 54 // Allow construction using '0' as the initial value, for readability, 55 // but no other numbers (so we don't have any implicit unit conversions). 56 struct _SomethingVeryRandomHere; 57 MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) { 58 MOZ_ASSERT(!aZero, "Who's playing funny games here?"); 59 } 60 // Default copy-constructor and assignment are OK 61 62 // Converting copy-constructor and assignment operator 63 template <typename E> 64 explicit BaseTimeDuration(const BaseTimeDuration<E>& aOther) 65 : mValue(aOther.mValue) {} 66 67 template <typename E> 68 BaseTimeDuration& operator=(const BaseTimeDuration<E>& aOther) { 69 mValue = aOther.mValue; 70 return *this; 71 } 72 73 // ToSeconds returns the (fractional) number of seconds of the duration 74 // with the maximum representable precision. 75 double ToSeconds() const { 76 if (mValue == INT64_MAX) { 77 return PositiveInfinity<double>(); 78 } 79 if (mValue == INT64_MIN) { 80 return NegativeInfinity<double>(); 81 } 82 return BaseTimeDurationPlatformUtils::ToSeconds(mValue); 83 } 84 // ToMilliseconds returns the (fractional) number of milliseconds of the 85 // duration with the maximum representable precision. 86 double ToMilliseconds() const { return ToSeconds() * 1000.0; } 87 // ToMicroseconds returns the (fractional) number of microseconds of the 88 // duration with the maximum representable precision. 89 double ToMicroseconds() const { return ToMilliseconds() * 1000.0; } 90 91 // Using a double here is safe enough; with 53 bits we can represent 92 // durations up to over 280,000 years exactly. If the units of 93 // mValue do not allow us to represent durations of that length, 94 // long durations are clamped to the max/min representable value 95 // instead of overflowing. 96 static inline BaseTimeDuration FromSeconds(double aSeconds) { 97 return FromMilliseconds(aSeconds * 1000.0); 98 } 99 static BaseTimeDuration FromMilliseconds(double aMilliseconds) { 100 if (aMilliseconds == PositiveInfinity<double>()) { 101 return Forever(); 102 } 103 if (aMilliseconds == NegativeInfinity<double>()) { 104 return FromTicks(INT64_MIN); 105 } 106 return FromTicks( 107 BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds)); 108 } 109 static inline BaseTimeDuration FromMicroseconds(double aMicroseconds) { 110 return FromMilliseconds(aMicroseconds / 1000.0); 111 } 112 113 static constexpr BaseTimeDuration Zero() { return BaseTimeDuration(); } 114 static constexpr BaseTimeDuration Forever() { return FromTicks(INT64_MAX); } 115 116 BaseTimeDuration operator+(const BaseTimeDuration& aOther) const { 117 return FromTicks(ValueCalculator::Add(mValue, aOther.mValue)); 118 } 119 BaseTimeDuration operator-(const BaseTimeDuration& aOther) const { 120 return FromTicks(ValueCalculator::Subtract(mValue, aOther.mValue)); 121 } 122 BaseTimeDuration& operator+=(const BaseTimeDuration& aOther) { 123 mValue = ValueCalculator::Add(mValue, aOther.mValue); 124 return *this; 125 } 126 BaseTimeDuration& operator-=(const BaseTimeDuration& aOther) { 127 mValue = ValueCalculator::Subtract(mValue, aOther.mValue); 128 return *this; 129 } 130 BaseTimeDuration operator-() const { 131 // We don't just use FromTicks(ValueCalculator::Subtract(0, mValue)) 132 // since that won't give the correct result for -TimeDuration::Forever(). 133 int64_t ticks; 134 if (mValue == INT64_MAX) { 135 ticks = INT64_MIN; 136 } else if (mValue == INT64_MIN) { 137 ticks = INT64_MAX; 138 } else { 139 ticks = -mValue; 140 } 141 142 return FromTicks(ticks); 143 } 144 145 static BaseTimeDuration Max(const BaseTimeDuration& aA, 146 const BaseTimeDuration& aB) { 147 return FromTicks(std::max(aA.mValue, aB.mValue)); 148 } 149 static BaseTimeDuration Min(const BaseTimeDuration& aA, 150 const BaseTimeDuration& aB) { 151 return FromTicks(std::min(aA.mValue, aB.mValue)); 152 } 153 154 private: 155 // Block double multiplier (slower, imprecise if long duration) - Bug 853398. 156 // If required, use MultDouble explicitly and with care. 157 BaseTimeDuration operator*(const double aMultiplier) const = delete; 158 159 // Block double divisor (for the same reason, and because dividing by 160 // fractional values would otherwise invoke the int64_t variant, and rounding 161 // the passed argument can then cause divide-by-zero) - Bug 1147491. 162 BaseTimeDuration operator/(const double aDivisor) const = delete; 163 164 public: 165 BaseTimeDuration MultDouble(double aMultiplier) const { 166 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); 167 } 168 BaseTimeDuration operator*(const int32_t aMultiplier) const { 169 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); 170 } 171 BaseTimeDuration operator*(const uint32_t aMultiplier) const { 172 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); 173 } 174 BaseTimeDuration operator*(const int64_t aMultiplier) const { 175 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); 176 } 177 BaseTimeDuration operator*(const uint64_t aMultiplier) const { 178 if (aMultiplier > INT64_MAX) { 179 return Forever(); 180 } 181 return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); 182 } 183 BaseTimeDuration operator/(const int64_t aDivisor) const { 184 MOZ_ASSERT(aDivisor != 0, "Division by zero"); 185 return FromTicks(ValueCalculator::Divide(mValue, aDivisor)); 186 } 187 double operator/(const BaseTimeDuration& aOther) const { 188 MOZ_ASSERT(aOther.mValue != 0, "Division by zero"); 189 return ValueCalculator::DivideDouble(mValue, aOther.mValue); 190 } 191 BaseTimeDuration operator%(const BaseTimeDuration& aOther) const { 192 MOZ_ASSERT(aOther.mValue != 0, "Division by zero"); 193 return FromTicks(ValueCalculator::Modulo(mValue, aOther.mValue)); 194 } 195 196 template <typename E> 197 bool operator<(const BaseTimeDuration<E>& aOther) const { 198 return mValue < aOther.mValue; 199 } 200 template <typename E> 201 bool operator<=(const BaseTimeDuration<E>& aOther) const { 202 return mValue <= aOther.mValue; 203 } 204 template <typename E> 205 bool operator>=(const BaseTimeDuration<E>& aOther) const { 206 return mValue >= aOther.mValue; 207 } 208 template <typename E> 209 bool operator>(const BaseTimeDuration<E>& aOther) const { 210 return mValue > aOther.mValue; 211 } 212 template <typename E> 213 bool operator==(const BaseTimeDuration<E>& aOther) const { 214 return mValue == aOther.mValue; 215 } 216 template <typename E> 217 bool operator!=(const BaseTimeDuration<E>& aOther) const { 218 return mValue != aOther.mValue; 219 } 220 bool IsZero() const { return mValue == 0; } 221 explicit operator bool() const { return mValue != 0; } 222 223 friend std::ostream& operator<<(std::ostream& aStream, 224 const BaseTimeDuration& aDuration) { 225 return aStream << aDuration.ToMilliseconds() << " ms"; 226 } 227 228 // We could define additional operators here: 229 // -- convert to/from other time units 230 // -- scale duration by a float 231 // but let's do that on demand. 232 // Comparing durations for equality will only lead to bugs on 233 // platforms with high-resolution timers. 234 235 private: 236 friend class TimeStamp; 237 friend struct IPC::ParamTraits<mozilla::BaseTimeDuration<ValueCalculator>>; 238 template <typename> 239 friend class BaseTimeDuration; 240 241 static constexpr BaseTimeDuration FromTicks(int64_t aTicks) { 242 BaseTimeDuration t; 243 t.mValue = aTicks; 244 return t; 245 } 246 247 static BaseTimeDuration FromTicks(double aTicks) { 248 // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX)) 249 // overflows and gives INT64_MIN. 250 if (aTicks >= double(INT64_MAX)) { 251 return FromTicks(INT64_MAX); 252 } 253 254 // This MUST be a <= test. 255 if (aTicks <= double(INT64_MIN)) { 256 return FromTicks(INT64_MIN); 257 } 258 259 return FromTicks(int64_t(aTicks)); 260 } 261 262 // Duration, result is implementation-specific difference of two TimeStamps 263 int64_t mValue; 264 }; 265 266 /** 267 * Perform arithmetic operations on the value of a BaseTimeDuration without 268 * doing strict checks on the range of values. 269 */ 270 class TimeDurationValueCalculator { 271 public: 272 static int64_t Add(int64_t aA, int64_t aB) { return aA + aB; } 273 static int64_t Subtract(int64_t aA, int64_t aB) { return aA - aB; } 274 275 template <typename T> 276 static int64_t Multiply(int64_t aA, T aB) { 277 static_assert(std::is_integral_v<T>, 278 "Using integer multiplication routine with non-integer type." 279 " Further specialization required"); 280 return aA * static_cast<int64_t>(aB); 281 } 282 283 static int64_t Divide(int64_t aA, int64_t aB) { return aA / aB; } 284 static double DivideDouble(int64_t aA, int64_t aB) { 285 return static_cast<double>(aA) / aB; 286 } 287 static int64_t Modulo(int64_t aA, int64_t aB) { return aA % aB; } 288 }; 289 290 template <> 291 inline int64_t TimeDurationValueCalculator::Multiply<double>(int64_t aA, 292 double aB) { 293 return static_cast<int64_t>(aA * aB); 294 } 295 296 /** 297 * Specialization of BaseTimeDuration that uses TimeDurationValueCalculator for 298 * arithmetic on the mValue member. 299 * 300 * Use this class for time durations that are *not* expected to hold values of 301 * Forever (or the negative equivalent) or when such time duration are *not* 302 * expected to be used in arithmetic operations. 303 */ 304 typedef BaseTimeDuration<TimeDurationValueCalculator> TimeDuration; 305 306 /** 307 * Instances of this class represent moments in time, or a special 308 * "null" moment. We do not use the non-monotonic system clock or 309 * local time, since they can be reset, causing apparent backward 310 * travel in time, which can confuse algorithms. Instead we measure 311 * elapsed time according to the system. This time can never go 312 * backwards (i.e. it never wraps around, at least not in less than 313 * five million years of system elapsed time). It might not advance 314 * while the system is sleeping. If TimeStamp::SetNow() is not called 315 * at all for hours or days, we might not notice the passage of some 316 * of that time. 317 * 318 * We deliberately do not expose a way to convert TimeStamps to some 319 * particular unit. All you can do is compute a difference between two 320 * TimeStamps to get a TimeDuration. You can also add a TimeDuration 321 * to a TimeStamp to get a new TimeStamp. You can't do something 322 * meaningless like add two TimeStamps. 323 * 324 * Internally this is implemented as a wrapper around high-resolution, 325 * monotonic, platform-dependent system clocks. 326 * 327 * This class is similar to C++11's time_point, however it is 328 * explicitly nullable and provides an IsNull() method. time_point 329 * is initialized to the clock's epoch and provides a 330 * time_since_epoch() method that functions similiarly. i.e. 331 * t.IsNull() is equivalent to t.time_since_epoch() == 332 * decltype(t)::duration::zero(); 333 * 334 * Note that, since TimeStamp objects are small, prefer to pass them by value 335 * unless there is a specific reason not to do so. 336 */ 337 class TimeStamp { 338 public: 339 using DurationType = TimeDuration; 340 /** 341 * Initialize to the "null" moment 342 */ 343 constexpr TimeStamp() : mValue(0) {} 344 // Default copy-constructor and assignment are OK 345 346 /** 347 * The system timestamps are the same as the TimeStamp 348 * retrieved by mozilla::TimeStamp. Since we need this for 349 * vsync timestamps, we enable the creation of mozilla::TimeStamps 350 * on platforms that support vsync aligned refresh drivers / compositors 351 * Verified true as of Jan 31, 2015: B2G and OS X 352 * False on Windows 7 353 * Android's event time uses CLOCK_MONOTONIC via SystemClock.uptimeMilles. 354 * So it is same value of TimeStamp posix implementation. 355 * Wayland/GTK event time also uses CLOCK_MONOTONIC on Weston/Mutter 356 * compositors. 357 * UNTESTED ON OTHER PLATFORMS 358 */ 359 #if defined(XP_DARWIN) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK) 360 static TimeStamp FromSystemTime(int64_t aSystemTime) { 361 static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue), 362 "System timestamp should be same units as TimeStampValue"); 363 return TimeStamp(aSystemTime); 364 } 365 #endif 366 367 /** 368 * Return true if this is the "null" moment 369 */ 370 constexpr bool IsNull() const { return mValue == 0; } 371 372 /** 373 * Return true if this is not the "null" moment, may be used in tests, e.g.: 374 * |if (timestamp) { ... }| 375 */ 376 explicit operator bool() const { return mValue != 0; } 377 378 /** 379 * Return a timestamp reflecting the current elapsed system time. This 380 * is monotonically increasing (i.e., does not decrease) over the 381 * lifetime of this process' XPCOM session. 382 * 383 * Now() is trying to ensure the best possible precision on each platform, 384 * at least one millisecond. 385 */ 386 static TimeStamp Now() { return Now(true); } 387 388 /** 389 * Return a (coarse) timestamp reflecting the current elapsed system time. 390 * NowLoRes() behaves different depending on the OS: 391 * 392 * Windows: NowLoRes() == Now(), uses always QueryPerformanceCounter. 393 * MacOS: NowLoRes() == Now(), uses always mach_absolute_time. 394 * Posix: If the kernel supports CLOCK_MONOTONIC_COARSE use that, 395 * CLOCK_MONOTONIC otherwise. 396 * 397 * Used to promise better performance, which might still be true only for 398 * Posix. 399 */ 400 static TimeStamp NowLoRes() { return Now(false); } 401 402 /** 403 * Return a timestamp representing the time when the current process was 404 * created which will be comparable with other timestamps taken with this 405 * class. 406 * 407 * @returns A timestamp representing the time when the process was created 408 */ 409 static MFBT_API TimeStamp ProcessCreation(); 410 411 /** 412 * Return the very first timestamp that was taken. This can be used instead 413 * of TimeStamp::ProcessCreation() by code that might not allow running the 414 * complex logic required to compute the real process creation. This will 415 * necessarily have been recorded sometimes after TimeStamp::ProcessCreation() 416 * or at best should be equal to it. 417 * 418 * @returns The first tiemstamp that was taken by this process 419 */ 420 static MFBT_API TimeStamp FirstTimeStamp(); 421 422 /** 423 * Records a process restart. After this call ProcessCreation() will return 424 * the time when the browser was restarted instead of the actual time when 425 * the process was created. 426 */ 427 static MFBT_API void RecordProcessRestart(); 428 429 #ifdef XP_LINUX 430 uint64_t RawClockMonotonicNanosecondsSinceBoot() const { 431 return static_cast<uint64_t>(mValue); 432 } 433 #endif 434 435 #ifdef XP_DARWIN 436 // Returns the number of nanoseconds since the mach_absolute_time origin. 437 MFBT_API uint64_t RawMachAbsoluteTimeNanoseconds() const; 438 #endif 439 440 #ifdef XP_WIN 441 uint64_t RawQueryPerformanceCounterValue() const { 442 return static_cast<uint64_t>(mValue); 443 } 444 #endif 445 446 /** 447 * Compute the difference between two timestamps. Both must be non-null. 448 */ 449 TimeDuration operator-(const TimeStamp& aOther) const { 450 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 451 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 452 static_assert(-INT64_MAX > INT64_MIN, "int64_t sanity check"); 453 int64_t ticks = int64_t(mValue - aOther.mValue); 454 // Check for overflow. 455 if (mValue > aOther.mValue) { 456 if (ticks < 0) { 457 ticks = INT64_MAX; 458 } 459 } else { 460 if (ticks > 0) { 461 ticks = INT64_MIN; 462 } 463 } 464 return TimeDuration::FromTicks(ticks); 465 } 466 467 TimeStamp operator+(const TimeDuration& aOther) const { 468 TimeStamp result = *this; 469 result += aOther; 470 return result; 471 } 472 TimeStamp operator-(const TimeDuration& aOther) const { 473 TimeStamp result = *this; 474 result -= aOther; 475 return result; 476 } 477 TimeStamp& operator+=(const TimeDuration& aOther) { 478 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 479 TimeStampValue value = mValue + aOther.mValue; 480 // Check for underflow. 481 // (We don't check for overflow because it's not obvious what the error 482 // behavior should be in that case.) 483 if (aOther.mValue < 0 && value > mValue) { 484 value = 0; 485 } 486 mValue = value; 487 return *this; 488 } 489 TimeStamp& operator-=(const TimeDuration& aOther) { 490 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 491 TimeStampValue value = mValue - aOther.mValue; 492 // Check for underflow. 493 // (We don't check for overflow because it's not obvious what the error 494 // behavior should be in that case.) 495 if (aOther.mValue > 0 && value > mValue) { 496 value = 0; 497 } 498 mValue = value; 499 return *this; 500 } 501 502 constexpr bool operator<(const TimeStamp& aOther) const { 503 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 504 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 505 return mValue < aOther.mValue; 506 } 507 constexpr bool operator<=(const TimeStamp& aOther) const { 508 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 509 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 510 return mValue <= aOther.mValue; 511 } 512 constexpr bool operator>=(const TimeStamp& aOther) const { 513 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 514 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 515 return mValue >= aOther.mValue; 516 } 517 constexpr bool operator>(const TimeStamp& aOther) const { 518 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 519 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 520 return mValue > aOther.mValue; 521 } 522 bool operator==(const TimeStamp& aOther) const { 523 return IsNull() ? aOther.IsNull() 524 : !aOther.IsNull() && mValue == aOther.mValue; 525 } 526 bool operator!=(const TimeStamp& aOther) const { return !(*this == aOther); } 527 528 // Comparing TimeStamps for equality should be discouraged. Adding 529 // two TimeStamps, or scaling TimeStamps, is nonsense and must never 530 // be allowed. 531 532 static MFBT_API void Startup(); 533 static MFBT_API void Shutdown(); 534 535 #if defined(DEBUG) 536 TimeStampValue GetValue() const { return mValue; } 537 #endif 538 539 private: 540 friend struct IPC::ParamTraits<mozilla::TimeStamp>; 541 friend struct TimeStampInitialization; 542 friend class TimeStampTests; 543 544 constexpr MOZ_IMPLICIT TimeStamp(TimeStampValue aValue) : mValue(aValue) {} 545 546 static MFBT_API TimeStamp Now(bool aHighResolution); 547 548 /** 549 * Computes the uptime of the current process in microseconds. The result 550 * is platform-dependent and needs to be checked against existing timestamps 551 * for consistency. 552 * 553 * @returns The number of microseconds since the calling process was started 554 * or 0 if an error was encountered while computing the uptime 555 */ 556 static MFBT_API uint64_t ComputeProcessUptime(); 557 558 /** 559 * When built with PRIntervalTime, a value of 0 means this instance 560 * is "null". Otherwise, the low 32 bits represent a PRIntervalTime, 561 * and the high 32 bits represent a counter of the number of 562 * rollovers of PRIntervalTime that we've seen. This counter starts 563 * at 1 to avoid a real time colliding with the "null" value. 564 * 565 * PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum 566 * time to wrap around is about 2^64/100000 seconds, i.e. about 567 * 5,849,424 years. 568 * 569 * When using a system clock, a value is system dependent. 570 */ 571 TimeStampValue mValue; 572 }; 573 574 } // namespace mozilla 575 576 #endif /* mozilla_TimeStamp_h */