| 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 | |