   Windows C++ High precision timer
  I am trying to make an accurate timer for animation. I'd like granularity to the millisecond.It has been suggested in the past to use QueryPerformanceCount for this task.However, my timer is reporting 30 seconds has gone by as I sit here and watch it only take 7.Does anyone know what is wrong with the code?Did I miss a nuance?#ifndef TIMER_H#define TIMER_H#include <windows.h>namespace common_lib_cpisz{//----------------------------------------------------------------------------/*** Timer class that is accurate to the millisecond*/class Timer{public:   /**   * Constructor   */   Timer();   /**   * Deconstructor   */   ~Timer();   /**   * Resets the timer to a stopped state and sets the elapsed time to zero   **/   void Reset();   /**   * Starts the timer   */   void Start();   /**   * Stops the timer   **/   void Stop();   /**   * Gets the state if the timer   **/   bool IsStarted() const;   /**   * Gets the total elapsed time between starts and stops since the last reset,   * in seconds, with a precision guarenteed to be accurate to the millisecond   */   double GetElapsedTime();private:   _int64 m_frequency; // Number of counts per second the hardware will report   _int64 m_start;// Hardware performance count when start was called   double m_elapsed;   // Elapsed time   bool   m_started;   // Whether or not the timer is currently started};} //namespace common_lib_cpisz#endif#include "Timer.h"#include "BaseException.h"namespace common_lib_cpisz{//----------------------------------------------------------------------------Timer::Timer()   :   m_started(false),   m_start(0),   m_elapsed(0){   // Get the number of counts per second the hardware reports   if( !QueryPerformanceFrequency((LARGE_INTEGER *)&m_frequency) )   { throw BaseException("Failed to query frequency of performance counter",  "Timer::Timer()", "Timer.cpp");   }}//----------------------------------------------------------------------------Timer::~Timer(){}//----------------------------------------------------------------------------void Timer::Reset(){   m_started = false;   m_start   = 0;   m_elapsed = 0;}//----------------------------------------------------------------------------void Timer::Start(){   // Flag the timer as started   m_started = true;   // Get the start count   if( !QueryPerformanceCounter((LARGE_INTEGER *)&m_start) )   { throw BaseException("Failed to query hardware performance counter",  "Timer::Start()", "Timer.cpp");   }}//----------------------------------------------------------------------------void Timer::Stop(){   // If the timer was flagged as started, then    //    add the time elapsed since the start to the current elapsed time   try   { GetElapsedTime();   }   catch(BaseException & e)   { throw e;   }   // Flag the timer as stopped   m_started = false;}//----------------------------------------------------------------------------bool Timer::IsStarted() const{   return m_started;}//----------------------------------------------------------------------------double Timer::GetElapsedTime(){   // If the timer is flagged as started   if( m_started )   { // Get the time elapsed since the start _int64 current; if( !QueryPerformanceCounter((LARGE_INTEGER *)&current) ) {    throw BaseException("Failed to query hardware performance counter",  "Timer::Start()", "Timer.cpp"); } // Add the elapsed time since the start to the current elapsed time m_elapsed += static_cast<double>(current - m_start) / static_cast<double>(m_frequency);   } return m_elapsed;}} // namespace common_lib_cpisz#include "Timer.h"#include <iostream>#include <cmath>using namespace common_lib_cpisz;//----------------------------------------------------------------------------/*** Entry point to the application*/int main(){   Timer timer;   // Test 1 - Test elapsed time   std::cout << "Test 1:\n";   std::cout << "You should see a 'done' message 30 seconds from now.\n"; timer.Reset();   timer.Start(); while( timer.GetElapsedTime() < 30.0 )   { Sleep(1000); std::cout << ".";   }   std::cout << "Done. \n\n";   // Test 2 - Add to last elapsed time   std::cout << "Test 2:\n";   std::cout << "You should see a 'done' message 30 seconds from now.\n"; timer.Start(); while( timer.GetElapsedTime() < 60.0 )   { Sleep(1000); std::cout << ".";   }   std::cout << "Done. \n\n";   // Test 3 - Precision   std::cout << "Test 3:\n";   std::cout << "Testing precision (sleep vs timer)\n"; timer.Reset();   timer.Start(); Sleep(100);   double elapsedTime = timer.GetElapsedTime();   double error = std::abs(elapsedTime - 0.1);   std::cout << "100 ms sleep compared to elapsed time reported by timer yields error of " << error <<"%\n\n"; // Done   system("pause");   return 0;}
  This older but still relevant blog post might be of interest. I've also heard that sleep doesn't play well with some timer implementations on windows, however I'm not sure of the truth behind that statement.You might consider using "timeGetTime()" instead, it is accurate to within a millisecond.   ;Quote:Original post by brekehanIt has been suggested in the past to use QueryPerformanceCount for this task.However, my timer is reporting 30 seconds has gone by as I sit here and watch it only take 7.The line:  m_elapsed += static_cast<double>(current - m_start) / static_cast<double>(m_frequency);should be:  m_elapsed = static_cast<double>(current - m_start) / static_cast<double>(m_frequency);I think you should be able to think that through as to why you should not accumulate the time differences. [wink]   ;Quote:Original post by Drew_BentonQuote:Original post by brekehanIt has been suggested in the past to use QueryPerformanceCount for this task.However, my timer is reporting 30 seconds has gone by as I sit here and watch it only take 7.The line:  m_elapsed += static_cast<double>(current - m_start) / static_cast<double>(m_frequency);should be:  m_elapsed = static_cast<double>(current - m_start) / static_cast<double>(m_frequency);I think you should be able to think that through as to why you should not accumulate the time differences. [wink]Why do you think it should be =?It is a running tally of start/stops until reset is called.Expected Behavior Example:I start it    // elapsed is 0I stop it in 30 seconds // elapsed is 30I start it    // elapsed is 30I stop it in 30 seconds // elapsed is 60I reset it    // elapsed is 0The only problem with accumulating the differences is if the elapes member overflows, which I think is very unlikely for the lifetime of the application's execution.Is there another reason? Did I assume you didn't understand the expected behavior correctly or am I still missing the problem?Accumulation aside, the the very first test case (before any accumulation occurs, ends in 7 real time (look at my watch seconds) when it should be 30.;Quote:Original post by SeoushiThis older but still relevant blog post might be of interest. I've also heard that sleep doesn't play well with some timer implementations on windows, however I'm not sure of the truth behind that statement.You might consider using "timeGetTime()" instead, it is accurate to within a millisecond.Reason I don't want to use that method:Quote:MSDNNT/2000: The default precision of the timeGetTime function can be five milliseconds or more, depending on the machineLeads me to believe in may still be inaccurate.Edit:Well, poopy. After reading the blog article, maybe I should switch. It _has_ been nothing but a pain in my buttocks anyway.I was really hoping for a hard guarentee that I have a time with 1 millisecond accuracy. Maybe it does with Vista, but I've come to really distrust MS docs lately. I don't know how I can really test the accuracy to 1 ms.;  Might be largely exaggerated, but is OpenMP's timer an option?Quote:Original post by SeoushiThis older but still relevant blog post might be of interest. I've also heard that sleep doesn't play well with some timer implementations on windows, however I'm not sure of the truth behind that statement.You might consider using "timeGetTime()" instead, it is accurate to within a millisecond.Last time I used timeGetTime(), it had a granularity of 25 or so msec on an older box of mine. But check this site.edit: ninja'd.   ;  Are you running this on a laptop or dual core machine? QPC() quite often fails miserably on laptop CPUs since the CPU speed can be variable, and on dual core CPUs you need to force the timing thread's affinity to one core to stop it switching cores and reading a different CPU time value.What happens if you log the timer frequency, start time and stop time values?Also, QPC isn't designed to be used to time for that long, it's supposed to be used to time a few milliseconds. If you need more, use timeGetTime() or even GetTickCount().Jan Wassenberg made an article about it all Here.   ;  You are accumulating each time difference, which is incorrect for getting the elapse time.This is what you are doing right now each time you call GetElapsedTime:[t0] + t1] + t2] + t3] + t4] + t5] + t6] + t7] + t8] + ... ]0    + 1   + 2   + 3   + 4   + 5   + 6   + 7   + 8   + ...0 13610    15    21    28    36When you call GetElapsedTime at t0, you get 0, naturally. When you call it again, you add the current elapsed time to the m_elapsed variable, so you get 1. When you call it again, when 2 seconds has elapsed, you once again add that to the elapse time variable, which gives you 0 + 1 + 2 = 3 seconds have elapsed when only 2 really have!Instead, the result of  static_cast<double>(current - m_start) / static_cast<double>(m_frequency); is the elapsed time and what you should be returning. If you want to accumulate a total runtime through start and stop calls, then you handle that logic in the stop function and you can also add another member function to return the total running time.So if you want a "stopwatch" class, then you need to do some rewriting. If you want a "timer" class, then you should not be performing a cumulative summation of the elapsed times. Does that make sense now?   ;Quote:Original post by Evil SteveAre you running this on a laptop or dual core machine? QPC() quite often fails miserably on laptop CPUs since the CPU speed can be variable, and on dual core CPUs you need to force the timing thread's affinity to one core to stop it switching cores and reading a different CPU time value.I am on a dual core, but would like my timer to work everywhere.I read that is can fail due to which processor on bugged machines, but haven't really seen how to implement a timer with thread affinity, without limiting the entire application to use one processor. I am not experienced enough in multithreading to figure that out myself.;  Here are my results using timeGetTime()It looks to be very very unprecise at the millisecond level. It seems right on if you only care about seconds. I don't think this will do for a good animation timer.#ifndef TIMER_H#define TIMER_H#include <windows.h>namespace common_lib_cpisz{//----------------------------------------------------------------------------/*** Timer class that is accurate to the millisecond*/class Timer{public:   /**   * Constructor   */   Timer();   /**   * Deconstructor   */   ~Timer();   /**   * Starts the timer   */   void Start();   /**   * Stops the timer   **/   double Stop();   /**   * Gets the state of the timer   **/   bool IsStarted() const;   /**   * Gets the total elapsed time since the last start in seconds   *    * Precision guarenteed to be accurate to the millisecond on XP and later (not by me, but by MS)   * If using for long periods, test for drift.   */   double GetElapsedTime();private:   DWORD m_start;// System time when start was called   bool  m_started;   // Whether or not the timer is currently started};} //namespace common_lib_cpisz#endif#include "Timer.h"#include "BaseException.h"namespace common_lib_cpisz{//----------------------------------------------------------------------------Timer::Timer()   :   m_started(false),   m_start(0){}//----------------------------------------------------------------------------Timer::~Timer(){}//----------------------------------------------------------------------------void Timer::Start(){   // Flag the timer as started   m_started = true;   // Get the start count   m_start = timeGetTime();}//----------------------------------------------------------------------------double Timer::Stop(){   // Get the time elapsed since the start   double elapsed = GetElapsedTime();   // Flag the timer as stopped   m_started = false;return elapsed;  }//----------------------------------------------------------------------------bool Timer::IsStarted() const{   return m_started;}//----------------------------------------------------------------------------double Timer::GetElapsedTime(){   if( m_started )   { // If the timer is flagged as started return static_cast<double>(timeGetTime() - m_start) / 1000.0;   }   else   { return 0;   }}} // namespace common_lib_cpisz#include "Timer.h"#include <iostream>#include <cmath>using namespace common_lib_cpisz;//----------------------------------------------------------------------------/*** Entry point to the application*/int main(){   Timer timer;   // Test 1 - Test elapsed time   std::cout << "Test 1:\n";   std::cout << "You should see a 'done' message 30 seconds from now.\n"; timer.Start(); while( timer.GetElapsedTime() < 30.0 )   { Sleep(1000); std::cout << ".";   }   std::cout << "Done. \n\n";   // Test 2 - Add to last elapsed time   std::cout << "Test 2:\n";   std::cout << "You should see a 'done' message 30 seconds from now.\n"; while( timer.GetElapsedTime() < 60.0 )   { Sleep(1000); std::cout << ".";   }   std::cout << "Done. \n\n";   // Test 3 - Stop   double elapsed = timer.Stop();   double error = std::abs((elapsed - 60.0) / 60.0 * 100.0); std::cout << "Test 3:\n";   std::cout << "60 seconds compared to time reported by timer stop yields error of " << error <<"%\n";   std::cout << "This tests instructions account for some error\n\n";   // Test 4 - Precision   std::cout << "Test 4:\n";   std::cout << "Testing precision (sleep vs timer)\n"; timer.Start(); Sleep(1);   elapsed = timer.Stop();   error   = std::abs((elapsed - 0.001) / 0.001 * 100.0);   std::cout << "1 ms sleep compared to elapsed time reported by timer yields error of " << error <<"%\n";   timer.Start(); Sleep(5);   elapsed = timer.Stop();   error   = std::abs((elapsed - 0.005) / 0.005 * 100.0);   std::cout << "5 ms sleep compared to elapsed time reported by timer yields error of " << error <<"%\n";   timer.Start(); Sleep(25);   elapsed = timer.Stop();   error   = std::abs((elapsed - 0.025) / 0.025 * 100.0);   std::cout << "25 ms sleep compared to elapsed time reported by timer yields error of " << error <<"%\n";   timer.Start(); Sleep(100);   elapsed = timer.Stop();   error   = std::abs((elapsed - 0.100) / 0.100 * 100.0);   std::cout << "100 ms sleep compared to elapsed time reported by timer yields error of " << error <<"%\n";   timer.Start(); Sleep(1000);   elapsed = timer.Stop();   error   = std::abs((elapsed - 1.0) / 1.0 * 100.0);   std::cout << "1 second sleep compared to elapsed time reported by timer yields error of " << error <<"%\n\n"; // Done   system("pause");   return 0;}Results:Test 1:You should see a 'done' message 30 seconds from now...............................Done.Test 2:You should see a 'done' message 30 seconds from now...............................Done.Test 3:60 seconds compared to time reported by timer stop yields error of 0%This tests instructions account for some errorTest 4:Testing precision (sleep vs timer)1 ms sleep compared to elapsed time reported by timer yields error of 1500%5 ms sleep compared to elapsed time reported by timer yields error of 200%25 ms sleep compared to elapsed time reported by timer yields error of 28%100 ms sleep compared to elapsed time reported by timer yields error of 9%1 second sleep compared to elapsed time reported by timer yields error of 0%Press any key to continue . . .EDIT: redid results, evidently the one run was a fluke. These seem to be the most consistent.It was mentioned that sleep isn't guarenteed to return at the time requested. I believe it. Does anyone have a suggestion for a better means of testing?