Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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);
    }
    @


  • Moderators

    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)."


Log in to reply