From c9f4c0d45e85c7cd7c6f7c18c3f3391857135ce2 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 22 Feb 2023 13:08:05 -0800 Subject: [PATCH] QElapsedTimer: rewrite using std::chrono::steady_clock everywhere This commit deletes the direct, low-level functionality that QElapsedTimer has carried since it was introduced. Everything now uses only std::chrono::steady_clock and std::chrono::nanoseconds. QDeadlineTimer temporarily still uses qt_gettime(), which is moved to qcore_unix.cpp. Task-number: QTBUG-110059 Change-Id: Ieec322d73c1e40ad95c8fffd174641a469b1eee5 Reviewed-by: Ahmad Samir Reviewed-by: Thiago Macieira --- src/corelib/CMakeLists.txt | 6 - src/corelib/kernel/qcore_unix.cpp | 28 +++ src/corelib/kernel/qdeadlinetimer.cpp | 21 ++ src/corelib/kernel/qelapsedtimer.cpp | 215 ++++++++++++++++++ src/corelib/kernel/qelapsedtimer.h | 9 +- src/corelib/kernel/qelapsedtimer_generic.cpp | 169 -------------- src/corelib/kernel/qelapsedtimer_unix.cpp | 160 ------------- src/corelib/kernel/qelapsedtimer_win.cpp | 123 ---------- src/corelib/kernel/qeventdispatcher_win.cpp | 7 + src/corelib/kernel/qeventdispatcher_win_p.h | 1 - .../qelapsedtimer/tst_qelapsedtimer.cpp | 22 +- 11 files changed, 297 insertions(+), 464 deletions(-) delete mode 100644 src/corelib/kernel/qelapsedtimer_generic.cpp delete mode 100644 src/corelib/kernel/qelapsedtimer_unix.cpp delete mode 100644 src/corelib/kernel/qelapsedtimer_win.cpp diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index c2a3a930b6e..bf46b891578 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -512,7 +512,6 @@ qt_internal_extend_target(Core CONDITION WIN32 io/qwindowspipewriter.cpp io/qwindowspipewriter_p.h io/qntdll_p.h kernel/qcoreapplication_win.cpp - kernel/qelapsedtimer_win.cpp kernel/qeventdispatcher_win.cpp kernel/qeventdispatcher_win_p.h kernel/qfunctions_win.cpp kernel/qfunctions_win_p.h kernel/qfunctions_winrt_p.h ipc/qsharedmemory_win.cpp @@ -972,11 +971,6 @@ qt_internal_extend_target(Core CONDITION APPLE AND NOT MACOS ${FWMobileCoreServices} ) -qt_internal_extend_target(Core CONDITION UNIX - SOURCES - kernel/qelapsedtimer_unix.cpp -) - qt_internal_extend_target(Core CONDITION ANDROID SOURCES io/qstandardpaths_android.cpp diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp index 4a95080c199..78d99a382df 100644 --- a/src/corelib/kernel/qcore_unix.cpp +++ b/src/corelib/kernel/qcore_unix.cpp @@ -65,6 +65,34 @@ int qt_open64(const char *pathname, int flags, mode_t mode) #ifndef QT_BOOTSTRAPPED +static inline void do_gettime(qint64 *sec, qint64 *frac) +{ + timespec ts; + clockid_t clk = CLOCK_REALTIME; +#if defined(CLOCK_MONOTONIC_RAW) + clk = CLOCK_MONOTONIC_RAW; +#elif defined(CLOCK_MONOTONIC) + clk = CLOCK_MONOTONIC; +#endif + + clock_gettime(clk, &ts); + *sec = ts.tv_sec; + *frac = ts.tv_nsec; +} + +// also used in qeventdispatcher_unix.cpp +struct timespec qt_gettime() noexcept +{ + qint64 sec, frac; + do_gettime(&sec, &frac); + + timespec tv; + tv.tv_sec = sec; + tv.tv_nsec = frac; + + return tv; +} + #if QT_CONFIG(poll_pollts) # define ppoll pollts #endif diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp index ef78a71981f..25ac58be4f3 100644 --- a/src/corelib/kernel/qdeadlinetimer.cpp +++ b/src/corelib/kernel/qdeadlinetimer.cpp @@ -5,6 +5,10 @@ #include "qdeadlinetimer_p.h" #include "private/qnumeric_p.h" +#ifdef Q_OS_UNIX +# include "qcore_unix_p.h" +#endif + QT_BEGIN_NAMESPACE QT_IMPL_METATYPE_EXTERN(QDeadlineTimer) @@ -836,6 +840,23 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep The QDeadlineTimer object will be constructed with the specified \a timerType. */ +QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept +{ + QDeadlineTimer result; +#ifdef Q_OS_UNIX + static_assert(QDeadlineTimerNanosecondsInT2); + timespec ts = qt_gettime(); + result.t1 = ts.tv_sec; + result.t2 = ts.tv_nsec; +#else + // ensure we get nanoseconds; this will work so long as steady_clock's + // time_point isn't of finer resolution (picoseconds) + std::chrono::nanoseconds ns = std::chrono::steady_clock::now().time_since_epoch(); + result.t1 = ns.count(); +#endif + result.type = timerType; + return result; +} /*! \fn bool QDeadlineTimer::operator==(QDeadlineTimer d1, QDeadlineTimer d2) diff --git a/src/corelib/kernel/qelapsedtimer.cpp b/src/corelib/kernel/qelapsedtimer.cpp index 39ddb3491c0..66ae82811f7 100644 --- a/src/corelib/kernel/qelapsedtimer.cpp +++ b/src/corelib/kernel/qelapsedtimer.cpp @@ -165,9 +165,219 @@ QT_BEGIN_NAMESPACE function will return false. */ +/*! + \fn QElapsedTimer::clockType() noexcept + + Returns the clock type that this QElapsedTimer implementation uses. + + Since Qt 6.6, QElapsedTimer uses \c{std::chrono::steady_clock}, so the + clock type is always \l MonotonicClock. + + \sa isMonotonic() +*/ + +QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept +{ + // we use std::chrono::steady_clock + return MonotonicClock; +} + +/*! + \fn QElapsedTimer::isMonotonic() noexcept + + Returns \c true if this is a monotonic clock, false otherwise. See the + information on the different clock types to understand which ones are + monotonic. + + Since Qt 6.6, QElapsedTimer uses \c{std::chrono::steady_clock}, so this + function now always returns true. + + \sa clockType(), QElapsedTimer::ClockType +*/ +bool QElapsedTimer::isMonotonic() noexcept +{ + // We trust std::chrono::steady_clock to be steady (monotonic); if the + // Standard Library is lying to us, users must complain to their vendor. + return true; +} + +/*! + Starts this timer. Once started, a timer value can be checked with elapsed() or msecsSinceReference(). + + Normally, a timer is started just before a lengthy operation, such as: + \snippet qelapsedtimer/main.cpp 0 + + Also, starting a timer makes it valid again. + + \sa restart(), invalidate(), elapsed() +*/ +void QElapsedTimer::start() noexcept +{ + static_assert(sizeof(t1) == sizeof(Duration::rep)); + + // This assignment will work so long as TimePoint uses the same time + // duration or one of finer granularity than steady_clock::time_point. That + // means it will work until the first steady_clock using picoseconds. + TimePoint now = std::chrono::steady_clock::now(); + t1 = now.time_since_epoch().count(); + QT6_ONLY(t2 = 0); +} + +/*! + Restarts the timer and returns the number of milliseconds elapsed since + the previous start. + This function is equivalent to obtaining the elapsed time with elapsed() + and then starting the timer again with start(), but it does so in one + single operation, avoiding the need to obtain the clock value twice. + + Calling this function on a QElapsedTimer that is invalid + results in undefined behavior. + + The following example illustrates how to use this function to calibrate a + parameter to a slow operation (for example, an iteration count) so that + this operation takes at least 250 milliseconds: + + \snippet qelapsedtimer/main.cpp 3 + + \sa start(), invalidate(), elapsed(), isValid() +*/ +qint64 QElapsedTimer::restart() noexcept +{ + QElapsedTimer old = *this; + start(); + return old.msecsTo(*this); +} + +/*! + \since 6.6 + + Returns a \c{std::chrono::nanoseconds} with the time since this QElapsedTimer was last + started. + + Calling this function on a QElapsedTimer that is invalid + results in undefined behavior. + + On platforms that do not provide nanosecond resolution, the value returned + will be the best estimate available. + + \sa start(), restart(), hasExpired(), invalidate() +*/ +auto QElapsedTimer::durationElapsed() const noexcept -> Duration +{ + TimePoint then{Duration(t1)}; + return std::chrono::steady_clock::now() - then; +} + +/*! + \since 4.8 + + Returns the number of nanoseconds since this QElapsedTimer was last + started. + + Calling this function on a QElapsedTimer that is invalid + results in undefined behavior. + + On platforms that do not provide nanosecond resolution, the value returned + will be the best estimate available. + + \sa start(), restart(), hasExpired(), invalidate() +*/ +qint64 QElapsedTimer::nsecsElapsed() const noexcept +{ + return durationElapsed().count(); +} + +/*! + Returns the number of milliseconds since this QElapsedTimer was last + started. + + Calling this function on a QElapsedTimer that is invalid + results in undefined behavior. + + \sa start(), restart(), hasExpired(), isValid(), invalidate() +*/ +qint64 QElapsedTimer::elapsed() const noexcept +{ + using namespace std::chrono; + return duration_cast(durationElapsed()).count(); +} + +/*! + Returns the number of milliseconds between last time this QElapsedTimer + object was started and its reference clock's start. + + This number is usually arbitrary for all clocks except the + QElapsedTimer::SystemTime clock. For that clock type, this number is the + number of milliseconds since January 1st, 1970 at 0:00 UTC (that is, it + is the Unix time expressed in milliseconds). + + On Linux, Windows and Apple platforms, this value is usually the time + since the system boot, though it usually does not include the time the + system has spent in sleep states. + + \sa clockType(), elapsed() +*/ +qint64 QElapsedTimer::msecsSinceReference() const noexcept +{ + using namespace std::chrono; + return duration_cast(Duration(t1)).count(); +} + +/*! + \since 6.6 + + Returns the time difference between this QElapsedTimer and \a other as a + \c{std::chrono::nanoseconds}. If \a other was started before this object, + the returned value will be negative. If it was started later, the returned + value will be positive. + + The return value is undefined if this object or \a other were invalidated. + + \sa secsTo(), elapsed() +*/ +auto QElapsedTimer::durationTo(const QElapsedTimer &other) const noexcept -> Duration +{ + Duration d1(t1); + Duration d2(other.t1); + return d2 - d1; +} + +/*! + Returns the number of milliseconds between this QElapsedTimer and \a + other. If \a other was started before this object, the returned value + will be negative. If it was started later, the returned value will be + positive. + + The return value is undefined if this object or \a other were invalidated. + + \sa secsTo(), elapsed() +*/ +qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept +{ + using namespace std::chrono; + return duration_cast(durationTo(other)).count(); +} + +/*! + Returns the number of seconds between this QElapsedTimer and \a other. If + \a other was started before this object, the returned value will be + negative. If it was started later, the returned value will be positive. + + Calling this function on or with a QElapsedTimer that is invalid + results in undefined behavior. + + \sa msecsTo(), elapsed() +*/ +qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept +{ + using namespace std::chrono; + return duration_cast(durationTo(other)).count(); +} + static const qint64 invalidData = Q_INT64_C(0x8000000000000000); /*! + \fn QElapsedTimer::invalidate() noexcept Marks this QElapsedTimer object as invalid. An invalid object can be checked with isValid(). Calculations of timer @@ -207,4 +417,9 @@ bool QElapsedTimer::hasExpired(qint64 timeout) const noexcept return quint64(elapsed()) > quint64(timeout); } +bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept +{ + return lhs.t1 < rhs.t1; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer.h b/src/corelib/kernel/qelapsedtimer.h index ab32265cba1..7d8b889f613 100644 --- a/src/corelib/kernel/qelapsedtimer.h +++ b/src/corelib/kernel/qelapsedtimer.h @@ -6,8 +6,9 @@ #include -QT_BEGIN_NAMESPACE +#include +QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QElapsedTimer { @@ -21,6 +22,10 @@ class Q_CORE_EXPORT QElapsedTimer PerformanceCounter }; + // similar to std::chrono::*_clock + using Duration = std::chrono::nanoseconds; + using TimePoint = std::chrono::time_point; + constexpr QElapsedTimer() = default; static ClockType clockType() noexcept; @@ -31,11 +36,13 @@ class Q_CORE_EXPORT QElapsedTimer void invalidate() noexcept; bool isValid() const noexcept; + Duration durationElapsed() const noexcept; qint64 nsecsElapsed() const noexcept; qint64 elapsed() const noexcept; bool hasExpired(qint64 timeout) const noexcept; qint64 msecsSinceReference() const noexcept; + Duration durationTo(const QElapsedTimer &other) const noexcept; qint64 msecsTo(const QElapsedTimer &other) const noexcept; qint64 secsTo(const QElapsedTimer &other) const noexcept; diff --git a/src/corelib/kernel/qelapsedtimer_generic.cpp b/src/corelib/kernel/qelapsedtimer_generic.cpp deleted file mode 100644 index 874122f4931..00000000000 --- a/src/corelib/kernel/qelapsedtimer_generic.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#include "qelapsedtimer.h" -#include "qdeadlinetimer.h" -#include "qdatetime.h" - -QT_BEGIN_NAMESPACE - -/*! - Returns the clock type that this QElapsedTimer implementation uses. - - \sa isMonotonic() -*/ -QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept -{ - return SystemTime; -} - -/*! - Returns \c true if this is a monotonic clock, false otherwise. See the - information on the different clock types to understand which ones are - monotonic. - - \sa clockType(), QElapsedTimer::ClockType -*/ -bool QElapsedTimer::isMonotonic() noexcept -{ - return false; -} - -/*! - Starts this timer. Once started, a timer value can be checked with elapsed() or msecsSinceReference(). - - Normally, a timer is started just before a lengthy operation, such as: - \snippet qelapsedtimer/main.cpp 0 - - Also, starting a timer makes it valid again. - - \sa restart(), invalidate(), elapsed() -*/ -void QElapsedTimer::start() noexcept -{ - restart(); -} - -/*! - Restarts the timer and returns the number of milliseconds elapsed since - the previous start. - This function is equivalent to obtaining the elapsed time with elapsed() - and then starting the timer again with start(), but it does so in one - single operation, avoiding the need to obtain the clock value twice. - - Calling this function on a QElapsedTimer that is invalid - results in undefined behavior. - - The following example illustrates how to use this function to calibrate a - parameter to a slow operation (for example, an iteration count) so that - this operation takes at least 250 milliseconds: - - \snippet qelapsedtimer/main.cpp 3 - - \sa start(), invalidate(), elapsed(), isValid() -*/ -qint64 QElapsedTimer::restart() noexcept -{ - qint64 old = t1; - t1 = QDateTime::currentMSecsSinceEpoch(); - t2 = 0; - return t1 - old; -} - -/*! \since 4.8 - - Returns the number of nanoseconds since this QElapsedTimer was last - started. - - Calling this function on a QElapsedTimer that is invalid - results in undefined behavior. - - On platforms that do not provide nanosecond resolution, the value returned - will be the best estimate available. - - \sa start(), restart(), hasExpired(), invalidate() -*/ -qint64 QElapsedTimer::nsecsElapsed() const noexcept -{ - return elapsed() * 1000000; -} - -/*! - Returns the number of milliseconds since this QElapsedTimer was last - started. - - Calling this function on a QElapsedTimer that is invalid - results in undefined behavior. - - \sa start(), restart(), hasExpired(), isValid(), invalidate() -*/ -qint64 QElapsedTimer::elapsed() const noexcept -{ - return QDateTime::currentMSecsSinceEpoch() - t1; -} - -/*! - Returns the number of milliseconds between last time this QElapsedTimer - object was started and its reference clock's start. - - This number is usually arbitrary for all clocks except the - QElapsedTimer::SystemTime clock. For that clock type, this number is the - number of milliseconds since January 1st, 1970 at 0:00 UTC (that is, it - is the Unix time expressed in milliseconds). - - On Linux, Windows and Apple platforms, this value is usually the time - since the system boot, though it usually does not include the time the - system has spent in sleep states. - - \sa clockType(), elapsed() -*/ -qint64 QElapsedTimer::msecsSinceReference() const noexcept -{ - return t1; -} - -/*! - Returns the number of milliseconds between this QElapsedTimer and \a - other. If \a other was started before this object, the returned value - will be negative. If it was started later, the returned value will be - positive. - - The return value is undefined if this object or \a other were invalidated. - - \sa secsTo(), elapsed() -*/ -qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept -{ - qint64 diff = other.t1 - t1; - return diff; -} - -/*! - Returns the number of seconds between this QElapsedTimer and \a other. If - \a other was started before this object, the returned value will be - negative. If it was started later, the returned value will be positive. - - Calling this function on or with a QElapsedTimer that is invalid - results in undefined behavior. - - \sa msecsTo(), elapsed() -*/ -qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept -{ - return msecsTo(other) / 1000; -} - -bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept -{ - return lhs.t1 < rhs.t1; -} - -QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept -{ - QDeadlineTimer result; - result.t1 = QDateTime::currentMSecsSinceEpoch() * 1000 * 1000; - result.type = timerType; - return result; -} - -QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer_unix.cpp b/src/corelib/kernel/qelapsedtimer_unix.cpp deleted file mode 100644 index d7a81babb88..00000000000 --- a/src/corelib/kernel/qelapsedtimer_unix.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// Copyright (C) 2016 Intel Corporation. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#include "qelapsedtimer.h" -#include "qdeadlinetimer.h" -#include "qdeadlinetimer_p.h" -#if defined(Q_OS_VXWORKS) -#include "qfunctions_vxworks.h" -#else -#include -#include -#endif -#include - -#include -#include "private/qcore_unix_p.h" - -#if defined(QT_NO_CLOCK_MONOTONIC) || defined(QT_BOOTSTRAPPED) -// turn off the monotonic clock -# ifdef _POSIX_MONOTONIC_CLOCK -# undef _POSIX_MONOTONIC_CLOCK -# endif -# define _POSIX_MONOTONIC_CLOCK -1 -#endif - -QT_BEGIN_NAMESPACE - -/* - * Design: - * - * POSIX offers a facility to select the system's monotonic clock when getting - * the current timestamp. Whereas the functions are mandatory in POSIX.1-2008, - * the presence of a monotonic clock is a POSIX Option (see the document - * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_06 ) - * - * The macro _POSIX_MONOTONIC_CLOCK can therefore assume the following values: - * -1 monotonic clock is never supported on this system - * 0 monotonic clock might be supported, runtime check is needed - * >1 (such as 200809L) monotonic clock is always supported - * - * Since Qt 6.6, we no longer perform any runtime checks and instead enforce - * the use of the monotonic clock in all OSes that have the CLOCK_MONOTONIC - * macro and use of the POSIX realtime clock functions. - * - * Conforming to: - * POSIX.1b-1993 section "Clocks and Timers" - * included in UNIX98 (Single Unix Specification v2) - * included in POSIX.1-2001 - * see http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html - */ - -static constexpr clockid_t regularClock() -{ -#ifdef CLOCK_MONOTONIC - return CLOCK_MONOTONIC; -#else - return CLOCK_REALTIME; -#endif -} - -bool QElapsedTimer::isMonotonic() noexcept -{ - return clockType() == MonotonicClock; -} - -QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept -{ - return regularClock() == CLOCK_REALTIME ? SystemTime : MonotonicClock; -} - -static inline void do_gettime(qint64 *sec, qint64 *frac) -{ - timespec ts; - clock_gettime(regularClock(), &ts); - *sec = ts.tv_sec; - *frac = ts.tv_nsec; -} - -// used in qcore_unix.cpp and qeventdispatcher_unix.cpp -struct timespec qt_gettime() noexcept -{ - qint64 sec, frac; - do_gettime(&sec, &frac); - - timespec tv; - tv.tv_sec = sec; - tv.tv_nsec = frac; - - return tv; -} - -static qint64 elapsedAndRestart(qint64 sec, qint64 frac, - qint64 *nowsec, qint64 *nowfrac) -{ - do_gettime(nowsec, nowfrac); - sec = *nowsec - sec; - frac = *nowfrac - frac; - return (sec * Q_INT64_C(1000000000) + frac) / Q_INT64_C(1000000); -} - -void QElapsedTimer::start() noexcept -{ - do_gettime(&t1, &t2); -} - -qint64 QElapsedTimer::restart() noexcept -{ - return elapsedAndRestart(t1, t2, &t1, &t2); -} - -qint64 QElapsedTimer::nsecsElapsed() const noexcept -{ - qint64 sec, frac; - do_gettime(&sec, &frac); - sec = sec - t1; - frac = frac - t2; - return sec * Q_INT64_C(1000000000) + frac; -} - -qint64 QElapsedTimer::elapsed() const noexcept -{ - return nsecsElapsed() / Q_INT64_C(1000000); -} - -qint64 QElapsedTimer::msecsSinceReference() const noexcept -{ - return t1 * Q_INT64_C(1000) + t2 / Q_INT64_C(1000000); -} - -qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept -{ - qint64 secs = other.t1 - t1; - qint64 fraction = other.t2 - t2; - return (secs * Q_INT64_C(1000000000) + fraction) / Q_INT64_C(1000000); -} - -qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept -{ - return other.t1 - t1; -} - -bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) noexcept -{ - return v1.t1 < v2.t1 || (v1.t1 == v2.t1 && v1.t2 < v2.t2); -} - -QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept -{ - static_assert(QDeadlineTimerNanosecondsInT2); - QDeadlineTimer result; - qint64 cursec, curnsec; - do_gettime(&cursec, &curnsec); - result.t1 = cursec; - result.t2 = curnsec; - result.type = timerType; - return result; -} - -QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer_win.cpp b/src/corelib/kernel/qelapsedtimer_win.cpp deleted file mode 100644 index bbd5b220fe7..00000000000 --- a/src/corelib/kernel/qelapsedtimer_win.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#include "qelapsedtimer.h" -#include "qdeadlinetimer.h" -#include "qdeadlinetimer_p.h" -#include - -QT_BEGIN_NAMESPACE - -// Result of QueryPerformanceFrequency -static quint64 counterFrequency = 0; - -static void resolveCounterFrequency() -{ - static bool done = false; - if (done) - return; - - // Retrieve the number of high-resolution performance counter ticks per second - LARGE_INTEGER frequency; - if (!QueryPerformanceFrequency(&frequency) || frequency.QuadPart == 0) - qFatal("QueryPerformanceFrequency failed, even though Microsoft documentation promises it wouldn't."); - counterFrequency = frequency.QuadPart; - - done = true; -} - -static inline qint64 ticksToNanoseconds(qint64 ticks) -{ - // QueryPerformanceCounter uses an arbitrary frequency - qint64 seconds = ticks / counterFrequency; - qint64 nanoSeconds = (ticks - seconds * counterFrequency) * 1000000000 / counterFrequency; - return seconds * 1000000000 + nanoSeconds; -} - - -static quint64 getTickCount() -{ - resolveCounterFrequency(); - - LARGE_INTEGER counter; - bool ok = QueryPerformanceCounter(&counter); - Q_ASSERT_X(ok, "QElapsedTimer::start()", - "QueryPerformanceCounter failed, although QueryPerformanceFrequency succeeded."); - Q_UNUSED(ok); - return counter.QuadPart; -} - -quint64 qt_msectime() -{ - return ticksToNanoseconds(getTickCount()) / 1000000; -} - -QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept -{ - resolveCounterFrequency(); - - return PerformanceCounter; -} - -bool QElapsedTimer::isMonotonic() noexcept -{ - return true; -} - -void QElapsedTimer::start() noexcept -{ - t1 = getTickCount(); - t2 = 0; -} - -qint64 QElapsedTimer::restart() noexcept -{ - qint64 oldt1 = t1; - t1 = getTickCount(); - t2 = 0; - return ticksToNanoseconds(t1 - oldt1) / 1000000; -} - -qint64 QElapsedTimer::nsecsElapsed() const noexcept -{ - qint64 elapsed = getTickCount() - t1; - return ticksToNanoseconds(elapsed); -} - -qint64 QElapsedTimer::elapsed() const noexcept -{ - qint64 elapsed = getTickCount() - t1; - return ticksToNanoseconds(elapsed) / 1000000; -} - -qint64 QElapsedTimer::msecsSinceReference() const noexcept -{ - return ticksToNanoseconds(t1) / 1000000; -} - -qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept -{ - qint64 difference = other.t1 - t1; - return ticksToNanoseconds(difference) / 1000000; -} - -qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept -{ - return msecsTo(other) / 1000; -} - -bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) noexcept -{ - return (v1.t1 - v2.t1) < 0; -} - -QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept -{ - static_assert(!QDeadlineTimerNanosecondsInT2); - QDeadlineTimer result; - result.t1 = ticksToNanoseconds(getTickCount()); - result.type = timerType; - return result; -} - -QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 1c54c97514b..f7fd2a7b511 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -56,6 +56,13 @@ class QEventDispatcherWin32Private; LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); +static quint64 qt_msectime() +{ + using namespace std::chrono; + auto t = duration_cast(steady_clock::now().time_since_epoch()); + return t.count(); +} + QEventDispatcherWin32Private::QEventDispatcherWin32Private() : interrupt(false), internalHwnd(0), sendPostedEventsTimerId(0), wakeUps(0), diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index ecd4bcb27b6..e6ea6b28c33 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -28,7 +28,6 @@ class QEventDispatcherWin32Private; // forward declaration LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); -quint64 qt_msectime(); class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcher { diff --git a/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp b/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp index f2f42bef4b8..502fe9b5e6a 100644 --- a/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp +++ b/tests/auto/corelib/kernel/qelapsedtimer/tst_qelapsedtimer.cpp @@ -1,8 +1,8 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include #include -#include #include #include #include @@ -31,11 +31,25 @@ private Q_SLOTS: void tst_QElapsedTimer::statics() { - qDebug() << "Clock type is" << QElapsedTimer::clockType(); - qDebug() << "Said clock is" << (QElapsedTimer::isMonotonic() ? "monotonic" : "not monotonic"); + // these have been required since Qt 6.6 + QCOMPARE(QElapsedTimer::clockType(), QElapsedTimer::MonotonicClock); + QVERIFY(QElapsedTimer::isMonotonic()); + QElapsedTimer t; t.start(); - qDebug() << "Current time is" << t.msecsSinceReference(); + qint64 system_now = QDateTime::currentMSecsSinceEpoch(); + + auto setprecision = +[](QTextStream &s) -> QTextStream & { + s.setRealNumberNotation(QTextStream::FixedNotation); + s.setRealNumberPrecision(3); + return s; + }; + qDebug() << setprecision + << "Current monotonic time is" << (t.msecsSinceReference() / 1000.) + << "s and current system time is" << (system_now / 1000.) << 's'; + if (qAbs(system_now - t.msecsSinceReference()) < 5 * minResolution) + qWarning() << "The monotonic clock is awfully close to the system clock" + " (it may not be monotonic at all!)"; } void tst_QElapsedTimer::validity()