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 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
179QElapsedTimer::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*/
197bool 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*/
224void 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*/
254qint64 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*/
275auto 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*/
295qint64 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*/
309qint64 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*/
330qint64 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*/
348auto 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*/
365qint64 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*/
381qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept
382{
383 using namespace std::chrono;
384 return duration_cast<seconds>(d: durationTo(other)).count();
385}
386
387static 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*/
399void 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*/
410bool 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*/
425bool 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
432bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
433{
434 return lhs.t1 < rhs.t1;
435}
436
437QT_END_NAMESPACE
438

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