diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2024-02-18 19:24:02 -0800 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2024-03-13 17:29:13 -0800 |
commit | 9dc2935462ef42a5172b19b2bd4a8b938cf40bee (patch) | |
tree | f5d243755062d87b1cb417feb0e822c5d17eaa52 | |
parent | 1ca89b65d85c5df971fac7c1f9d5678e0e0cf45b (diff) |
QTimerInfo: store nanoseconds instead of milliseconds
No change in behavior, other than the ability for the precise timers to
be even more precise. There's a reduction in the stored interval range
from 292 million years to 292 years, but there's no change in behavior
because the timeout is stored as a steady_clock::time_point, which is
nanoseconds with libstdc++ and libc++. Now, if there's an overflow,
it'll happen on the call to registerTimer() instead of inside the
calculation of the wake-up.
Change-Id: I83dda2d36c904517b3c0fffd17b3d1f2d9505c1c
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_glib.cpp | 5 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_unix.cpp | 5 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_wasm.cpp | 5 | ||||
-rw-r--r-- | src/corelib/kernel/qtimerinfo_unix.cpp | 34 | ||||
-rw-r--r-- | src/corelib/kernel/qtimerinfo_unix_p.h | 20 |
5 files changed, 39 insertions, 30 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp index 4be4fea98a..ba3a1ea988 100644 --- a/src/corelib/kernel/qeventdispatcher_glib.cpp +++ b/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -14,6 +14,7 @@ #include <glib.h> +using namespace std::chrono; using namespace std::chrono_literals; QT_BEGIN_NAMESPACE @@ -102,8 +103,8 @@ static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout) return true; } - auto msecs = src->timerList.timerWait().value_or(-1ms); - *timeout = qt_saturate<gint>(msecs.count()); + auto remaining = src->timerList.timerWait().value_or(-1ms); + *timeout = qt_saturate<gint>(ceil<milliseconds>(remaining).count()); return (*timeout == 0); } diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index d0b47757bf..e6da258d9f 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -29,6 +29,7 @@ static constexpr bool UsingEventfd = false; # include <pipeDrv.h> #endif +using namespace std::chrono; using namespace std::chrono_literals; QT_BEGIN_NAMESPACE @@ -431,8 +432,8 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) QDeadlineTimer deadline; if (canWait) { if (include_timers) { - std::optional<std::chrono::milliseconds> msecs = d->timerList.timerWait(); - deadline = msecs ? QDeadlineTimer{*msecs} + std::optional<nanoseconds> remaining = d->timerList.timerWait(); + deadline = remaining ? QDeadlineTimer{*remaining} : QDeadlineTimer(QDeadlineTimer::Forever); } else { deadline = QDeadlineTimer(QDeadlineTimer::Forever); diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp index f5061f35d7..51904eaab8 100644 --- a/src/corelib/kernel/qeventdispatcher_wasm.cpp +++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp @@ -14,6 +14,7 @@ #include <emscripten/threading.h> #include <emscripten/val.h> +using namespace std::chrono; using namespace std::chrono_literals; QT_BEGIN_NAMESPACE @@ -619,8 +620,8 @@ void QEventDispatcherWasm::updateNativeTimer() // access to m_timerInfo), and then call native API to set the new // wakeup time on the main thread. - const std::optional<std::chrono::milliseconds> wait = m_timerInfo->timerWait(); - const auto toWaitDuration = wait.value_or(0ms); + const std::optional<std::chrono::nanoseconds> wait = m_timerInfo->timerWait(); + const auto toWaitDuration = duration_cast<milliseconds>(wait.value_or(0ms)); const auto newTargetTimePoint = m_timerInfo->currentTime + toWaitDuration; auto epochNsecs = newTargetTimePoint.time_since_epoch(); auto newTargetTime = std::chrono::duration_cast<std::chrono::milliseconds>(epochNsecs); diff --git a/src/corelib/kernel/qtimerinfo_unix.cpp b/src/corelib/kernel/qtimerinfo_unix.cpp index da570eded2..4c846fa5ec 100644 --- a/src/corelib/kernel/qtimerinfo_unix.cpp +++ b/src/corelib/kernel/qtimerinfo_unix.cpp @@ -74,7 +74,7 @@ static_assert(roundToMillisecond(999'000'001ns) == 1000ms); static_assert(roundToMillisecond(999'999'999ns) == 1000ms); static_assert(roundToMillisecond(1s) == 1s); -static constexpr seconds roundToSecs(milliseconds msecs) +static constexpr seconds roundToSecs(nanoseconds interval) { // The very coarse timer is based on full second precision, so we want to // round the interval to the closest second, rounding 500ms up to 1s. @@ -86,8 +86,8 @@ static constexpr seconds roundToSecs(milliseconds msecs) // 1500 2 2 // 2500 2 3 - auto secs = duration_cast<seconds>(msecs); - const milliseconds frac = msecs - secs; + auto secs = duration_cast<seconds>(interval); + const nanoseconds frac = interval - secs; if (frac >= 500ms) ++secs; return secs; @@ -122,14 +122,15 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, steady_clock::time_point }; // Calculate how much we can round and still keep within 5% error - const milliseconds absMaxRounding = t->interval / 20; + milliseconds interval = roundToMillisecond(t->interval); + const milliseconds absMaxRounding = interval / 20; auto fracMsec = duration_cast<milliseconds>(t->timeout - timeoutInSecs); - if (t->interval < 100ms && t->interval != 25ms && t->interval != 50ms && t->interval != 75ms) { + if (interval < 100ms && interval != 25ms && interval != 50ms && interval != 75ms) { auto fracCount = fracMsec.count(); // special mode for timers of less than 100 ms - if (t->interval < 50ms) { + if (interval < 50ms) { // round to even // round towards multiples of 50 ms bool roundUp = (fracCount % 50) >= 25; @@ -171,17 +172,17 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, steady_clock::time_point // towards a round-to-the-second // 3) if the interval is a multiple of 500 ms, we'll round towards the nearest // multiple of 500 ms - if ((t->interval % 500) == 0ms) { - if (t->interval >= 5s) { + if ((interval % 500) == 0ms) { + if (interval >= 5s) { fracMsec = fracMsec >= 500ms ? max : min; recalculate(fracMsec); return; } else { wantedBoundaryMultiple = 500ms; } - } else if ((t->interval % 50) == 0ms) { + } else if ((interval % 50) == 0ms) { // 4) same for multiples of 250, 200, 100, 50 - milliseconds mult50 = t->interval / 50; + milliseconds mult50 = interval / 50; if ((mult50 % 4) == 0ms) { // multiple of 200 wantedBoundaryMultiple = 200ms; @@ -234,7 +235,7 @@ static void calculateNextTimeout(QTimerInfo *t, steady_clock::time_point now) Returns the time to wait for the first timer that has not been activated yet, otherwise returns std::nullopt. */ -std::optional<std::chrono::milliseconds> QTimerInfoList::timerWait() +std::optional<QTimerInfoList::Duration> QTimerInfoList::timerWait() { steady_clock::time_point now = updateCurrentTime(); @@ -257,10 +258,10 @@ std::optional<std::chrono::milliseconds> QTimerInfoList::timerWait() */ qint64 QTimerInfoList::timerRemainingTime(int timerId) { - return remainingDuration(timerId).count(); + return roundToMillisecond(remainingDuration(timerId)).count(); } -milliseconds QTimerInfoList::remainingDuration(int timerId) +QTimerInfoList::Duration QTimerInfoList::remainingDuration(int timerId) { const steady_clock::time_point now = updateCurrentTime(); @@ -274,7 +275,7 @@ milliseconds QTimerInfoList::remainingDuration(int timerId) const QTimerInfo *t = *it; if (now < t->timeout) // time to wait - return roundToMillisecond(t->timeout - now); + return t->timeout - now; return 0ms; } @@ -283,7 +284,7 @@ void QTimerInfoList::registerTimer(int timerId, qint64 interval, Qt::TimerType t registerTimer(timerId, milliseconds{interval}, timerType, object); } -void QTimerInfoList::registerTimer(int timerId, milliseconds interval, +void QTimerInfoList::registerTimer(int timerId, Duration interval, Qt::TimerType timerType, QObject *object) { // correct the timer type first @@ -299,7 +300,7 @@ void QTimerInfoList::registerTimer(int timerId, milliseconds interval, } QTimerInfo *t = new QTimerInfo(timerId, interval, timerType, object); - steady_clock::time_point expected = updateCurrentTime() + interval; + QTimerInfo::TimePoint expected = updateCurrentTime() + interval; switch (timerType) { case Qt::PreciseTimer: @@ -310,6 +311,7 @@ void QTimerInfoList::registerTimer(int timerId, milliseconds interval, case Qt::CoarseTimer: t->timeout = expected; + t->interval = roundToMillisecond(interval); calculateCoarseTimerTimeout(t, currentTime); break; diff --git a/src/corelib/kernel/qtimerinfo_unix_p.h b/src/corelib/kernel/qtimerinfo_unix_p.h index d8f41955f8..5ebda6a68d 100644 --- a/src/corelib/kernel/qtimerinfo_unix_p.h +++ b/src/corelib/kernel/qtimerinfo_unix_p.h @@ -25,14 +25,17 @@ QT_BEGIN_NAMESPACE // internal timer info -struct QTimerInfo { - QTimerInfo(int timerId, std::chrono::milliseconds msecs, Qt::TimerType type, QObject *obj) - : interval(msecs), id(timerId), timerType(type), obj(obj) +struct QTimerInfo +{ + using Duration = QAbstractEventDispatcher::Duration; + using TimePoint = std::chrono::time_point<std::chrono::steady_clock, Duration>; + QTimerInfo(int timerId, Duration interval, Qt::TimerType type, QObject *obj) + : interval(interval), id(timerId), timerType(type), obj(obj) { } - std::chrono::steady_clock::time_point timeout; // - when to actually fire - std::chrono::milliseconds interval = std::chrono::milliseconds{-1}; // - timer interval + TimePoint timeout = {}; // - when to actually fire + Duration interval = Duration{-1}; // - timer interval int id = -1; // - timer identifier Qt::TimerType timerType; // - timer type QObject *obj = nullptr; // - object to receive event @@ -42,18 +45,19 @@ struct QTimerInfo { class Q_CORE_EXPORT QTimerInfoList { public: + using Duration = QAbstractEventDispatcher::Duration; QTimerInfoList(); std::chrono::steady_clock::time_point currentTime; - std::optional<std::chrono::milliseconds> timerWait(); + std::optional<Duration> timerWait(); void timerInsert(QTimerInfo *); qint64 timerRemainingTime(int timerId); - std::chrono::milliseconds remainingDuration(int timerId); + Duration remainingDuration(int timerId); void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object); - void registerTimer(int timerId, std::chrono::milliseconds interval, Qt::TimerType timerType, + void registerTimer(int timerId, Duration interval, Qt::TimerType timerType, QObject *object); bool unregisterTimer(int timerId); bool unregisterTimers(QObject *object); |