diff options
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r-- | src/corelib/kernel/kernel.pri | 7 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer.cpp | 267 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer.h | 95 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer_generic.cpp | 204 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer_mac.cpp | 149 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer_unix.cpp | 251 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer_win.cpp | 164 |
7 files changed, 1137 insertions, 0 deletions
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 991b73812a..39fe61ea4e 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -4,6 +4,7 @@ HEADERS += \ kernel/qabstracteventdispatcher.h \ kernel/qabstractnativeeventfilter.h \ kernel/qbasictimer.h \ + kernel/qelapsedtimer.h \ kernel/qeventloop.h\ kernel/qpointer.h \ kernel/qcorecmdlineargs_p.h \ @@ -45,6 +46,7 @@ SOURCES += \ kernel/qabstracteventdispatcher.cpp \ kernel/qabstractnativeeventfilter.cpp \ kernel/qbasictimer.cpp \ + kernel/qelapsedtimer.cpp \ kernel/qeventloop.cpp \ kernel/qcoreapplication.cpp \ kernel/qcoreevent.cpp \ @@ -69,6 +71,7 @@ SOURCES += \ win32 { SOURCES += \ kernel/qcoreapplication_win.cpp \ + kernel/qelapsedtimer_win.cpp \ kernel/qwineventnotifier.cpp \ kernel/qsharedmemory_win.cpp \ kernel/qsystemsemaphore_win.cpp @@ -103,6 +106,7 @@ mac { kernel/qcoreapplication_mac.cpp \ kernel/qcore_mac.cpp \ kernel/qcore_foundation.mm + !nacl: SOURCES += kernel/qelapsedtimer_mac.cpp OBJECTIVE_SOURCES += \ kernel/qcore_mac_objc.mm \ @@ -131,6 +135,7 @@ unix|integrity { kernel/qcrashhandler.cpp \ kernel/qeventdispatcher_unix.cpp \ kernel/qtimerinfo_unix.cpp + !darwin|nacl: SOURCES += kernel/qelapsedtimer_unix.cpp HEADERS += \ kernel/qcore_unix_p.h \ @@ -196,3 +201,5 @@ android { kernel/qjnihelpers_p.h \ kernel/qjni_p.h } + +!darwin:!unix:!win32: SOURCES += kernel/qelapsedtimer_generic.cpp diff --git a/src/corelib/kernel/qelapsedtimer.cpp b/src/corelib/kernel/qelapsedtimer.cpp new file mode 100644 index 0000000000..2eabb4c3a3 --- /dev/null +++ b/src/corelib/kernel/qelapsedtimer.cpp @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qelapsedtimer.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QElapsedTimer + \inmodule QtCore + \brief The QElapsedTimer class provides a fast way to calculate elapsed times. + \since 4.7 + + \reentrant + \ingroup tools + + The QElapsedTimer class is usually used to quickly calculate how much + time has elapsed between two events. Its API is similar to that of QTime, + so code that was using that can be ported quickly to the new class. + + However, unlike QTime, QElapsedTimer tries to use monotonic clocks if + possible. This means it's not possible to convert QElapsedTimer objects + to a human-readable time. + + The typical use-case for the class is to determine how much time was + spent in a slow operation. The simplest example of such a case is for + debugging purposes, as in the following example: + + \snippet qelapsedtimer/main.cpp 0 + + In this example, the timer is started by a call to start() and the + elapsed timer is calculated by the elapsed() function. + + The time elapsed can also be used to recalculate the time available for + another operation, after the first one is complete. This is useful when + the execution must complete within a certain time period, but several + steps are needed. The \tt{waitFor}-type functions in QIODevice and its + subclasses are good examples of such need. In that case, the code could + be as follows: + + \snippet qelapsedtimer/main.cpp 1 + + Another use-case is to execute a certain operation for a specific + timeslice. For this, QElapsedTimer provides the hasExpired() convenience + function, which can be used to determine if a certain number of + milliseconds has already elapsed: + + \snippet qelapsedtimer/main.cpp 2 + + \section1 Reference Clocks + + QElapsedTimer will use the platform's monotonic reference clock in all + platforms that support it (see QElapsedTimer::isMonotonic()). This has + the added benefit that QElapsedTimer is immune to time adjustments, such + as the user correcting the time. Also unlike QTime, QElapsedTimer is + immune to changes in the timezone settings, such as daylight-saving + periods. + + On the other hand, this means QElapsedTimer values can only be compared + with other values that use the same reference. This is especially true if + the time since the reference is extracted from the QElapsedTimer object + (QElapsedTimer::msecsSinceReference()) and serialised. These values + should never be exchanged across the network or saved to disk, since + there's no telling whether the computer node receiving the data is the + same as the one originating it or if it has rebooted since. + + It is, however, possible to exchange the value with other processes + running on the same machine, provided that they also use the same + reference clock. QElapsedTimer will always use the same clock, so it's + safe to compare with the value coming from another process in the same + machine. If comparing to values produced by other APIs, you should check + that the clock used is the same as QElapsedTimer (see + QElapsedTimer::clockType()). + + \section2 32-bit overflows + + Some of the clocks used by QElapsedTimer have a limited range and may + overflow after hitting the upper limit (usually 32-bit). QElapsedTimer + deals with this overflow issue and presents a consistent timing. However, + when extracting the time since reference from QElapsedTimer, two + different processes in the same machine may have different understanding + of how much time has actually elapsed. + + The information on which clocks types may overflow and how to remedy that + issue is documented along with the clock types. + + \sa QTime, QTimer +*/ + +/*! + \enum QElapsedTimer::ClockType + + This enum contains the different clock types that QElapsedTimer may use. + + QElapsedTimer will always use the same clock type in a particular + machine, so this value will not change during the lifetime of a program. + It is provided so that QElapsedTimer can be used with other non-Qt + implementations, to guarantee that the same reference clock is being + used. + + \value SystemTime The human-readable system time. This clock is not monotonic. + \value MonotonicClock The system's monotonic clock, usually found in Unix systems. This clock is monotonic and does not overflow. + \value TickCounter The system's tick counter, used on Windows systems. This clock may overflow. + \value MachAbsoluteTime The Mach kernel's absolute time (OS X and iOS). This clock is monotonic and does not overflow. + \value PerformanceCounter The high-resolution performance counter provided by Windows. This clock is monotonic and does not overflow. + + \section2 SystemTime + + The system time clock is purely the real time, expressed in milliseconds + since Jan 1, 1970 at 0:00 UTC. It's equivalent to the value returned by + the C and POSIX \tt{time} function, with the milliseconds added. This + clock type is currently only used on Unix systems that do not support + monotonic clocks (see below). + + This is the only non-monotonic clock that QElapsedTimer may use. + + \section2 MonotonicClock + + This is the system's monotonic clock, expressed in milliseconds since an + arbitrary point in the past. This clock type is used on Unix systems + which support POSIX monotonic clocks (\tt{_POSIX_MONOTONIC_CLOCK}). + + This clock does not overflow. + + \section2 TickCounter + + The tick counter clock type is based on the system's or the processor's + tick counter, multiplied by the duration of a tick. This clock type is + used on Windows platforms. If the high-precision performance + counter is available on Windows, the \tt{PerformanceCounter} clock type + is used instead. + + The TickCounter clock type is the only clock type that may overflow. + Windows Vista and Windows Server 2008 support the extended 64-bit tick + counter, which allows avoiding the overflow. + + On Windows systems, the clock overflows after 2^32 milliseconds, which + corresponds to roughly 49.7 days. This means two processes' reckoning of + the time since the reference may be different by multiples of 2^32 + milliseconds. When comparing such values, it's recommended that the high + 32 bits of the millisecond count be masked off. + + \section2 MachAbsoluteTime + + This clock type is based on the absolute time presented by Mach kernels, + such as that found on OS X. This clock type is presented separately + from MonotonicClock since OS X and iOS are also Unix systems and may support + a POSIX monotonic clock with values differing from the Mach absolute + time. + + This clock is monotonic and does not overflow. + + \section2 PerformanceCounter + + This clock uses the Windows functions \tt{QueryPerformanceCounter} and + \tt{QueryPerformanceFrequency} to access the system's high-precision + performance counter. Since this counter may not be available on all + systems, QElapsedTimer will fall back to the \tt{TickCounter} clock + automatically, if this clock cannot be used. + + This clock is monotonic and does not overflow. + + \sa clockType(), isMonotonic() +*/ + +/*! + \fn QElapsedTimer::QElapsedTimer() + \since 5.4 + + Constructs an invalid QElapsedTimer. A timer becomes valid once it has been + started. + + \sa isValid(), start() +*/ + + +/*! + \fn bool QElapsedTimer::operator ==(const QElapsedTimer &other) const + + Returns \c true if this object and \a other contain the same time. +*/ + +/*! + \fn bool QElapsedTimer::operator !=(const QElapsedTimer &other) const + + Returns \c true if this object and \a other contain different times. +*/ + +static const qint64 invalidData = Q_INT64_C(0x8000000000000000); + +/*! + Marks this QElapsedTimer object as invalid. + + An invalid object can be checked with isValid(). Calculations of timer + elapsed since invalid data are undefined and will likely produce bizarre + results. + + \sa isValid(), start(), restart() +*/ +void QElapsedTimer::invalidate() Q_DECL_NOTHROW +{ + t1 = t2 = invalidData; +} + +/*! + Returns \c false if the timer has never been started or invalidated by a + call to invalidate(). + + \sa invalidate(), start(), restart() +*/ +bool QElapsedTimer::isValid() const Q_DECL_NOTHROW +{ + return t1 != invalidData && t2 != invalidData; +} + +/*! + Returns \c true if this QElapsedTimer has already expired by \a timeout + milliseconds (that is, more than \a timeout milliseconds have elapsed). + The value of \a timeout can be -1 to indicate that this timer does not + expire, in which case this function will always return false. + + \sa elapsed() +*/ +bool QElapsedTimer::hasExpired(qint64 timeout) const Q_DECL_NOTHROW +{ + // if timeout is -1, quint64(timeout) is LLINT_MAX, so this will be + // considered as never expired + return quint64(elapsed()) > quint64(timeout); +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer.h b/src/corelib/kernel/qelapsedtimer.h new file mode 100644 index 0000000000..7954b41bf4 --- /dev/null +++ b/src/corelib/kernel/qelapsedtimer.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QELAPSEDTIMER_H +#define QELAPSEDTIMER_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + + +class Q_CORE_EXPORT QElapsedTimer +{ +public: + enum ClockType { + SystemTime, + MonotonicClock, + TickCounter, + MachAbsoluteTime, + PerformanceCounter + }; + + Q_DECL_CONSTEXPR QElapsedTimer() + : t1(Q_INT64_C(0x8000000000000000)), + t2(Q_INT64_C(0x8000000000000000)) + { + } + + static ClockType clockType() Q_DECL_NOTHROW; + static bool isMonotonic() Q_DECL_NOTHROW; + + void start() Q_DECL_NOTHROW; + qint64 restart() Q_DECL_NOTHROW; + void invalidate() Q_DECL_NOTHROW; + bool isValid() const Q_DECL_NOTHROW; + + qint64 nsecsElapsed() const Q_DECL_NOTHROW; + qint64 elapsed() const Q_DECL_NOTHROW; + bool hasExpired(qint64 timeout) const Q_DECL_NOTHROW; + + qint64 msecsSinceReference() const Q_DECL_NOTHROW; + qint64 msecsTo(const QElapsedTimer &other) const Q_DECL_NOTHROW; + qint64 secsTo(const QElapsedTimer &other) const Q_DECL_NOTHROW; + + bool operator==(const QElapsedTimer &other) const Q_DECL_NOTHROW + { return t1 == other.t1 && t2 == other.t2; } + bool operator!=(const QElapsedTimer &other) const Q_DECL_NOTHROW + { return !(*this == other); } + + friend bool Q_CORE_EXPORT operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW; + +private: + qint64 t1; + qint64 t2; +}; + +QT_END_NAMESPACE + +#endif // QELAPSEDTIMER_H diff --git a/src/corelib/kernel/qelapsedtimer_generic.cpp b/src/corelib/kernel/qelapsedtimer_generic.cpp new file mode 100644 index 0000000000..8c724247be --- /dev/null +++ b/src/corelib/kernel/qelapsedtimer_generic.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qelapsedtimer.h" +#include "qdatetime.h" + +QT_BEGIN_NAMESPACE + +/*! + Returns the clock type that this QElapsedTimer implementation uses. + + \sa isMonotonic() +*/ +QElapsedTimer::ClockType QElapsedTimer::clockType() Q_DECL_NOTHROW +{ + 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() Q_DECL_NOTHROW +{ + 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() Q_DECL_NOTHROW +{ + restart(); +} + +/*! + Restarts the timer and returns the time 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() Q_DECL_NOTHROW +{ + 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 Q_DECL_NOTHROW +{ + 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 Q_DECL_NOTHROW +{ + 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 OS X/iOS systems, 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 Q_DECL_NOTHROW +{ + 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 Q_DECL_NOTHROW +{ + 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 Q_DECL_NOTHROW +{ + return msecsTo(other) / 1000; +} + +/*! + \relates QElapsedTimer + + Returns \c true if \a v1 was started before \a v2, false otherwise. + + The returned value is undefined if one of the two parameters is invalid + and the other isn't. However, two invalid timers are equal and thus this + function will return false. +*/ +bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW +{ + return v1.t1 < v2.t1; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer_mac.cpp b/src/corelib/kernel/qelapsedtimer_mac.cpp new file mode 100644 index 0000000000..886e0f41b2 --- /dev/null +++ b/src/corelib/kernel/qelapsedtimer_mac.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// ask for the latest POSIX, just in case +#define _POSIX_C_SOURCE 200809L + +#include "qelapsedtimer.h" +#include <sys/time.h> +#include <time.h> +#include <unistd.h> + +#include <mach/mach_time.h> +#include <private/qcore_unix_p.h> + +QT_BEGIN_NAMESPACE + +QElapsedTimer::ClockType QElapsedTimer::clockType() Q_DECL_NOTHROW +{ + return MachAbsoluteTime; +} + +bool QElapsedTimer::isMonotonic() Q_DECL_NOTHROW +{ + return true; +} + +static mach_timebase_info_data_t info = {0,0}; +static qint64 absoluteToNSecs(qint64 cpuTime) +{ + if (info.denom == 0) + mach_timebase_info(&info); +#ifdef __LP64__ + __uint128_t nsecs = static_cast<__uint128_t>(cpuTime) * info.numer / info.denom; + return static_cast<qint64>(nsecs); +#else + qint64 nsecs = cpuTime * info.numer / info.denom; + return nsecs; +#endif +} + +static qint64 absoluteToMSecs(qint64 cpuTime) +{ + return absoluteToNSecs(cpuTime) / 1000000; +} + +timespec qt_gettime() Q_DECL_NOTHROW +{ + timespec tv; + + uint64_t cpu_time = mach_absolute_time(); + uint64_t nsecs = absoluteToNSecs(cpu_time); + tv.tv_sec = nsecs / 1000000000ull; + tv.tv_nsec = nsecs - (tv.tv_sec * 1000000000ull); + return tv; +} + +void qt_nanosleep(timespec amount) +{ + // Mac doesn't have clock_nanosleep, but it does have nanosleep. + // nanosleep is POSIX.1-1993 + + int r; + EINTR_LOOP(r, nanosleep(&amount, &amount)); +} + +void QElapsedTimer::start() Q_DECL_NOTHROW +{ + t1 = mach_absolute_time(); + t2 = 0; +} + +qint64 QElapsedTimer::restart() Q_DECL_NOTHROW +{ + qint64 old = t1; + t1 = mach_absolute_time(); + t2 = 0; + + return absoluteToMSecs(t1 - old); +} + +qint64 QElapsedTimer::nsecsElapsed() const Q_DECL_NOTHROW +{ + uint64_t cpu_time = mach_absolute_time(); + return absoluteToNSecs(cpu_time - t1); +} + +qint64 QElapsedTimer::elapsed() const Q_DECL_NOTHROW +{ + uint64_t cpu_time = mach_absolute_time(); + return absoluteToMSecs(cpu_time - t1); +} + +qint64 QElapsedTimer::msecsSinceReference() const Q_DECL_NOTHROW +{ + return absoluteToMSecs(t1); +} + +qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const Q_DECL_NOTHROW +{ + return absoluteToMSecs(other.t1 - t1); +} + +qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const Q_DECL_NOTHROW +{ + return msecsTo(other) / 1000; +} + +bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW +{ + return v1.t1 < v2.t1; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer_unix.cpp b/src/corelib/kernel/qelapsedtimer_unix.cpp new file mode 100644 index 0000000000..e2c3ae6280 --- /dev/null +++ b/src/corelib/kernel/qelapsedtimer_unix.cpp @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Intel Corporation. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qelapsedtimer.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 + * + * The unixCheckClockType() function will return the clock to use: either + * CLOCK_MONOTONIC or CLOCK_REALTIME. In the case the POSIX option has a value + * of zero, then this function stores a static that contains the clock to be + * used. + * + * There's one extra case, which is when CLOCK_REALTIME isn't defined. When + * that's the case, we'll emulate the clock_gettime function with gettimeofday. + * + * 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 + */ + +#if !defined(CLOCK_REALTIME) +# define CLOCK_REALTIME 0 +static inline void qt_clock_gettime(int, struct timespec *ts) +{ + // support clock_gettime with gettimeofday + struct timeval tv; + gettimeofday(&tv, 0); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; +} + +# ifdef _POSIX_MONOTONIC_CLOCK +# undef _POSIX_MONOTONIC_CLOCK +# define _POSIX_MONOTONIC_CLOCK -1 +# endif +#else +static inline void qt_clock_gettime(clockid_t clock, struct timespec *ts) +{ + clock_gettime(clock, ts); +} +#endif + +static int unixCheckClockType() +{ +#ifdef Q_OS_LINUX + // Despite glibc claiming that we should check at runtime, the Linux kernel + // always supports the monotonic clock + return CLOCK_MONOTONIC; +#elif (_POSIX_MONOTONIC_CLOCK-0 == 0) && defined(_SC_MONOTONIC_CLOCK) + // we need a value we can store in a clockid_t that isn't a valid clock + // check if the valid ones are both non-negative or both non-positive +# if CLOCK_MONOTONIC >= 0 && CLOCK_REALTIME >= 0 +# define IS_VALID_CLOCK(clock) (clock >= 0) +# define INVALID_CLOCK -1 +# elif CLOCK_MONOTONIC <= 0 && CLOCK_REALTIME <= 0 +# define IS_VALID_CLOCK(clock) (clock <= 0) +# define INVALID_CLOCK 1 +# else +# error "Sorry, your system has weird values for CLOCK_MONOTONIC and CLOCK_REALTIME" +# endif + + static QBasicAtomicInt clockToUse = Q_BASIC_ATOMIC_INITIALIZER(INVALID_CLOCK); + int clock = clockToUse.loadAcquire(); + if (Q_LIKELY(IS_VALID_CLOCK(clock))) + return clock; + + // detect if the system supports monotonic timers + clock = sysconf(_SC_MONOTONIC_CLOCK) > 0 ? CLOCK_MONOTONIC : CLOCK_REALTIME; + clockToUse.storeRelease(clock); + return clock; + +# undef INVALID_CLOCK +# undef IS_VALID_CLOCK +#elif (_POSIX_MONOTONIC_CLOCK-0) > 0 + return CLOCK_MONOTONIC; +#else + return CLOCK_REALTIME; +#endif +} + +bool QElapsedTimer::isMonotonic() Q_DECL_NOTHROW +{ + return clockType() == MonotonicClock; +} + +QElapsedTimer::ClockType QElapsedTimer::clockType() Q_DECL_NOTHROW +{ + return unixCheckClockType() == CLOCK_REALTIME ? SystemTime : MonotonicClock; +} + +static inline void do_gettime(qint64 *sec, qint64 *frac) +{ + timespec ts; + qt_clock_gettime(unixCheckClockType(), &ts); + *sec = ts.tv_sec; + *frac = ts.tv_nsec; +} + +// used in qcore_unix.cpp and qeventdispatcher_unix.cpp +struct timespec qt_gettime() Q_DECL_NOTHROW +{ + qint64 sec, frac; + do_gettime(&sec, &frac); + + timespec tv; + tv.tv_sec = sec; + tv.tv_nsec = frac; + + return tv; +} + +void qt_nanosleep(timespec amount) +{ + // We'd like to use clock_nanosleep. + // + // But clock_nanosleep is from POSIX.1-2001 and both are *not* + // affected by clock changes when using relative sleeps, even for + // CLOCK_REALTIME. + // + // nanosleep is POSIX.1-1993 + + int r; + EINTR_LOOP(r, nanosleep(&amount, &amount)); +} + +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() Q_DECL_NOTHROW +{ + do_gettime(&t1, &t2); +} + +qint64 QElapsedTimer::restart() Q_DECL_NOTHROW +{ + return elapsedAndRestart(t1, t2, &t1, &t2); +} + +qint64 QElapsedTimer::nsecsElapsed() const Q_DECL_NOTHROW +{ + qint64 sec, frac; + do_gettime(&sec, &frac); + sec = sec - t1; + frac = frac - t2; + return sec * Q_INT64_C(1000000000) + frac; +} + +qint64 QElapsedTimer::elapsed() const Q_DECL_NOTHROW +{ + return nsecsElapsed() / Q_INT64_C(1000000); +} + +qint64 QElapsedTimer::msecsSinceReference() const Q_DECL_NOTHROW +{ + return t1 * Q_INT64_C(1000) + t2 / Q_INT64_C(1000000); +} + +qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const Q_DECL_NOTHROW +{ + 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 Q_DECL_NOTHROW +{ + return other.t1 - t1; +} + +bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW +{ + return v1.t1 < v2.t1 || (v1.t1 == v2.t1 && v1.t2 < v2.t2); +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer_win.cpp b/src/corelib/kernel/qelapsedtimer_win.cpp new file mode 100644 index 0000000000..520126d262 --- /dev/null +++ b/src/corelib/kernel/qelapsedtimer_win.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qelapsedtimer.h" +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +// Result of QueryPerformanceFrequency, 0 indicates that the high resolution timer is unavailable +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)) { + qFatal("QueryPerformanceFrequency failed, even though Microsoft documentation promises it wouldn't."); + counterFrequency = 0; + } else { + counterFrequency = frequency.QuadPart; + } + + done = true; +} + +static inline qint64 ticksToNanoseconds(qint64 ticks) +{ + if (counterFrequency > 0) { + // QueryPerformanceCounter uses an arbitrary frequency + qint64 seconds = ticks / counterFrequency; + qint64 nanoSeconds = (ticks - seconds * counterFrequency) * 1000000000 / counterFrequency; + return seconds * 1000000000 + nanoSeconds; + } else { + // GetTickCount(64) return milliseconds + return ticks * 1000000; + } +} + +static quint64 getTickCount() +{ + resolveCounterFrequency(); + + // This avoids a division by zero and disables the high performance counter if it's not available + if (counterFrequency > 0) { + LARGE_INTEGER counter; + + bool ok = QueryPerformanceCounter(&counter); + Q_ASSERT_X(ok, "QElapsedTimer::start()", + "QueryPerformanceCounter failed, although QueryPerformanceFrequency succeeded."); + Q_UNUSED(ok); + return counter.QuadPart; + } + + return GetTickCount64(); +} + +quint64 qt_msectime() +{ + return ticksToNanoseconds(getTickCount()) / 1000000; +} + +QElapsedTimer::ClockType QElapsedTimer::clockType() Q_DECL_NOTHROW +{ + resolveCounterFrequency(); + + if (counterFrequency > 0) + return PerformanceCounter; + else + return TickCounter; +} + +bool QElapsedTimer::isMonotonic() Q_DECL_NOTHROW +{ + return true; +} + +void QElapsedTimer::start() Q_DECL_NOTHROW +{ + t1 = getTickCount(); + t2 = 0; +} + +qint64 QElapsedTimer::restart() Q_DECL_NOTHROW +{ + qint64 oldt1 = t1; + t1 = getTickCount(); + t2 = 0; + return ticksToNanoseconds(t1 - oldt1) / 1000000; +} + +qint64 QElapsedTimer::nsecsElapsed() const Q_DECL_NOTHROW +{ + qint64 elapsed = getTickCount() - t1; + return ticksToNanoseconds(elapsed); +} + +qint64 QElapsedTimer::elapsed() const Q_DECL_NOTHROW +{ + qint64 elapsed = getTickCount() - t1; + return ticksToNanoseconds(elapsed) / 1000000; +} + +qint64 QElapsedTimer::msecsSinceReference() const Q_DECL_NOTHROW +{ + return ticksToNanoseconds(t1) / 1000000; +} + +qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const Q_DECL_NOTHROW +{ + qint64 difference = other.t1 - t1; + return ticksToNanoseconds(difference) / 1000000; +} + +qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const Q_DECL_NOTHROW +{ + return msecsTo(other) / 1000; +} + +bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW +{ + return (v1.t1 - v2.t1) < 0; +} + +QT_END_NAMESPACE |