1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/ds/TimeStamp.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,377 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_TimeStamp_h 1.11 +#define mozilla_TimeStamp_h 1.12 + 1.13 +#include <stdint.h> 1.14 +#include "mozilla/Assertions.h" 1.15 +#include "mozilla/Attributes.h" 1.16 +#include "nscore.h" 1.17 + 1.18 +namespace IPC { 1.19 +template <typename T> struct ParamTraits; 1.20 +} 1.21 + 1.22 +#ifdef XP_WIN 1.23 +// defines TimeStampValue as a complex value keeping both 1.24 +// GetTickCount and QueryPerformanceCounter values 1.25 +#include "TimeStamp_windows.h" 1.26 +#endif 1.27 + 1.28 +namespace mozilla { 1.29 + 1.30 +#ifndef XP_WIN 1.31 +typedef uint64_t TimeStampValue; 1.32 +#endif 1.33 + 1.34 +class TimeStamp; 1.35 + 1.36 +/** 1.37 + * Instances of this class represent the length of an interval of time. 1.38 + * Negative durations are allowed, meaning the end is before the start. 1.39 + * 1.40 + * Internally the duration is stored as a int64_t in units of 1.41 + * PR_TicksPerSecond() when building with NSPR interval timers, or a 1.42 + * system-dependent unit when building with system clocks. The 1.43 + * system-dependent unit must be constant, otherwise the semantics of 1.44 + * this class would be broken. 1.45 + */ 1.46 +class TimeDuration 1.47 +{ 1.48 +public: 1.49 + // The default duration is 0. 1.50 + MOZ_CONSTEXPR TimeDuration() : mValue(0) {} 1.51 + // Allow construction using '0' as the initial value, for readability, 1.52 + // but no other numbers (so we don't have any implicit unit conversions). 1.53 + struct _SomethingVeryRandomHere; 1.54 + TimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) { 1.55 + MOZ_ASSERT(!aZero, "Who's playing funny games here?"); 1.56 + } 1.57 + // Default copy-constructor and assignment are OK 1.58 + 1.59 + double ToSeconds() const; 1.60 + // Return a duration value that includes digits of time we think to 1.61 + // be significant. This method should be used when displaying a 1.62 + // time to humans. 1.63 + double ToSecondsSigDigits() const; 1.64 + double ToMilliseconds() const { 1.65 + return ToSeconds() * 1000.0; 1.66 + } 1.67 + double ToMicroseconds() const { 1.68 + return ToMilliseconds() * 1000.0; 1.69 + } 1.70 + 1.71 + // Using a double here is safe enough; with 53 bits we can represent 1.72 + // durations up to over 280,000 years exactly. If the units of 1.73 + // mValue do not allow us to represent durations of that length, 1.74 + // long durations are clamped to the max/min representable value 1.75 + // instead of overflowing. 1.76 + static inline TimeDuration FromSeconds(double aSeconds) { 1.77 + return FromMilliseconds(aSeconds * 1000.0); 1.78 + } 1.79 + static TimeDuration FromMilliseconds(double aMilliseconds); 1.80 + static inline TimeDuration FromMicroseconds(double aMicroseconds) { 1.81 + return FromMilliseconds(aMicroseconds / 1000.0); 1.82 + } 1.83 + 1.84 + static TimeDuration Forever() { 1.85 + return FromTicks(INT64_MAX); 1.86 + } 1.87 + 1.88 + TimeDuration operator+(const TimeDuration& aOther) const { 1.89 + return TimeDuration::FromTicks(mValue + aOther.mValue); 1.90 + } 1.91 + TimeDuration operator-(const TimeDuration& aOther) const { 1.92 + return TimeDuration::FromTicks(mValue - aOther.mValue); 1.93 + } 1.94 + TimeDuration& operator+=(const TimeDuration& aOther) { 1.95 + mValue += aOther.mValue; 1.96 + return *this; 1.97 + } 1.98 + TimeDuration& operator-=(const TimeDuration& aOther) { 1.99 + mValue -= aOther.mValue; 1.100 + return *this; 1.101 + } 1.102 + 1.103 +private: 1.104 + // Block double multiplier (slower, imprecise if long duration) - Bug 853398. 1.105 + // If required, use MultDouble explicitly and with care. 1.106 + TimeDuration operator*(const double aMultiplier) const MOZ_DELETE; 1.107 + 1.108 +public: 1.109 + TimeDuration MultDouble(double aMultiplier) const { 1.110 + return TimeDuration::FromTicks(static_cast<int64_t>(mValue * aMultiplier)); 1.111 + } 1.112 + TimeDuration operator*(const int32_t aMultiplier) const { 1.113 + return TimeDuration::FromTicks(mValue * int64_t(aMultiplier)); 1.114 + } 1.115 + TimeDuration operator*(const uint32_t aMultiplier) const { 1.116 + return TimeDuration::FromTicks(mValue * int64_t(aMultiplier)); 1.117 + } 1.118 + TimeDuration operator*(const int64_t aMultiplier) const { 1.119 + return TimeDuration::FromTicks(mValue * int64_t(aMultiplier)); 1.120 + } 1.121 + TimeDuration operator/(const int64_t aDivisor) const { 1.122 + return TimeDuration::FromTicks(mValue / aDivisor); 1.123 + } 1.124 + double operator/(const TimeDuration& aOther) const { 1.125 + return static_cast<double>(mValue) / aOther.mValue; 1.126 + } 1.127 + 1.128 + bool operator<(const TimeDuration& aOther) const { 1.129 + return mValue < aOther.mValue; 1.130 + } 1.131 + bool operator<=(const TimeDuration& aOther) const { 1.132 + return mValue <= aOther.mValue; 1.133 + } 1.134 + bool operator>=(const TimeDuration& aOther) const { 1.135 + return mValue >= aOther.mValue; 1.136 + } 1.137 + bool operator>(const TimeDuration& aOther) const { 1.138 + return mValue > aOther.mValue; 1.139 + } 1.140 + bool operator==(const TimeDuration& aOther) const { 1.141 + return mValue == aOther.mValue; 1.142 + } 1.143 + 1.144 + // Return a best guess at the system's current timing resolution, 1.145 + // which might be variable. TimeDurations below this order of 1.146 + // magnitude are meaningless, and those at the same order of 1.147 + // magnitude or just above are suspect. 1.148 + static TimeDuration Resolution(); 1.149 + 1.150 + // We could define additional operators here: 1.151 + // -- convert to/from other time units 1.152 + // -- scale duration by a float 1.153 + // but let's do that on demand. 1.154 + // Comparing durations for equality will only lead to bugs on 1.155 + // platforms with high-resolution timers. 1.156 + 1.157 +private: 1.158 + friend class TimeStamp; 1.159 + friend struct IPC::ParamTraits<mozilla::TimeDuration>; 1.160 + 1.161 + static TimeDuration FromTicks(int64_t aTicks) { 1.162 + TimeDuration t; 1.163 + t.mValue = aTicks; 1.164 + return t; 1.165 + } 1.166 + 1.167 + static TimeDuration FromTicks(double aTicks) { 1.168 + // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX)) 1.169 + // overflows and gives INT64_MIN. 1.170 + if (aTicks >= double(INT64_MAX)) 1.171 + return TimeDuration::FromTicks(INT64_MAX); 1.172 + 1.173 + // This MUST be a <= test. 1.174 + if (aTicks <= double(INT64_MIN)) 1.175 + return TimeDuration::FromTicks(INT64_MIN); 1.176 + 1.177 + return TimeDuration::FromTicks(int64_t(aTicks)); 1.178 + } 1.179 + 1.180 + // Duration, result is implementation-specific difference of two TimeStamps 1.181 + int64_t mValue; 1.182 +}; 1.183 + 1.184 +/** 1.185 + * Instances of this class represent moments in time, or a special 1.186 + * "null" moment. We do not use the non-monotonic system clock or 1.187 + * local time, since they can be reset, causing apparent backward 1.188 + * travel in time, which can confuse algorithms. Instead we measure 1.189 + * elapsed time according to the system. This time can never go 1.190 + * backwards (i.e. it never wraps around, at least not in less than 1.191 + * five million years of system elapsed time). It might not advance 1.192 + * while the system is sleeping. If TimeStamp::SetNow() is not called 1.193 + * at all for hours or days, we might not notice the passage of some 1.194 + * of that time. 1.195 + * 1.196 + * We deliberately do not expose a way to convert TimeStamps to some 1.197 + * particular unit. All you can do is compute a difference between two 1.198 + * TimeStamps to get a TimeDuration. You can also add a TimeDuration 1.199 + * to a TimeStamp to get a new TimeStamp. You can't do something 1.200 + * meaningless like add two TimeStamps. 1.201 + * 1.202 + * Internally this is implemented as either a wrapper around 1.203 + * - high-resolution, monotonic, system clocks if they exist on this 1.204 + * platform 1.205 + * - PRIntervalTime otherwise. We detect wraparounds of 1.206 + * PRIntervalTime and work around them. 1.207 + * 1.208 + * This class is similar to C++11's time_point, however it is 1.209 + * explicitly nullable and provides an IsNull() method. time_point 1.210 + * is initialized to the clock's epoch and provides a 1.211 + * time_since_epoch() method that functions similiarly. i.e. 1.212 + * t.IsNull() is equivalent to t.time_since_epoch() == decltype(t)::duration::zero(); 1.213 + */ 1.214 +class TimeStamp 1.215 +{ 1.216 +public: 1.217 + /** 1.218 + * Initialize to the "null" moment 1.219 + */ 1.220 + MOZ_CONSTEXPR TimeStamp() : mValue(0) {} 1.221 + // Default copy-constructor and assignment are OK 1.222 + 1.223 + /** 1.224 + * Return true if this is the "null" moment 1.225 + */ 1.226 + bool IsNull() const { return mValue == 0; } 1.227 + /** 1.228 + * Return a timestamp reflecting the current elapsed system time. This 1.229 + * is monotonically increasing (i.e., does not decrease) over the 1.230 + * lifetime of this process' XPCOM session. 1.231 + * 1.232 + * Now() is trying to ensure the best possible precision on each platform, 1.233 + * at least one millisecond. 1.234 + * 1.235 + * NowLoRes() has been introduced to workaround performance problems of 1.236 + * QueryPerformanceCounter on the Windows platform. NowLoRes() is giving 1.237 + * lower precision, usually 15.6 ms, but with very good performance benefit. 1.238 + * Use it for measurements of longer times, like >200ms timeouts. 1.239 + */ 1.240 + static TimeStamp Now() { return Now(true); } 1.241 + static TimeStamp NowLoRes() { return Now(false); } 1.242 + 1.243 + /** 1.244 + * Return a timestamp representing the time when the current process was 1.245 + * created which will be comparable with other timestamps taken with this 1.246 + * class. If the actual process creation time is detected to be inconsistent 1.247 + * the @a aIsInconsistent parameter will be set to true, the returned 1.248 + * timestamp however will still be valid though inaccurate. 1.249 + * 1.250 + * @param aIsInconsistent Set to true if an inconsistency was detected in the 1.251 + * process creation time 1.252 + * @returns A timestamp representing the time when the process was created, 1.253 + * this timestamp is always valid even when errors are reported 1.254 + */ 1.255 + static TimeStamp ProcessCreation(bool& aIsInconsistent); 1.256 + 1.257 + /** 1.258 + * Records a process restart. After this call ProcessCreation() will return 1.259 + * the time when the browser was restarted instead of the actual time when 1.260 + * the process was created. 1.261 + */ 1.262 + static void RecordProcessRestart(); 1.263 + 1.264 + /** 1.265 + * Compute the difference between two timestamps. Both must be non-null. 1.266 + */ 1.267 + TimeDuration operator-(const TimeStamp& aOther) const { 1.268 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.269 + MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 1.270 + static_assert(-INT64_MAX > INT64_MIN, "int64_t sanity check"); 1.271 + int64_t ticks = int64_t(mValue - aOther.mValue); 1.272 + // Check for overflow. 1.273 + if (mValue > aOther.mValue) { 1.274 + if (ticks < 0) { 1.275 + ticks = INT64_MAX; 1.276 + } 1.277 + } else { 1.278 + if (ticks > 0) { 1.279 + ticks = INT64_MIN; 1.280 + } 1.281 + } 1.282 + return TimeDuration::FromTicks(ticks); 1.283 + } 1.284 + 1.285 + TimeStamp operator+(const TimeDuration& aOther) const { 1.286 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.287 + return TimeStamp(mValue + aOther.mValue); 1.288 + } 1.289 + TimeStamp operator-(const TimeDuration& aOther) const { 1.290 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.291 + return TimeStamp(mValue - aOther.mValue); 1.292 + } 1.293 + TimeStamp& operator+=(const TimeDuration& aOther) { 1.294 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.295 + mValue += aOther.mValue; 1.296 + return *this; 1.297 + } 1.298 + TimeStamp& operator-=(const TimeDuration& aOther) { 1.299 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.300 + mValue -= aOther.mValue; 1.301 + return *this; 1.302 + } 1.303 + 1.304 + bool operator<(const TimeStamp& aOther) const { 1.305 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.306 + MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 1.307 + return mValue < aOther.mValue; 1.308 + } 1.309 + bool operator<=(const TimeStamp& aOther) const { 1.310 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.311 + MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 1.312 + return mValue <= aOther.mValue; 1.313 + } 1.314 + bool operator>=(const TimeStamp& aOther) const { 1.315 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.316 + MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 1.317 + return mValue >= aOther.mValue; 1.318 + } 1.319 + bool operator>(const TimeStamp& aOther) const { 1.320 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.321 + MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 1.322 + return mValue > aOther.mValue; 1.323 + } 1.324 + bool operator==(const TimeStamp& aOther) const { 1.325 + // Maybe it's ok to check == with null timestamps? 1.326 + MOZ_ASSERT(!IsNull() && "Cannot compute with a null value"); 1.327 + MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 1.328 + return mValue == aOther.mValue; 1.329 + } 1.330 + bool operator!=(const TimeStamp& aOther) const { 1.331 + // Maybe it's ok to check != with null timestamps? 1.332 + MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); 1.333 + MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); 1.334 + return mValue != aOther.mValue; 1.335 + } 1.336 + 1.337 + // Comparing TimeStamps for equality should be discouraged. Adding 1.338 + // two TimeStamps, or scaling TimeStamps, is nonsense and must never 1.339 + // be allowed. 1.340 + 1.341 + static NS_HIDDEN_(nsresult) Startup(); 1.342 + static NS_HIDDEN_(void) Shutdown(); 1.343 + 1.344 +private: 1.345 + friend struct IPC::ParamTraits<mozilla::TimeStamp>; 1.346 + friend void StartupTimelineRecordExternal(int, uint64_t); 1.347 + 1.348 + TimeStamp(TimeStampValue aValue) : mValue(aValue) {} 1.349 + 1.350 + static TimeStamp Now(bool aHighResolution); 1.351 + 1.352 + /** 1.353 + * Computes the uptime of the current process in microseconds. The result 1.354 + * is platform-dependent and needs to be checked against existing timestamps 1.355 + * for consistency. 1.356 + * 1.357 + * @returns The number of microseconds since the calling process was started 1.358 + * or 0 if an error was encountered while computing the uptime 1.359 + */ 1.360 + static uint64_t ComputeProcessUptime(); 1.361 + 1.362 + /** 1.363 + * When built with PRIntervalTime, a value of 0 means this instance 1.364 + * is "null". Otherwise, the low 32 bits represent a PRIntervalTime, 1.365 + * and the high 32 bits represent a counter of the number of 1.366 + * rollovers of PRIntervalTime that we've seen. This counter starts 1.367 + * at 1 to avoid a real time colliding with the "null" value. 1.368 + * 1.369 + * PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum 1.370 + * time to wrap around is about 2^64/100000 seconds, i.e. about 1.371 + * 5,849,424 years. 1.372 + * 1.373 + * When using a system clock, a value is system dependent. 1.374 + */ 1.375 + TimeStampValue mValue; 1.376 +}; 1.377 + 1.378 +} 1.379 + 1.380 +#endif /* mozilla_TimeStamp_h */