|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
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 <stdint.h> |
|
11 #include "mozilla/Assertions.h" |
|
12 #include "mozilla/Attributes.h" |
|
13 #include "nscore.h" |
|
14 |
|
15 namespace IPC { |
|
16 template <typename T> struct ParamTraits; |
|
17 } |
|
18 |
|
19 #ifdef XP_WIN |
|
20 // defines TimeStampValue as a complex value keeping both |
|
21 // GetTickCount and QueryPerformanceCounter values |
|
22 #include "TimeStamp_windows.h" |
|
23 #endif |
|
24 |
|
25 namespace mozilla { |
|
26 |
|
27 #ifndef XP_WIN |
|
28 typedef uint64_t TimeStampValue; |
|
29 #endif |
|
30 |
|
31 class TimeStamp; |
|
32 |
|
33 /** |
|
34 * Instances of this class represent the length of an interval of time. |
|
35 * Negative durations are allowed, meaning the end is before the start. |
|
36 * |
|
37 * Internally the duration is stored as a int64_t in units of |
|
38 * PR_TicksPerSecond() when building with NSPR interval timers, or a |
|
39 * system-dependent unit when building with system clocks. The |
|
40 * system-dependent unit must be constant, otherwise the semantics of |
|
41 * this class would be broken. |
|
42 */ |
|
43 class TimeDuration |
|
44 { |
|
45 public: |
|
46 // The default duration is 0. |
|
47 MOZ_CONSTEXPR TimeDuration() : mValue(0) {} |
|
48 // Allow construction using '0' as the initial value, for readability, |
|
49 // but no other numbers (so we don't have any implicit unit conversions). |
|
50 struct _SomethingVeryRandomHere; |
|
51 TimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) { |
|
52 MOZ_ASSERT(!aZero, "Who's playing funny games here?"); |
|
53 } |
|
54 // Default copy-constructor and assignment are OK |
|
55 |
|
56 double ToSeconds() const; |
|
57 // Return a duration value that includes digits of time we think to |
|
58 // be significant. This method should be used when displaying a |
|
59 // time to humans. |
|
60 double ToSecondsSigDigits() const; |
|
61 double ToMilliseconds() const { |
|
62 return ToSeconds() * 1000.0; |
|
63 } |
|
64 double ToMicroseconds() const { |
|
65 return ToMilliseconds() * 1000.0; |
|
66 } |
|
67 |
|
68 // Using a double here is safe enough; with 53 bits we can represent |
|
69 // durations up to over 280,000 years exactly. If the units of |
|
70 // mValue do not allow us to represent durations of that length, |
|
71 // long durations are clamped to the max/min representable value |
|
72 // instead of overflowing. |
|
73 static inline TimeDuration FromSeconds(double aSeconds) { |
|
74 return FromMilliseconds(aSeconds * 1000.0); |
|
75 } |
|
76 static TimeDuration FromMilliseconds(double aMilliseconds); |
|
77 static inline TimeDuration FromMicroseconds(double aMicroseconds) { |
|
78 return FromMilliseconds(aMicroseconds / 1000.0); |
|
79 } |
|
80 |
|
81 static TimeDuration Forever() { |
|
82 return FromTicks(INT64_MAX); |
|
83 } |
|
84 |
|
85 TimeDuration operator+(const TimeDuration& aOther) const { |
|
86 return TimeDuration::FromTicks(mValue + aOther.mValue); |
|
87 } |
|
88 TimeDuration operator-(const TimeDuration& aOther) const { |
|
89 return TimeDuration::FromTicks(mValue - aOther.mValue); |
|
90 } |
|
91 TimeDuration& operator+=(const TimeDuration& aOther) { |
|
92 mValue += aOther.mValue; |
|
93 return *this; |
|
94 } |
|
95 TimeDuration& operator-=(const TimeDuration& aOther) { |
|
96 mValue -= aOther.mValue; |
|
97 return *this; |
|
98 } |
|
99 |
|
100 private: |
|
101 // Block double multiplier (slower, imprecise if long duration) - Bug 853398. |
|
102 // If required, use MultDouble explicitly and with care. |
|
103 TimeDuration operator*(const double aMultiplier) const MOZ_DELETE; |
|
104 |
|
105 public: |
|
106 TimeDuration MultDouble(double aMultiplier) const { |
|
107 return TimeDuration::FromTicks(static_cast<int64_t>(mValue * aMultiplier)); |
|
108 } |
|
109 TimeDuration operator*(const int32_t aMultiplier) const { |
|
110 return TimeDuration::FromTicks(mValue * int64_t(aMultiplier)); |
|
111 } |
|
112 TimeDuration operator*(const uint32_t aMultiplier) const { |
|
113 return TimeDuration::FromTicks(mValue * int64_t(aMultiplier)); |
|
114 } |
|
115 TimeDuration operator*(const int64_t aMultiplier) const { |
|
116 return TimeDuration::FromTicks(mValue * int64_t(aMultiplier)); |
|
117 } |
|
118 TimeDuration operator/(const int64_t aDivisor) const { |
|
119 return TimeDuration::FromTicks(mValue / aDivisor); |
|
120 } |
|
121 double operator/(const TimeDuration& aOther) const { |
|
122 return static_cast<double>(mValue) / aOther.mValue; |
|
123 } |
|
124 |
|
125 bool operator<(const TimeDuration& aOther) const { |
|
126 return mValue < aOther.mValue; |
|
127 } |
|
128 bool operator<=(const TimeDuration& aOther) const { |
|
129 return mValue <= aOther.mValue; |
|
130 } |
|
131 bool operator>=(const TimeDuration& aOther) const { |
|
132 return mValue >= aOther.mValue; |
|
133 } |
|
134 bool operator>(const TimeDuration& aOther) const { |
|
135 return mValue > aOther.mValue; |
|
136 } |
|
137 bool operator==(const TimeDuration& aOther) const { |
|
138 return mValue == aOther.mValue; |
|
139 } |
|
140 |
|
141 // Return a best guess at the system's current timing resolution, |
|
142 // which might be variable. TimeDurations below this order of |
|
143 // magnitude are meaningless, and those at the same order of |
|
144 // magnitude or just above are suspect. |
|
145 static TimeDuration Resolution(); |
|
146 |
|
147 // We could define additional operators here: |
|
148 // -- convert to/from other time units |
|
149 // -- scale duration by a float |
|
150 // but let's do that on demand. |
|
151 // Comparing durations for equality will only lead to bugs on |
|
152 // platforms with high-resolution timers. |
|
153 |
|
154 private: |
|
155 friend class TimeStamp; |
|
156 friend struct IPC::ParamTraits<mozilla::TimeDuration>; |
|
157 |
|
158 static TimeDuration FromTicks(int64_t aTicks) { |
|
159 TimeDuration t; |
|
160 t.mValue = aTicks; |
|
161 return t; |
|
162 } |
|
163 |
|
164 static TimeDuration FromTicks(double aTicks) { |
|
165 // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX)) |
|
166 // overflows and gives INT64_MIN. |
|
167 if (aTicks >= double(INT64_MAX)) |
|
168 return TimeDuration::FromTicks(INT64_MAX); |
|
169 |
|
170 // This MUST be a <= test. |
|
171 if (aTicks <= double(INT64_MIN)) |
|
172 return TimeDuration::FromTicks(INT64_MIN); |
|
173 |
|
174 return TimeDuration::FromTicks(int64_t(aTicks)); |
|
175 } |
|
176 |
|
177 // Duration, result is implementation-specific difference of two TimeStamps |
|
178 int64_t mValue; |
|
179 }; |
|
180 |
|
181 /** |
|
182 * Instances of this class represent moments in time, or a special |
|
183 * "null" moment. We do not use the non-monotonic system clock or |
|
184 * local time, since they can be reset, causing apparent backward |
|
185 * travel in time, which can confuse algorithms. Instead we measure |
|
186 * elapsed time according to the system. This time can never go |
|
187 * backwards (i.e. it never wraps around, at least not in less than |
|
188 * five million years of system elapsed time). It might not advance |
|
189 * while the system is sleeping. If TimeStamp::SetNow() is not called |
|
190 * at all for hours or days, we might not notice the passage of some |
|
191 * of that time. |
|
192 * |
|
193 * We deliberately do not expose a way to convert TimeStamps to some |
|
194 * particular unit. All you can do is compute a difference between two |
|
195 * TimeStamps to get a TimeDuration. You can also add a TimeDuration |
|
196 * to a TimeStamp to get a new TimeStamp. You can't do something |
|
197 * meaningless like add two TimeStamps. |
|
198 * |
|
199 * Internally this is implemented as either a wrapper around |
|
200 * - high-resolution, monotonic, system clocks if they exist on this |
|
201 * platform |
|
202 * - PRIntervalTime otherwise. We detect wraparounds of |
|
203 * PRIntervalTime and work around them. |
|
204 * |
|
205 * This class is similar to C++11's time_point, however it is |
|
206 * explicitly nullable and provides an IsNull() method. time_point |
|
207 * is initialized to the clock's epoch and provides a |
|
208 * time_since_epoch() method that functions similiarly. i.e. |
|
209 * t.IsNull() is equivalent to t.time_since_epoch() == decltype(t)::duration::zero(); |
|
210 */ |
|
211 class TimeStamp |
|
212 { |
|
213 public: |
|
214 /** |
|
215 * Initialize to the "null" moment |
|
216 */ |
|
217 MOZ_CONSTEXPR TimeStamp() : mValue(0) {} |
|
218 // Default copy-constructor and assignment are OK |
|
219 |
|
220 /** |
|
221 * Return true if this is the "null" moment |
|
222 */ |
|
223 bool IsNull() const { return mValue == 0; } |
|
224 /** |
|
225 * Return a timestamp reflecting the current elapsed system time. This |
|
226 * is monotonically increasing (i.e., does not decrease) over the |
|
227 * lifetime of this process' XPCOM session. |
|
228 * |
|
229 * Now() is trying to ensure the best possible precision on each platform, |
|
230 * at least one millisecond. |
|
231 * |
|
232 * NowLoRes() has been introduced to workaround performance problems of |
|
233 * QueryPerformanceCounter on the Windows platform. NowLoRes() is giving |
|
234 * lower precision, usually 15.6 ms, but with very good performance benefit. |
|
235 * Use it for measurements of longer times, like >200ms timeouts. |
|
236 */ |
|
237 static TimeStamp Now() { return Now(true); } |
|
238 static TimeStamp NowLoRes() { return Now(false); } |
|
239 |
|
240 /** |
|
241 * Return a timestamp representing the time when the current process was |
|
242 * created which will be comparable with other timestamps taken with this |
|
243 * class. If the actual process creation time is detected to be inconsistent |
|
244 * the @a aIsInconsistent parameter will be set to true, the returned |
|
245 * timestamp however will still be valid though inaccurate. |
|
246 * |
|
247 * @param aIsInconsistent Set to true if an inconsistency was detected in the |
|
248 * process creation time |
|
249 * @returns A timestamp representing the time when the process was created, |
|
250 * this timestamp is always valid even when errors are reported |
|
251 */ |
|
252 static TimeStamp ProcessCreation(bool& aIsInconsistent); |
|
253 |
|
254 /** |
|
255 * Records a process restart. After this call ProcessCreation() will return |
|
256 * the time when the browser was restarted instead of the actual time when |
|
257 * the process was created. |
|
258 */ |
|
259 static void RecordProcessRestart(); |
|
260 |
|
261 /** |
|
262 * Compute the difference between two timestamps. Both must be non-null. |
|
263 */ |
|
264 TimeDuration operator-(const TimeStamp& aOther) const { |
|
265 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
266 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); |
|
267 static_assert(-INT64_MAX > INT64_MIN, "int64_t sanity check"); |
|
268 int64_t ticks = int64_t(mValue - aOther.mValue); |
|
269 // Check for overflow. |
|
270 if (mValue > aOther.mValue) { |
|
271 if (ticks < 0) { |
|
272 ticks = INT64_MAX; |
|
273 } |
|
274 } else { |
|
275 if (ticks > 0) { |
|
276 ticks = INT64_MIN; |
|
277 } |
|
278 } |
|
279 return TimeDuration::FromTicks(ticks); |
|
280 } |
|
281 |
|
282 TimeStamp operator+(const TimeDuration& aOther) const { |
|
283 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
284 return TimeStamp(mValue + aOther.mValue); |
|
285 } |
|
286 TimeStamp operator-(const TimeDuration& aOther) const { |
|
287 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
288 return TimeStamp(mValue - aOther.mValue); |
|
289 } |
|
290 TimeStamp& operator+=(const TimeDuration& aOther) { |
|
291 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
292 mValue += aOther.mValue; |
|
293 return *this; |
|
294 } |
|
295 TimeStamp& operator-=(const TimeDuration& aOther) { |
|
296 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
297 mValue -= aOther.mValue; |
|
298 return *this; |
|
299 } |
|
300 |
|
301 bool operator<(const TimeStamp& aOther) const { |
|
302 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
303 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); |
|
304 return mValue < aOther.mValue; |
|
305 } |
|
306 bool operator<=(const TimeStamp& aOther) const { |
|
307 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
308 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); |
|
309 return mValue <= aOther.mValue; |
|
310 } |
|
311 bool operator>=(const TimeStamp& aOther) const { |
|
312 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
313 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); |
|
314 return mValue >= aOther.mValue; |
|
315 } |
|
316 bool operator>(const TimeStamp& aOther) const { |
|
317 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
318 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); |
|
319 return mValue > aOther.mValue; |
|
320 } |
|
321 bool operator==(const TimeStamp& aOther) const { |
|
322 // Maybe it's ok to check == with null timestamps? |
|
323 MOZ_ASSERT(!IsNull() && "Cannot compute with a null value"); |
|
324 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); |
|
325 return mValue == aOther.mValue; |
|
326 } |
|
327 bool operator!=(const TimeStamp& aOther) const { |
|
328 // Maybe it's ok to check != with null timestamps? |
|
329 MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); |
|
330 MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); |
|
331 return mValue != aOther.mValue; |
|
332 } |
|
333 |
|
334 // Comparing TimeStamps for equality should be discouraged. Adding |
|
335 // two TimeStamps, or scaling TimeStamps, is nonsense and must never |
|
336 // be allowed. |
|
337 |
|
338 static NS_HIDDEN_(nsresult) Startup(); |
|
339 static NS_HIDDEN_(void) Shutdown(); |
|
340 |
|
341 private: |
|
342 friend struct IPC::ParamTraits<mozilla::TimeStamp>; |
|
343 friend void StartupTimelineRecordExternal(int, uint64_t); |
|
344 |
|
345 TimeStamp(TimeStampValue aValue) : mValue(aValue) {} |
|
346 |
|
347 static TimeStamp Now(bool aHighResolution); |
|
348 |
|
349 /** |
|
350 * Computes the uptime of the current process in microseconds. The result |
|
351 * is platform-dependent and needs to be checked against existing timestamps |
|
352 * for consistency. |
|
353 * |
|
354 * @returns The number of microseconds since the calling process was started |
|
355 * or 0 if an error was encountered while computing the uptime |
|
356 */ |
|
357 static uint64_t ComputeProcessUptime(); |
|
358 |
|
359 /** |
|
360 * When built with PRIntervalTime, a value of 0 means this instance |
|
361 * is "null". Otherwise, the low 32 bits represent a PRIntervalTime, |
|
362 * and the high 32 bits represent a counter of the number of |
|
363 * rollovers of PRIntervalTime that we've seen. This counter starts |
|
364 * at 1 to avoid a real time colliding with the "null" value. |
|
365 * |
|
366 * PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum |
|
367 * time to wrap around is about 2^64/100000 seconds, i.e. about |
|
368 * 5,849,424 years. |
|
369 * |
|
370 * When using a system clock, a value is system dependent. |
|
371 */ |
|
372 TimeStampValue mValue; |
|
373 }; |
|
374 |
|
375 } |
|
376 |
|
377 #endif /* mozilla_TimeStamp_h */ |