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