From 7113c6d4be87ead4f2be9afe64c6e81e3f6720a3 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 19 Jun 2010 01:54:45 +0200 Subject: QElapsedTimer/Win: use QueryPerformanceCounter if available Added a clock type to reflect this. Merge-request: 697 Reviewed-by: joerg Reviewed-by: thiago --- src/corelib/tools/qelapsedtimer.cpp | 23 ++++++++++---- src/corelib/tools/qelapsedtimer.h | 3 +- src/corelib/tools/qelapsedtimer_win.cpp | 53 +++++++++++++++++++++++++++++---- 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/corelib/tools/qelapsedtimer.cpp b/src/corelib/tools/qelapsedtimer.cpp index cb5e701..4adddf9 100644 --- a/src/corelib/tools/qelapsedtimer.cpp +++ b/src/corelib/tools/qelapsedtimer.cpp @@ -136,10 +136,11 @@ QT_BEGIN_NAMESPACE 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 and Symbian systems. This clock may overflow. - \value MachAbsoluteTime The Mach kernel's absolute time (Mac OS X). This clock is monotonic and does not overflow. + \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 and Symbian systems. This clock may overflow. + \value MachAbsoluteTime The Mach kernel's absolute time (Mac OS X). 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 @@ -163,7 +164,9 @@ QT_BEGIN_NAMESPACE 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 and Symbian platforms. + used on Windows and Symbian 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 @@ -191,6 +194,16 @@ QT_BEGIN_NAMESPACE 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() */ diff --git a/src/corelib/tools/qelapsedtimer.h b/src/corelib/tools/qelapsedtimer.h index 0d6f0be..b996f6a 100644 --- a/src/corelib/tools/qelapsedtimer.h +++ b/src/corelib/tools/qelapsedtimer.h @@ -57,7 +57,8 @@ public: SystemTime, MonotonicClock, TickCounter, - MachAbsoluteTime + MachAbsoluteTime, + PerformanceCounter }; static ClockType clockType(); static bool isMonotonic(); diff --git a/src/corelib/tools/qelapsedtimer_win.cpp b/src/corelib/tools/qelapsedtimer_win.cpp index 135196a..c7c160d 100644 --- a/src/corelib/tools/qelapsedtimer_win.cpp +++ b/src/corelib/tools/qelapsedtimer_win.cpp @@ -42,6 +42,9 @@ #include "qelapsedtimer.h" #include +// Result of QueryPerformanceFrequency, 0 indicates that the high resolution timer is unavailable +static quint64 counterFrequency = 0; + typedef ULONGLONG (WINAPI *PtrGetTickCount64)(void); static PtrGetTickCount64 ptrGetTickCount64 = 0; @@ -65,12 +68,44 @@ static void resolveLibs() ptrGetTickCount64 = (PtrGetTickCount64)GetProcAddress(kernel32, "GetTickCount64"); #endif + // Retrieve the number of high-resolution performance counter ticks per second + LARGE_INTEGER frequency; + if (!QueryPerformanceFrequency(&frequency)) { + counterFrequency = 0; + } else { + counterFrequency = frequency.QuadPart; + } + done = true; } +static qint64 ticksToMilliseconds(qint64 ticks) +{ + if (counterFrequency > 0) { + // QueryPerformanceCounter uses an arbitrary frequency + return ticks * 1000 / counterFrequency; + } else { + // GetTickCount(64) return milliseconds + return ticks; + } +} + static quint64 getTickCount() { resolveLibs(); + + // This avoids a division by zero and disables the high performance counter if it's not available + if (counterFrequency > 0) { + LARGE_INTEGER counter; + + if (QueryPerformanceCounter(&counter)) { + return counter.QuadPart; + } else { + qWarning("QueryPerformanceCounter failed, although QueryPerformanceFrequency succeeded."); + return 0; + } + } + if (ptrGetTickCount64) return ptrGetTickCount64(); @@ -85,7 +120,13 @@ static quint64 getTickCount() QElapsedTimer::ClockType QElapsedTimer::clockType() { - return TickCounter; + resolveLibs(); + + if (counterFrequency > 0) { + return PerformanceCounter; + } else { + return TickCounter; + } } bool QElapsedTimer::isMonotonic() @@ -104,22 +145,24 @@ qint64 QElapsedTimer::restart() qint64 oldt1 = t1; t1 = getTickCount(); t2 = 0; - return t1 - oldt1; + return ticksToMilliseconds(t1 - oldt1); } qint64 QElapsedTimer::elapsed() const { - return getTickCount() - t1; + qint64 elapsed = getTickCount() - t1; + return ticksToMilliseconds(elapsed); } qint64 QElapsedTimer::msecsSinceReference() const { - return t1; + return ticksToMilliseconds(t1); } qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const { - return other.t1 - t1; + qint64 difference = other.t1 - t1; + return ticksToMilliseconds(difference); } qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const -- cgit v0.12