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
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.