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 <a.samirh78@gmail.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
13f0ee021e
commit
c9f4c0d45e
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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<milliseconds>(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<milliseconds>(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<milliseconds>(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<seconds>(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
|
||||
|
@ -6,8 +6,9 @@
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
#include <chrono>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_CORE_EXPORT QElapsedTimer
|
||||
{
|
||||
@ -21,6 +22,10 @@ public:
|
||||
PerformanceCounter
|
||||
};
|
||||
|
||||
// similar to std::chrono::*_clock
|
||||
using Duration = std::chrono::nanoseconds;
|
||||
using TimePoint = std::chrono::time_point<std::chrono::steady_clock, Duration>;
|
||||
|
||||
constexpr QElapsedTimer() = default;
|
||||
|
||||
static ClockType clockType() noexcept;
|
||||
@ -31,11 +36,13 @@ public:
|
||||
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;
|
||||
|
||||
|
@ -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
|
@ -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 <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
#include <qatomic.h>
|
||||
#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
|
@ -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_windows.h>
|
||||
|
||||
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
|
@ -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<milliseconds>(steady_clock::now().time_since_epoch());
|
||||
return t.count();
|
||||
}
|
||||
|
||||
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
|
||||
: interrupt(false), internalHwnd(0),
|
||||
sendPostedEventsTimerId(0), wakeUps(0),
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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 <QtCore/QDateTime>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user