1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qelapsedtimer.h" |
5 | |
6 | QT_BEGIN_NAMESPACE |
7 | |
8 | /*! |
9 | \class QElapsedTimer |
10 | \inmodule QtCore |
11 | \brief The QElapsedTimer class provides a fast way to calculate elapsed times. |
12 | \since 4.7 |
13 | |
14 | \reentrant |
15 | \ingroup tools |
16 | |
17 | \compares strong |
18 | |
19 | The QElapsedTimer class is usually used to quickly calculate how much |
20 | time has elapsed between two events. Its API is similar to that of QTime, |
21 | so code that was using that can be ported quickly to the new class. |
22 | |
23 | However, unlike QTime, QElapsedTimer tries to use monotonic clocks if |
24 | possible. This means it's not possible to convert QElapsedTimer objects |
25 | to a human-readable time. |
26 | |
27 | The typical use-case for the class is to determine how much time was |
28 | spent in a slow operation. The simplest example of such a case is for |
29 | debugging purposes, as in the following example: |
30 | |
31 | \snippet qelapsedtimer/main.cpp 0 |
32 | |
33 | In this example, the timer is started by a call to start() and the |
34 | elapsed time is calculated by the elapsed() function. |
35 | |
36 | The time elapsed can also be used to recalculate the time available for |
37 | another operation, after the first one is complete. This is useful when |
38 | the execution must complete within a certain time period, but several |
39 | steps are needed. The \tt{waitFor}-type functions in QIODevice and its |
40 | subclasses are good examples of such need. In that case, the code could |
41 | be as follows: |
42 | |
43 | \snippet qelapsedtimer/main.cpp 1 |
44 | |
45 | Another use-case is to execute a certain operation for a specific |
46 | timeslice. For this, QElapsedTimer provides the hasExpired() convenience |
47 | function, which can be used to determine if a certain number of |
48 | milliseconds has already elapsed: |
49 | |
50 | \snippet qelapsedtimer/main.cpp 2 |
51 | |
52 | It is often more convenient to use \l{QDeadlineTimer} in this case, which |
53 | counts towards a timeout in the future instead of tracking elapsed time. |
54 | |
55 | \section1 Reference Clocks |
56 | |
57 | QElapsedTimer will use the platform's monotonic reference clock in all |
58 | platforms that support it (see QElapsedTimer::isMonotonic()). This has |
59 | the added benefit that QElapsedTimer is immune to time adjustments, such |
60 | as the user correcting the time. Also unlike QTime, QElapsedTimer is |
61 | immune to changes in the timezone settings, such as daylight-saving |
62 | periods. |
63 | |
64 | On the other hand, this means QElapsedTimer values can only be compared |
65 | with other values that use the same reference. This is especially true if |
66 | the time since the reference is extracted from the QElapsedTimer object |
67 | (QElapsedTimer::msecsSinceReference()) and serialised. These values |
68 | should never be exchanged across the network or saved to disk, since |
69 | there's no telling whether the computer node receiving the data is the |
70 | same as the one originating it or if it has rebooted since. |
71 | |
72 | It is, however, possible to exchange the value with other processes |
73 | running on the same machine, provided that they also use the same |
74 | reference clock. QElapsedTimer will always use the same clock, so it's |
75 | safe to compare with the value coming from another process in the same |
76 | machine. If comparing to values produced by other APIs, you should check |
77 | that the clock used is the same as QElapsedTimer (see |
78 | QElapsedTimer::clockType()). |
79 | |
80 | \sa QTime, QChronoTimer, QDeadlineTimer |
81 | */ |
82 | |
83 | /*! |
84 | \enum QElapsedTimer::ClockType |
85 | |
86 | This enum contains the different clock types that QElapsedTimer may use. |
87 | |
88 | QElapsedTimer will always use the same clock type in a particular |
89 | machine, so this value will not change during the lifetime of a program. |
90 | It is provided so that QElapsedTimer can be used with other non-Qt |
91 | implementations, to guarantee that the same reference clock is being |
92 | used. |
93 | |
94 | \value SystemTime The human-readable system time. This clock is not monotonic. |
95 | \value MonotonicClock The system's monotonic clock, usually found in Unix systems. |
96 | This clock is monotonic. |
97 | \value TickCounter Not used anymore. |
98 | \value MachAbsoluteTime The Mach kernel's absolute time (\macos and iOS). |
99 | This clock is monotonic. |
100 | \value PerformanceCounter The performance counter provided by Windows. |
101 | This clock is monotonic. |
102 | |
103 | \section2 SystemTime |
104 | |
105 | The system time clock is purely the real time, expressed in milliseconds |
106 | since Jan 1, 1970 at 0:00 UTC. It's equivalent to the value returned by |
107 | the C and POSIX \tt{time} function, with the milliseconds added. This |
108 | clock type is currently only used on Unix systems that do not support |
109 | monotonic clocks (see below). |
110 | |
111 | This is the only non-monotonic clock that QElapsedTimer may use. |
112 | |
113 | \section2 MonotonicClock |
114 | |
115 | This is the system's monotonic clock, expressed in milliseconds since an |
116 | arbitrary point in the past. This clock type is used on Unix systems |
117 | which support POSIX monotonic clocks (\tt{_POSIX_MONOTONIC_CLOCK}). |
118 | |
119 | \section2 MachAbsoluteTime |
120 | |
121 | This clock type is based on the absolute time presented by Mach kernels, |
122 | such as that found on \macos. This clock type is presented separately |
123 | from MonotonicClock since \macos and iOS are also Unix systems and may support |
124 | a POSIX monotonic clock with values differing from the Mach absolute |
125 | time. |
126 | |
127 | This clock is monotonic. |
128 | |
129 | \section2 PerformanceCounter |
130 | |
131 | This clock uses the Windows functions \tt{QueryPerformanceCounter} and |
132 | \tt{QueryPerformanceFrequency} to access the system's performance counter. |
133 | |
134 | This clock is monotonic. |
135 | |
136 | \sa clockType(), isMonotonic() |
137 | */ |
138 | |
139 | /*! |
140 | \fn QElapsedTimer::QElapsedTimer() |
141 | \since 5.4 |
142 | |
143 | Constructs an invalid QElapsedTimer. A timer becomes valid once it has been |
144 | started. |
145 | |
146 | \sa isValid(), start() |
147 | */ |
148 | |
149 | /*! |
150 | \fn bool QElapsedTimer::operator==(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept |
151 | |
152 | Returns \c true if \a lhs and \a rhs contain the same time, false otherwise. |
153 | */ |
154 | /*! |
155 | \fn bool QElapsedTimer::operator!=(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept |
156 | |
157 | Returns \c true if \a lhs and \a rhs contain different times, false otherwise. |
158 | */ |
159 | /*! |
160 | \fn bool QElapsedTimer::operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept |
161 | |
162 | Returns \c true if \a lhs was started before \a rhs, false otherwise. |
163 | |
164 | The returned value is undefined if one of the two parameters is invalid |
165 | and the other isn't. However, two invalid timers are equal and thus this |
166 | function will return false. |
167 | */ |
168 | |
169 | /*! |
170 | \fn QElapsedTimer::clockType() noexcept |
171 | |
172 | Returns the clock type that this QElapsedTimer implementation uses. |
173 | |
174 | Since Qt 6.6, QElapsedTimer uses \c{std::chrono::steady_clock}, so the |
175 | clock type is always \l MonotonicClock. |
176 | |
177 | \sa isMonotonic() |
178 | */ |
179 | |
180 | QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept |
181 | { |
182 | // we use std::chrono::steady_clock |
183 | return MonotonicClock; |
184 | } |
185 | |
186 | /*! |
187 | \fn QElapsedTimer::isMonotonic() noexcept |
188 | |
189 | Returns \c true if this is a monotonic clock, false otherwise. See the |
190 | information on the different clock types to understand which ones are |
191 | monotonic. |
192 | |
193 | Since Qt 6.6, QElapsedTimer uses \c{std::chrono::steady_clock}, so this |
194 | function now always returns true. |
195 | |
196 | \sa clockType(), QElapsedTimer::ClockType |
197 | */ |
198 | bool QElapsedTimer::isMonotonic() noexcept |
199 | { |
200 | // We trust std::chrono::steady_clock to be steady (monotonic); if the |
201 | // Standard Library is lying to us, users must complain to their vendor. |
202 | return true; |
203 | } |
204 | |
205 | /*! |
206 | \typealias QElapsedTimer::Duration |
207 | Synonym for \c std::chrono::nanoseconds. |
208 | */ |
209 | |
210 | /*! |
211 | \typealias QElapsedTimer::TimePoint |
212 | Synonym for \c {std::chrono::time_point<std::chrono::steady_clock, Duration>}. |
213 | */ |
214 | |
215 | /*! |
216 | Starts this timer. Once started, a timer value can be checked with elapsed() or msecsSinceReference(). |
217 | |
218 | Normally, a timer is started just before a lengthy operation, such as: |
219 | \snippet qelapsedtimer/main.cpp 0 |
220 | |
221 | Also, starting a timer makes it valid again. |
222 | |
223 | \sa restart(), invalidate(), elapsed() |
224 | */ |
225 | void QElapsedTimer::start() noexcept |
226 | { |
227 | static_assert(sizeof(t1) == sizeof(Duration::rep)); |
228 | |
229 | // This assignment will work so long as TimePoint uses the same time |
230 | // duration or one of finer granularity than steady_clock::time_point. That |
231 | // means it will work until the first steady_clock using picoseconds. |
232 | TimePoint now = std::chrono::steady_clock::now(); |
233 | t1 = now.time_since_epoch().count(); |
234 | QT6_ONLY(t2 = 0); |
235 | } |
236 | |
237 | /*! |
238 | Restarts the timer and returns the number of milliseconds elapsed since |
239 | the previous start. |
240 | This function is equivalent to obtaining the elapsed time with elapsed() |
241 | and then starting the timer again with start(), but it does so in one |
242 | single operation, avoiding the need to obtain the clock value twice. |
243 | |
244 | Calling this function on a QElapsedTimer that is invalid |
245 | results in undefined behavior. |
246 | |
247 | The following example illustrates how to use this function to calibrate a |
248 | parameter to a slow operation (for example, an iteration count) so that |
249 | this operation takes at least 250 milliseconds: |
250 | |
251 | \snippet qelapsedtimer/main.cpp 3 |
252 | |
253 | \sa start(), invalidate(), elapsed(), isValid() |
254 | */ |
255 | qint64 QElapsedTimer::restart() noexcept |
256 | { |
257 | QElapsedTimer old = *this; |
258 | start(); |
259 | return old.msecsTo(other: *this); |
260 | } |
261 | |
262 | /*! |
263 | \since 6.6 |
264 | |
265 | Returns a \c{std::chrono::nanoseconds} with the time since this QElapsedTimer was last |
266 | started. |
267 | |
268 | Calling this function on a QElapsedTimer that is invalid |
269 | results in undefined behavior. |
270 | |
271 | On platforms that do not provide nanosecond resolution, the value returned |
272 | will be the best estimate available. |
273 | |
274 | \sa start(), restart(), hasExpired(), invalidate() |
275 | */ |
276 | auto QElapsedTimer::durationElapsed() const noexcept -> Duration |
277 | { |
278 | TimePoint then{Duration(t1)}; |
279 | return std::chrono::steady_clock::now() - then; |
280 | } |
281 | |
282 | /*! |
283 | \since 4.8 |
284 | |
285 | Returns the number of nanoseconds since this QElapsedTimer was last |
286 | started. |
287 | |
288 | Calling this function on a QElapsedTimer that is invalid |
289 | results in undefined behavior. |
290 | |
291 | On platforms that do not provide nanosecond resolution, the value returned |
292 | will be the best estimate available. |
293 | |
294 | \sa start(), restart(), hasExpired(), invalidate() |
295 | */ |
296 | qint64 QElapsedTimer::nsecsElapsed() const noexcept |
297 | { |
298 | return durationElapsed().count(); |
299 | } |
300 | |
301 | /*! |
302 | Returns the number of milliseconds since this QElapsedTimer was last |
303 | started. |
304 | |
305 | Calling this function on a QElapsedTimer that is invalid |
306 | results in undefined behavior. |
307 | |
308 | \sa start(), restart(), hasExpired(), isValid(), invalidate() |
309 | */ |
310 | qint64 QElapsedTimer::elapsed() const noexcept |
311 | { |
312 | using namespace std::chrono; |
313 | return duration_cast<milliseconds>(d: durationElapsed()).count(); |
314 | } |
315 | |
316 | /*! |
317 | Returns the number of milliseconds between last time this QElapsedTimer |
318 | object was started and its reference clock's start. |
319 | |
320 | This number is usually arbitrary for all clocks except the |
321 | QElapsedTimer::SystemTime clock. For that clock type, this number is the |
322 | number of milliseconds since January 1st, 1970 at 0:00 UTC (that is, it |
323 | is the Unix time expressed in milliseconds). |
324 | |
325 | On Linux, Windows and Apple platforms, this value is usually the time |
326 | since the system boot, though it usually does not include the time the |
327 | system has spent in sleep states. |
328 | |
329 | \sa clockType(), elapsed() |
330 | */ |
331 | qint64 QElapsedTimer::msecsSinceReference() const noexcept |
332 | { |
333 | using namespace std::chrono; |
334 | return duration_cast<milliseconds>(d: Duration(t1)).count(); |
335 | } |
336 | |
337 | /*! |
338 | \since 6.6 |
339 | |
340 | Returns the time difference between this QElapsedTimer and \a other as a |
341 | \c{std::chrono::nanoseconds}. If \a other was started before this object, |
342 | the returned value will be negative. If it was started later, the returned |
343 | value will be positive. |
344 | |
345 | The return value is undefined if this object or \a other were invalidated. |
346 | |
347 | \sa secsTo(), elapsed() |
348 | */ |
349 | auto QElapsedTimer::durationTo(const QElapsedTimer &other) const noexcept -> Duration |
350 | { |
351 | Duration d1(t1); |
352 | Duration d2(other.t1); |
353 | return d2 - d1; |
354 | } |
355 | |
356 | /*! |
357 | Returns the number of milliseconds between this QElapsedTimer and \a |
358 | other. If \a other was started before this object, the returned value |
359 | will be negative. If it was started later, the returned value will be |
360 | positive. |
361 | |
362 | The return value is undefined if this object or \a other were invalidated. |
363 | |
364 | \sa secsTo(), elapsed() |
365 | */ |
366 | qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept |
367 | { |
368 | using namespace std::chrono; |
369 | return duration_cast<milliseconds>(d: durationTo(other)).count(); |
370 | } |
371 | |
372 | /*! |
373 | Returns the number of seconds between this QElapsedTimer and \a other. If |
374 | \a other was started before this object, the returned value will be |
375 | negative. If it was started later, the returned value will be positive. |
376 | |
377 | Calling this function on or with a QElapsedTimer that is invalid |
378 | results in undefined behavior. |
379 | |
380 | \sa msecsTo(), elapsed() |
381 | */ |
382 | qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept |
383 | { |
384 | using namespace std::chrono; |
385 | return duration_cast<seconds>(d: durationTo(other)).count(); |
386 | } |
387 | |
388 | static const qint64 invalidData = Q_INT64_C(0x8000000000000000); |
389 | |
390 | /*! |
391 | \fn QElapsedTimer::invalidate() noexcept |
392 | Marks this QElapsedTimer object as invalid. |
393 | |
394 | An invalid object can be checked with isValid(). Calculations of timer |
395 | elapsed since invalid data are undefined and will likely produce bizarre |
396 | results. |
397 | |
398 | \sa isValid(), start(), restart() |
399 | */ |
400 | void QElapsedTimer::invalidate() noexcept |
401 | { |
402 | t1 = t2 = invalidData; |
403 | } |
404 | |
405 | /*! |
406 | Returns \c false if the timer has never been started or invalidated by a |
407 | call to invalidate(). |
408 | |
409 | \sa invalidate(), start(), restart() |
410 | */ |
411 | bool QElapsedTimer::isValid() const noexcept |
412 | { |
413 | return t1 != invalidData && t2 != invalidData; |
414 | } |
415 | |
416 | /*! |
417 | Returns \c true if elapsed() exceeds the given \a timeout, otherwise \c false. |
418 | |
419 | A negative \a timeout is interpreted as infinite, so \c false is returned in |
420 | this case. Otherwise, this is equivalent to \c {elapsed() > timeout}. You |
421 | can do the same for a duration by comparing durationElapsed() to a duration |
422 | timeout. |
423 | |
424 | \sa elapsed(), QDeadlineTimer |
425 | */ |
426 | bool QElapsedTimer::hasExpired(qint64 timeout) const noexcept |
427 | { |
428 | // if timeout is -1, quint64(timeout) is LLINT_MAX, so this will be |
429 | // considered as never expired |
430 | return quint64(elapsed()) > quint64(timeout); |
431 | } |
432 | |
433 | bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept |
434 | { |
435 | return lhs.t1 < rhs.t1; |
436 | } |
437 | |
438 | QT_END_NAMESPACE |
439 | |