QElapsedTimer and QTimer strange behavior
-
Currently working on a project we face the following strange behavior:
We set up a QTimer timing out each 5ms.
We also use a QElapsedTimer measuring the time at each QTimer timeout.
The printouts show a relative stable loop time.However, after exactly (!) 3497 iterations, the loop time is 4 milliseconds. This happens at exactly iteration 3497 each time the program is run, and with a cyclic behavior (it=6994, 10491, ...). The iteration may vary between computers, but occurs around that iteration (~3500).
Either the QTimer times out too soon (at that iteration) or the time measurement (QElapsedTimer) does something strange. Could that be a quantification error? We have also checked against system time (QDateTime) and windows QueryPerformanceTimers.
This phenomena occurs on Windows 7 64-bit only; on Linux OpenSUSE we do not see the same. We tried both Qt-4.8 and Qt-5.0 versions.
Debug printouts:
@"Iteration: 3495, Nanosecs: 17470502465, ns diff: 4992721, Millisecs: 17470.5, ms diff: 5.0, systime: 1372419103724"
"Iteration: 3496, Nanosecs: 17475514952, ns diff: 5012487, Millisecs: 17475.5, ms diff: 5.0, systime: 1372419103729"
"Iteration: 3497, Nanosecs: 17479511409, ns diff: 3996457, Millisecs: 17479.5, ms diff: 4.0, systime: 1372419103733"
"Iteration: 3498, Nanosecs: 17484515153, ns diff: 5003744, Millisecs: 17484.5, ms diff: 5.0, systime: 1372419103738"
"Iteration: 3499, Nanosecs: 17489533341, ns diff: 5018188, Millisecs: 17489.5, ms diff: 5.0, systime: 1372419103743" @Example code:
main.cpp
@#include <QCoreApplication>
#include "timertester.hpp"int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TimerTester time_test;
time_test.start();
return a.exec();
}
@timertester.hpp
@
#ifndef TIMERTESTER_HPP
#define TIMERTESTER_HPP#include <QtCore>
class TimerTester : public QObject
{
Q_OBJECT
public:
explicit TimerTester(QObject* parent = 0);
void start();signals:
public slots:
void tic();private:
QTimer* m_timer;
QElapsedTimer m_elapsed_timer;qint32 m_iteration;
qint64 m_base_nsec;
qint64 m_prev_nsec;
};#endif // TIMERTESTER_HPP
@timertester.cpp
@#include "timertester.hpp"TimerTester::TimerTester(QObject* parent) : QObject(parent)
{
m_timer = new QTimer(this);
m_timer->setInterval(5);
connect(m_timer, SIGNAL(timeout()), this, SLOT(tic()));m_iteration = 0;
m_base_nsec = 0;
m_prev_nsec = 0;
}void TimerTester::start() {
m_elapsed_timer.start();
m_timer->start();
}void TimerTester::tic() {
//First operation, store total number of nano seconds elapsed when
//QTimer times out
qint64 nsecs_elapsed = m_elapsed_timer.nsecsElapsed();
qint64 sys_time = QDateTime::currentMSecsSinceEpoch();//Adjust elapsed nano seconds with base line
if(m_base_nsec == 0) {
m_base_nsec = nsecs_elapsed;
}
nsecs_elapsed -= m_base_nsec;//Nano seconds since last QTimer time out
//Around 5 millions if no timer slips
qint64 nsec_diff = nsecs_elapsed - m_prev_nsec;
m_prev_nsec = nsecs_elapsed;//Also present in micro seconds
double msecs = double(nsecs_elapsed) / 1e6;
double msec_diff = double(nsec_diff) / 1e6;
m_iteration++;//Printout
qDebug() << QString("Iteration:%1, Nanosecs:%2, ns diff:%3, Millisecs:%4, ms diff:%5, systime: %6").
arg(m_iteration, 5).
arg(nsecs_elapsed, 12).
arg(nsec_diff, 8).
arg(msecs, 8, 'f', 1).
arg(msec_diff, 4, 'f', 1).
arg(sys_time);
}
@ -
Windows is a non-deterministic OS, so keeping strict time isn't a high priority for it. I'm surprised you managed to get 5 ms most of the time, actually -- Windows' system timer has a resolution of somewhere between "10ms -- 16ms":http://msdn.microsoft.com/en-us/library/windows/desktop/ms725496(v=vs.85).aspx Windows does provide "multimedia timers" that are much more precise, but I doubt QTimer uses that.
In contrast, Linux kernels provide timers of 1ms resolution, which makes Linux QTimers ~10x more precise than their Windows counterparts.
The periodicity of your anomalies is interesting -- I'm curious to know what causes it!
-
[quote author="JKSH" date="1372434688"]Windows does provide "multimedia timers" that are much more precise, but I doubt QTimer uses that.[/quote]
Hi. I actually found some information posted by Netich on other forums that Qt indeed uses multimedia timers. In the Qt's 4.6.0 change-log on line 111 it states:
" - QEventDispatcherWin32 (internal class)
* Changed the threshold for using multimedia timers to 20ms (was 10ms)."