Results 1 to 14 of 14

Thread: frame rate and QTimer accuracy

  1. #1
    Join Date
    Dec 2009
    Posts
    128
    Thanks
    7
    Thanked 14 Times in 14 Posts
    Platforms
    Unix/X11 Windows

    Default frame rate and QTimer accuracy

    I have to read a file that describes animations frames at constant interval. i know this interval so I used QTimer to regularly trigger an update.
    The problem is, when i approximately measure the time it takes (with a stopwatch), i see an important difference between theoretical and actual times.

    So i wrote an example code showing my problem : It's a shape that go around in a scene. every round it makes I decrease the framerate and display few things :
    - the time it took to make a round
    - the time it should have taken, regarding current frame rate
    - the relative difference between these 2 times

    Qt Code:
    1. #include <QApplication>
    2. #include <QtGui>
    3.  
    4.  
    5. qreal interval = 1.0 ;
    6. const qreal nbFrames = 100.0 ;
    7.  
    8.  
    9. class View : public QGraphicsView
    10. {
    11. Q_OBJECT
    12. QGraphicsScene *scene ;
    13. int timerid ;
    14. qreal angle, step, radius ;
    15. QTime t0, t1 ;
    16.  
    17. public :
    18. View(void)
    19. : scene(new QGraphicsScene),
    20. angle(0), // start angle=0°
    21. step(360.0/nbFrames), // 1 round == 852 frames
    22. radius(150.0) // circle radius
    23. {
    24. scene->setBackgroundBrush(Qt::darkBlue) ;
    25. setScene(scene) ;
    26. // draw circle path
    27. new QGraphicsEllipseItem(QRectF(-radius,-radius,2*radius,2*radius),0,scene) ;
    28. // draw shape
    29. item = new QGraphicsRectItem(QRectF(-25,-15,50,30),0,scene) ;
    30. item->setBrush(Qt::darkYellow) ;
    31. item->setPen(QPen(Qt::black)) ;
    32. // draw start point
    33. QGraphicsEllipseItem *start = new QGraphicsEllipseItem(QRectF(radius-2,-2,4,4),0,scene) ;
    34. start->setBrush(Qt::red) ;
    35. start->setPen(QPen(Qt::black)) ;
    36. // start animation
    37. t0 = QTime::currentTime() ;
    38. qDebug() << "start at" << t0.toString("hh:mm:ss.zzz") << ", interval =" << interval ;
    39. timerid = startTimer(interval) ;
    40. }
    41.  
    42. protected :
    43. void timerEvent(QTimerEvent *e)
    44. {
    45. if(angle>=360)
    46. {
    47. // compute time and restart
    48. t1 = QTime::currentTime() ;
    49. qreal theoric = 0.001*interval*nbFrames ;
    50. qreal measured = 0.001*t0.msecsTo(t1) ;
    51. qreal diff = (measured-theoric) ;
    52. qreal delta = 100*diff/measured ;
    53. qDebug() << "round time :" << measured << "s, should be" << theoric << "s (diff ="<<diff<<"("<<delta<<"%) for"<<interval<<")" ;
    54. killTimer(timerid) ;
    55. interval++ ; // decrease framerate
    56. angle = 0 ;
    57. t0 = QTime::currentTime() ;
    58. timerid = startTimer(interval) ;
    59. }
    60. else
    61. {
    62. // compute new position
    63. qreal radians = M_PI*angle/180.0 ;
    64. qreal x = radius*cos(radians) ;
    65. qreal y = radius*sin(radians) ;
    66. item->setPos(x,y) ;
    67. // step ahead
    68. angle += step ;
    69. }
    70. }
    71. } ;
    72.  
    73. int main(int argc, char** argv)
    74. {
    75. QApplication app(argc,argv) ;
    76. View view ;
    77. view.setGeometry(QRect(100,100,600,500)) ;
    78. view.show() ;
    79. return app.exec() ;
    80. }
    81.  
    82. #include "main.moc"
    To copy to clipboard, switch view to plain text mode 

    And here is what I obtain on my comps (one desktop and one laptop, both on XP SP3 i guess) : After an interval of 20ms, whatever interval i give, the total time of an animation is the same for a range of a dozen framerate :

    Quote Originally Posted by debug
    round time : 1.418 s, should be 1.4 s (diff = 0.018 ( 1.26939 %) for 14 )
    round time : 1.512 s, should be 1.5 s (diff = 0.012 ( 0.793651 %) for 15
    round time : 1.606 s, should be 1.6 s (diff = 0.006 ( 0.373599 %) for 16
    round time : 1.715 s, should be 1.7 s (diff = 0.015 ( 0.874636 %) for 17
    round time : 1.808 s, should be 1.8 s (diff = 0.008 ( 0.442478 %) for 18
    round time : 1.917 s, should be 1.9 s (diff = 0.017 ( 0.886802 %) for 19
    round time : 2.011 s, should be 2 s (diff = 0.011 ( 0.546992 %) for 20 )
    round time : 3.149 s, should be 2.1 s (diff = 1.049 ( 33.3122 %) for 21 )
    round time : 3.148 s, should be 2.2 s (diff = 0.948 ( 30.1144 %) for 22 )
    round time : 3.149 s, should be 2.3 s (diff = 0.849 ( 26.9609 %) for 23 )
    round time : 3.149 s, should be 2.4 s (diff = 0.749 ( 23.7853 %) for 24 )
    round time : 3.149 s, should be 2.5 s (diff = 0.649 ( 20.6097 %) for 25 )
    round time : 3.148 s, should be 2.6 s (diff = 0.548 ( 17.4079 %) for 26 )
    round time : 3.149 s, should be 2.7 s (diff = 0.449 ( 14.2585 %) for 27 )
    round time : 3.149 s, should be 2.8 s (diff = 0.349 ( 11.0829 %) for 28 )
    round time : 3.149 s, should be 2.9 s (diff = 0.249 ( 7.90727 %) for 29 )
    round time : 3.149 s, should be 3 s (diff = 0.149 ( 4.73166 %) for 30 )
    round time : 3.149 s, should be 3.1 s (diff = 0.049 ( 1.55605 %) for 31 )
    round time : 4.193 s, should be 3.2 s (diff = 0.993 ( 23.6823 %) for 32 )
    round time : 4.723 s, should be 3.3 s (diff = 1.423 ( 30.1292 %) for 33 )
    round time : 4.724 s, should be 3.4 s (diff = 1.324 ( 28.0271 %) for 34 )
    round time : 4.723 s, should be 3.5 s (diff = 1.223 ( 25.8946 %) for 35 )
    round time : 4.724 s, should be 3.6 s (diff = 1.124 ( 23.7934 %) for 36 )
    round time : 4.723 s, should be 3.7 s (diff = 1.023 ( 21.66 %) for 37 )
    round time : 4.723 s, should be 3.8 s (diff = 0.923 ( 19.5427 %) for 38 )
    round time : 4.724 s, should be 3.9 s (diff = 0.824 ( 17.4428 %) for 39 )
    round time : 4.723 s, should be 4 s (diff = 0.723 ( 15.3081 %) for 40 )
    round time : 4.723 s, should be 4.1 s (diff = 0.623 ( 13.1908 %) for 41 )
    round time : 4.724 s, should be 4.2 s (diff = 0.524 ( 11.0923 %) for 42 )
    round time : 4.723 s, should be 4.3 s (diff = 0.423 ( 8.95617 %) for 43 )
    round time : 4.724 s, should be 4.4 s (diff = 0.324 ( 6.85859 %) for 44 )
    round time : 4.723 s, should be 4.5 s (diff = 0.223 ( 4.72158 %) for 45 )
    round time : 4.723 s, should be 4.6 s (diff = 0.123 ( 2.60428 %) for 46 )
    round time : 5.082 s, should be 4.7 s (diff = 0.382 ( 7.51673 %) for 47 )
    round time : 6.298 s, should be 4.8 s (diff = 1.498 ( 23.7853 %) for 48 )
    round time : 6.298 s, should be 4.9 s (diff = 1.398 ( 22.1975 %) for 49 )
    round time : 6.298 s, should be 5 s (diff = 1.298 ( 20.6097 %) for 50 )
    round time : 6.298 s, should be 5.1 s (diff = 1.198 ( 19.0219 %) for 51 )
    round time : 6.297 s, should be 5.2 s (diff = 1.097 ( 17.421 %) for 52 )
    round time : 6.298 s, should be 5.3 s (diff = 0.998 ( 15.8463 %) for 53 )
    round time : 6.298 s, should be 5.4 s (diff = 0.898 ( 14.2585 %) for 54 )
    round time : 6.298 s, should be 5.5 s (diff = 0.798 ( 12.6707 %) for 55 )
    round time : 6.298 s, should be 5.6 s (diff = 0.698 ( 11.0829 %) for 56 )
    round time : 6.298 s, should be 5.7 s (diff = 0.598 ( 9.49508 %) for 57 )
    round time : 6.297 s, should be 5.8 s (diff = 0.497 ( 7.89265 %) for 58 )
    round time : 6.298 s, should be 5.9 s (diff = 0.398 ( 6.31947 %) for 59 )
    round time : 6.298 s, should be 6 s (diff = 0.298 ( 4.73166 %) for 60 )
    round time : 6.298 s, should be 6.1 s (diff = 0.198 ( 3.14386 %) for 61 )
    round time : 6.298 s, should be 6.2 s (diff = 0.098 ( 1.55605 %) for 62 )
    round time : 7.545 s, should be 6.3 s (diff = 1.245 ( 16.501 %) for 63 )
    round time : 7.872 s, should be 6.4 s (diff = 1.472 ( 18.6992 %) for 64 )

    Unfortunately for my app i need an interval of 33ms, which is obviously one of the worse result : 30% of difference. It means that for an animation of 10s, my app will display an animation which lasts 13s.

    Is it a known issue, and what are the possible alternatives ?

  2. #2
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    Hi Totem!

    I had a long workout with timers a while ago.. I measured them with a performanceCounter and found that their reported frequency could be way off. But thats not the matter here now.

    I guess you found another weakness in how the windows kernel schedules its timers. But if you know about it, this one can easily be resolved:

    Qt Code:
    1. #include <QtGui>
    2.  
    3. class View : public QGraphicsView
    4. {
    5. Q_OBJECT
    6. int nbFrames;
    7. QGraphicsScene *scene ;
    8. qreal angle, step, radius ;
    9. QTime t0, t1 ;
    10. int interval;
    11. QTimer* timer;
    12.  
    13. public :
    14. View(void)
    15. : scene(new QGraphicsScene),
    16. nbFrames(100),
    17. angle(0), // start angle=0°
    18. step(360.0/nbFrames), // 1 round == 852 frames
    19. radius(150.0), // circle radius
    20. interval(1)
    21. {
    22. scene->setBackgroundBrush(Qt::darkBlue) ;
    23. setScene(scene) ;
    24. // draw circle path
    25. new QGraphicsEllipseItem(QRectF(-radius,-radius,2*radius,2*radius),0,scene) ;
    26. // draw shape
    27. item = new QGraphicsRectItem(QRectF(-25,-15,50,30),0,scene) ;
    28. item->setBrush(Qt::darkYellow) ;
    29. item->setPen(QPen(Qt::black)) ;
    30. // draw start point
    31. QGraphicsEllipseItem *start = new QGraphicsEllipseItem(QRectF(radius-2,-2,4,4),0,scene) ;
    32. start->setBrush(Qt::red) ;
    33. start->setPen(QPen(Qt::black)) ;
    34. // start animation
    35. t0 = QTime::currentTime() ;
    36. qDebug() << "start at" << t0.toString("hh:mm:ss.zzz") << ", interval =" << interval ;
    37. timer = new QTimer();
    38. connect(timer,SIGNAL(timeout()),this,SLOT(doTimer()));
    39. timer->start(1);
    40. }
    41.  
    42. protected slots:
    43. void doTimer()
    44. {
    45. static int timerCounter = 0;
    46. ++timerCounter;
    47. if(angle>=360)
    48. {
    49. // compute time and restart
    50. t1 = QTime::currentTime() ;
    51. qreal theoric = 0.001*interval*nbFrames ;
    52. qreal measured = 0.001*t0.msecsTo(t1) ;
    53. qreal diff = (measured-theoric) ;
    54. qreal delta = 100*diff/measured ;
    55. qDebug() << "round time :" << measured << "s, should be" << theoric << "s (diff ="<<diff<<"("<<delta<<"%) for"<<interval<<")" ;
    56. //killTimer(timerid) ;
    57. interval++ ; // decrease framerate
    58. angle = 0 ;
    59. //the timer doesn't take into account the time you spend here, why do you?
    60. t0 = t1;
    61. // no restarting..
    62. //timer->start(interval);
    63. }
    64. else
    65. {
    66. if (timerCounter % interval == 0)
    67. {
    68. // compute new position
    69. qreal radians = M_PI*angle/180.0 ;
    70. qreal x = radius*cos(radians) ;
    71. qreal y = radius*sin(radians) ;
    72. item->setPos(x,y) ;
    73. // step ahead
    74. angle += step ;
    75. }
    76. }
    77. }
    78. } ;
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. start at "11:55:14.630" , interval = 1
    2. round time : 0.132 s, should be 0.1 s (diff = 0.032 ( 24.2424 %) for 1 )
    3. round time : 0.2 s, should be 0.2 s (diff = -6.93889e-18 ( -3.46945e-15 %) for 2 )
    4. round time : 0.3 s, should be 0.3 s (diff = 1.73472e-17 ( 5.78241e-15 %) for 3 )
    5. round time : 0.4 s, should be 0.4 s (diff = -1.38778e-17 ( -3.46945e-15 %) for 4 )
    6. round time : 0.5 s, should be 0.5 s (diff = 1.04083e-17 ( 2.08167e-15 %) for 5 )
    7. round time : 0.603 s, should be 0.6 s (diff = 0.003 ( 0.497512 %) for 6 )
    8. round time : 0.7 s, should be 0.7 s (diff = -5.20417e-17 ( -7.43453e-15 %) for 7 )
    9. round time : 0.8 s, should be 0.8 s (diff = -2.77556e-17 ( -3.46945e-15 %) for 8 )
    10. round time : 0.9 s, should be 0.9 s (diff = -3.46945e-18 ( -3.85494e-16 %) for 9 )
    11. round time : 1 s, should be 1 s (diff = 2.08167e-17 ( 2.08167e-15 %) for 10 )
    12. round time : 1.1 s, should be 1.1 s (diff = -6.59195e-17 ( -5.99268e-15 %) for 11 )
    13. round time : 1.2 s, should be 1.2 s (diff = 6.93889e-17 ( 5.78241e-15 %) for 12 )
    14. round time : 1.302 s, should be 1.3 s (diff = 0.002 ( 0.15361 %) for 13 )
    15. round time : 1.4 s, should be 1.4 s (diff = -1.04083e-16 ( -7.43453e-15 %) for 14 )
    16. round time : 1.5 s, should be 1.5 s (diff = 3.1225e-17 ( 2.08167e-15 %) for 15 )
    17. round time : 1.6 s, should be 1.6 s (diff = -5.55112e-17 ( -3.46945e-15 %) for 16 )
    18. round time : 1.7 s, should be 1.7 s (diff = 7.97973e-17 ( 4.69396e-15 %) for 17 )
    19. round time : 1.8 s, should be 1.8 s (diff = -6.93889e-18 ( -3.85494e-16 %) for 18 )
    20. round time : 1.9 s, should be 1.9 s (diff = -9.36751e-17 ( -4.93027e-15 %) for 19 )
    21. round time : 2 s, should be 2 s (diff = 4.16334e-17 ( 2.08167e-15 %) for 20 )
    22. round time : 2.1 s, should be 2.1 s (diff = -4.51028e-17 ( -2.14775e-15 %) for 21 )
    23. round time : 2.2 s, should be 2.2 s (diff = -1.31839e-16 ( -5.99268e-15 %) for 22 )
    24. round time : 2.301 s, should be 2.3 s (diff = 0.001 ( 0.0434594 %) for 23 )
    25. round time : 2.4 s, should be 2.4 s (diff = 1.38778e-16 ( 5.78241e-15 %) for 24 )
    26. round time : 2.5 s, should be 2.5 s (diff = 5.20417e-17 ( 2.08167e-15 %) for 25 )
    27. round time : 2.6 s, should be 2.6 s (diff = -3.46945e-17 ( -1.3344e-15 %) for 26 )
    28. round time : 2.7 s, should be 2.7 s (diff = -1.21431e-16 ( -4.49743e-15 %) for 27 )
    29. round time : 2.8 s, should be 2.8 s (diff = -2.08167e-16 ( -7.43453e-15 %) for 28 )
    30. round time : 2.901 s, should be 2.9 s (diff = 0.001 ( 0.0344709 %) for 29 )
    31. round time : 3 s, should be 3 s (diff = 6.245e-17 ( 2.08167e-15 %) for 30 )
    32. round time : 3.1 s, should be 3.1 s (diff = -2.42861e-17 ( -7.83424e-16 %) for 31 )
    33. round time : 3.2 s, should be 3.2 s (diff = -1.11022e-16 ( -3.46945e-15 %) for 32 )
    34. round time : 3.3 s, should be 3.3 s (diff = -1.97758e-16 ( -5.99268e-15 %) for 33 )
    35. round time : 3.4 s, should be 3.4 s (diff = 1.59595e-16 ( 4.69396e-15 %) for 34 )
    36. round time : 3.501 s, should be 3.5 s (diff = 0.001 ( 0.0285633 %) for 35 )
    37. round time : 3.6 s, should be 3.6 s (diff = -1.38778e-17 ( -3.85494e-16 %) for 36 )
    38. round time : 3.7 s, should be 3.7 s (diff = -1.00614e-16 ( -2.7193e-15 %) for 37 )
    39. round time : 3.8 s, should be 3.8 s (diff = -1.8735e-16 ( -4.93027e-15 %) for 38 )
    40. round time : 3.9 s, should be 3.9 s (diff = 1.70003e-16 ( 4.35905e-15 %) for 39 )
    41. round time : 4.001 s, should be 4 s (diff = 0.001 ( 0.0249938 %) for 40 )
    42. round time : 4.1 s, should be 4.1 s (diff = 4.4062e-16 ( 1.07468e-14 %) for 41 )
    43. round time : 4.2 s, should be 4.2 s (diff = -9.02056e-17 ( -2.14775e-15 %) for 42 )
    44. round time : 4.3 s, should be 4.3 s (diff = 2.67147e-16 ( 6.21273e-15 %) for 43 )
    45. round time : 4.401 s, should be 4.4 s (diff = 0.001 ( 0.0227221 %) for 44 )
    46. round time : 4.5 s, should be 4.5 s (diff = 9.36751e-17 ( 2.08167e-15 %) for 45 )
    47. round time : 4.6 s, should be 4.6 s (diff = -4.3715e-16 ( -9.50327e-15 %) for 46 )
    48. round time : 4.7 s, should be 4.7 s (diff = -7.97973e-17 ( -1.69781e-15 %) for 47 )
    49. round time : 4.801 s, should be 4.8 s (diff = 0.001 ( 0.020829 %) for 48 )
    50. round time : 4.9 s, should be 4.9 s (diff = -2.5327e-16 ( -5.16877e-15 %) for 49 )
    51. round time : 5 s, should be 5 s (diff = 1.04083e-16 ( 2.08167e-15 %) for 50 )
    52. round time : 5.101 s, should be 5.1 s (diff = 0.001 ( 0.019604 %) for 51 )
    53. round time : 5.2 s, should be 5.2 s (diff = -6.93889e-17 ( -1.3344e-15 %) for 52 )
    54. round time : 5.3 s, should be 5.3 s (diff = 2.87964e-16 ( 5.43328e-15 %) for 53 )
    55. round time : 5.401 s, should be 5.4 s (diff = 0.001 ( 0.0185151 %) for 54 )
    56. round time : 5.5 s, should be 5.5 s (diff = 1.14492e-16 ( 2.08167e-15 %) for 55 )
    57. round time : 5.6 s, should be 5.6 s (diff = -4.16334e-16 ( -7.43453e-15 %) for 56 )
    58. round time : 5.7 s, should be 5.7 s (diff = -5.89806e-17 ( -1.03475e-15 %) for 57 )
    To copy to clipboard, switch view to plain text mode 

    QTimer seems to adjust windows timer resolution if required. That defaults to 10ms but is increased by applications that require more.. like winamp .. One has to set that manually in order for QThread::sleep() to work at 1ms precision:

    Qt Code:
    1. #ifdef Q_OS_WIN
    2. #include "windows.h"
    3. DWORD AdjustPrivileges()
    4. {
    5. HANDLE hToken;
    6. TOKEN_PRIVILEGES tkp;
    7. // get the current process token handle
    8. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
    9. return GetLastError();
    10. }
    11. // get the LUID for system-time privilege.
    12. LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
    13. tkp.PrivilegeCount = 1; // one privilege to set
    14. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    15. // get set-time privilege for this process.
    16. AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
    17. // cannot test return value of AdjustTokenPrivileges.
    18. return GetLastError();
    19. }
    20. #endif
    21. ..
    22. AdjustPrivileges();
    23. if (timeBeginPeriod(1) == TIMERR_NOCANDO)
    24. qWarning() << "Could not start the time period!";
    25. ...
    26. timeEndPeriod(1);
    To copy to clipboard, switch view to plain text mode 

    HIH

    Johannes

  3. The following user says thank you to JohannesMunk for this useful post:

    totem (4th April 2011)

  4. #3
    Join Date
    Dec 2009
    Posts
    128
    Thanks
    7
    Thanked 14 Times in 14 Posts
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    thank you very much, i'll try your solution as soon as possible

  5. #4
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    You might want to have a try at this:
    http://undocumented.ntinternals.net/...esolution.html


    Added after 6 minutes:


    @Johannes:
    Just out of curiosity, your code is setting privileges for setting the system time.
    MSDN for SE_SYSTEMTIME_NAME:
    Required to modify the system time.

    User Right: Change the system time.
    How does this change the timer resolution for the privileged process?
    Last edited by high_flyer; 5th April 2011 at 11:14.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  6. #5
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    Hi High_flyer!

    You are absolutely right! The setting for the high resolution timer is done only by the timeBeginPeriod call.

    And the privilege adjustment is not required for it! I didn't realize! It was only in context of an NTP-Clock sync, that this made sense.

    But as I mentioned none of it is required to have a 1 ms QTimer work correctly. Only if you want QThread::sleep to work accurately you will need to set the timer resolution yourself.
    I just mentioned it, because I had trouble with it in context of high precision timing.

    Joh

  7. #6
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    But as I mentioned none of it is required to have a 1 ms QTimer work correctly. Only if you want QThread::sleep to work accurately you will need to set the timer resolution yourself.
    So just to see if I understand what you are saying is that for having QThread::sleep() work accurately, one must set the windows timer resolution (per process) via timeBeginPeriod() + timeEndPeriod(), is that correct?
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  8. #7
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    Yes, this is correct for Windows. I experienced that on WinXPSP3,Win7-32 and 64bit. The timer resolution equals the kernels schedulers granularity so unless you set it to 1ms you can't get accurate sleep intervals.

    To prove it, I hacked together a small test application:

    It runs msleep(1) 100x times. As the default timer resolution of windows is 10ms, you get about 1sec for 100 calls to msleep(1):

    Qt Code:
    1. 999
    2. 998
    3. BeginPeriod!
    4. 110
    5. 94
    6. 110
    7. EndPeriod!
    8. 998
    9. 1014
    To copy to clipboard, switch view to plain text mode 
    Before you run it, make sure all other processes that might request a higher timer resolution are closed. This includes winamp, your browser (flash plugin!), ..
    You can then check the current timer resolution with sysinternals clockres.

    Here is the sourcecode:

    Qt Code:
    1. main.h
    2. #ifndef MAIN_H
    3. #define MAIN_H
    4.  
    5. #include <QtGui>
    6.  
    7. #ifdef Q_OS_WIN
    8. #include "windows.h"
    9. #endif
    10.  
    11. class SleeperThread : public QThread
    12. { Q_OBJECT
    13. public:
    14. SleeperThread(int interval,QObject* parent = 0) : QThread(parent), m_interval(interval) {}
    15. protected:
    16. virtual void run()
    17. {
    18. QElapsedTimer timer;
    19. timer.start();
    20. for (int i=0;i<100;++i)
    21. {
    22. msleep(m_interval);
    23. }
    24. QMetaObject::invokeMethod(parent(),"showResult",Q_ARG(int, timer.elapsed()));
    25. }
    26. private:
    27. int m_interval;
    28. };
    29.  
    30. class MainWindow : public QMainWindow
    31. { Q_OBJECT
    32. public:
    33. MainWindow()
    34. {
    35. QPushButton* start_pb = new QPushButton("Test Sleep");
    36. connect(start_pb,SIGNAL(clicked()),this,SLOT(testSleep()));
    37.  
    38. QPushButton* beginPeriod_pb = new QPushButton("Begin Period");
    39. connect(beginPeriod_pb,SIGNAL(clicked()),this,SLOT(beginPeriod()));
    40. QPushButton* endPeriod_pb = new QPushButton("End Period");
    41. connect(endPeriod_pb,SIGNAL(clicked()),this,SLOT(endPeriod()));
    42.  
    43. QHBoxLayout* hl = new QHBoxLayout();
    44. hl->addWidget(beginPeriod_pb);
    45. hl->addWidget(start_pb);
    46. hl->addWidget(endPeriod_pb);
    47.  
    48. output_te = new QPlainTextEdit();
    49. output_te->setReadOnly(true);
    50.  
    51. QVBoxLayout* vl = new QVBoxLayout();
    52. vl->addLayout(hl);
    53. vl->addWidget(output_te);
    54.  
    55.  
    56. QWidget* w = new QWidget();
    57. w->setLayout(vl);
    58.  
    59. setCentralWidget(w);
    60. }
    61. public slots:
    62. void testSleep()
    63. {
    64. SleeperThread* st = new SleeperThread(1,this);
    65. connect(st,SIGNAL(result(int)),this,SLOT(showResult(int)));
    66. connect(st,SIGNAL(finished()),st,SLOT(deleteLater()));
    67. st->start();
    68. }
    69.  
    70. void beginPeriod()
    71. {
    72. output_te->appendPlainText("BeginPeriod!");
    73. #ifdef Q_OS_WIN
    74. if (timeBeginPeriod(1) == TIMERR_NOCANDO)
    75. qWarning() << "Could not start the time period!";
    76. #endif
    77. }
    78.  
    79. void endPeriod()
    80. {
    81. output_te->appendPlainText("EndPeriod!");
    82. #ifdef Q_OS_WIN
    83. timeEndPeriod(1);
    84. #endif
    85. }
    86.  
    87. void showResult(int elapsed)
    88. {
    89. output_te->appendPlainText(QString::number(elapsed));
    90. }
    91. private:
    92. QPlainTextEdit* output_te;
    93. };
    94.  
    95. #endif // MAIN_H
    96.  
    97. main.cpp:
    98.  
    99. #include <QApplication>
    100. #include <QtGui>
    101.  
    102. #include "main.h"
    103.  
    104. int main(int argc, char** argv)
    105. {
    106. QApplication app(argc,argv) ;
    107.  
    108. MainWindow mw;
    109. mw.show();
    110.  
    111. return app.exec();
    112. }
    To copy to clipboard, switch view to plain text mode 
    Johannes
    Last edited by JohannesMunk; 5th April 2011 at 12:58. Reason: Changed ClockRes link to technet en-us

  9. The following user says thank you to JohannesMunk for this useful post:

    high_flyer (5th April 2011)

  10. #8
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    for the sake if completeness, here is a good link I just found on the subject:
    http://msdn.microsoft.com/en-us/magazine/cc163996.aspx
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  11. #9
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    Actually the article is not about a timer that can periodically schedule or delay something, but about using the Performance Counter API to supplement the precision of the system time and thus interval measurement. They explain the lack of resolution by the lack of resolution of the system timer, though.

    Joh


    Added after 9 minutes:


    To get back on the original topic, I just tested, that when you start a QTimer with an arbitrary number above 20ms it will not adapt the timer resolution. So that a timer of 33ms will fire either after 30ms or 40ms, because the system timer resolution is at 10ms.

    That problem can be resolved as i suggested by using a 1ms timer and counting its timeouts or probably (I didn't check this) by using a 33ms timer and manually setting the windows timer resolution to 1ms with timeBeginPeriod!

    Joh
    Last edited by JohannesMunk; 5th April 2011 at 13:34.

  12. #10
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    They explain the lack of resolution by the lack of resolution of the system timer, though.
    Yes, but also how to increase the timer resolution in the limits of a given system, which I think is what the OP was generally after.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  13. #11
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    When I look at the similar threads below this seems to be a rather common problem.

    http://www.qtcentre.org/threads/2316...is-not-acurate

    Maybe I should create a WIKI-Article about precision timing under windows sometime. I have spent quite a lot of time with performance counters and their unreliable frequency statements and with thread-switching times, due to a real time data acquisition suite i'm currently developing.

    Joh

  14. #12
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    Maybe I should create a WIKI-Article about precision timing under windows sometime. I have spent quite a lot of time with performance counters and their unreliable frequency statements and with thread-switching times, due to a real time data acquisition suite i'm currently developing.
    I am not going to stop you!
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  15. #13
    Join Date
    Dec 2009
    Posts
    128
    Thanks
    7
    Thanked 14 Times in 14 Posts
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    Quote Originally Posted by JohannesMunk View Post
    The setting for the high resolution timer is done only by the timeBeginPeriod call.

    And the privilege adjustment is not required for it! I didn't realize! It was only in context of an NTP-Clock sync, that this made sense.

    But as I mentioned none of it is required to have a 1 ms QTimer work correctly. Only if you want QThread::sleep to work accurately you will need to set the timer resolution yourself.
    I just mentioned it, because I had trouble with it in context of high precision timing.
    Joh
    So If I don't use QThread::sleep I don't need to include windows-specific code ?
    I'd be glad because it makes me link against some MS lib (i got linker error with timeBeginPeriod call I did not even tried to resolve)

    By the way I tried your solution and it seems to work for me, thanks again.
    As I said I needed a frame interval of 33ms so I used a timer interval of 11ms, which implies an update every 3 timer events. Now animation duration seems consistent

  16. #14
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: frame rate and QTimer accuracy

    Hi Totem!

    Yes, below 20ms QTimer-interval, windows timer resolution is set to 1ms, without you doing anything.
    Thats why your 11ms should be quite accurate.

    Glad that your problem is resolved,

    Happy coding,

    Johannes

Similar Threads

  1. OpenGL frame rate
    By martinb0820 in forum Installation and Deployment
    Replies: 3
    Last Post: 2nd October 2009, 19:24
  2. OpenGL frame rate under 64-bit XP
    By martinb0820 in forum Qt Programming
    Replies: 1
    Last Post: 2nd October 2009, 19:23
  3. Replies: 24
    Last Post: 13th August 2009, 10:13
  4. Frame rate problem
    By MrShahi in forum Qt Programming
    Replies: 1
    Last Post: 30th July 2008, 23:06
  5. Change frame rate
    By superutsav in forum General Programming
    Replies: 1
    Last Post: 3rd August 2006, 21:02

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.