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
6QT_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
180QElapsedTimer::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*/
198bool 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*/
225void 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*/
255qint64 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*/
276auto 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*/
296qint64 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*/
310qint64 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*/
331qint64 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*/
349auto 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*/
366qint64 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*/
382qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept
383{
384 using namespace std::chrono;
385 return duration_cast<seconds>(d: durationTo(other)).count();
386}
387
388static 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*/
400void 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*/
411bool 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*/
426bool 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
433bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
434{
435 return lhs.t1 < rhs.t1;
436}
437
438QT_END_NAMESPACE
439

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/corelib/kernel/qelapsedtimer.cpp