Using the Windows 95/98/NT High Performance Timer

Overview

Win32 applications are event-driven.  In order to perform tasks at specific intervals, such as screen updates or calculations, programmers typically use the SetTimer() function to generate WM_TIMER messages.  However, the timer created by this function has a resolution of only 55 ms (Windows NT has a timer resolution of 10 ms), so it is not suitable for applications that need more frequent timer messages.
 

The Workaround

For applications that need high-resolution timing, Windows provides access to a high performance timer.  The high performance timer, however, is not as easy to use as the timer created by SetTimer(), as it requires significantly more work on the part of the programmer.
 

  How the High Performance Timer Operates

The high performance timer is a system-wide timer that is continously incrementing.  You can read the current value of the timer at any time by calling the QueryPerformanceCounter() function.  QueryPerformanceCounter() has the following prototype:

BOOL QueryPerformanceCounter(  LARGE_INTEGER *lpPerformanceCount );

lpPerformanceCount is a pointer to a LARGE_INTEGER that will be filled with the current value of the performance counter.

Note that the existence of a high performance timer is completely dependent on hardware.  If QueryPerformanceCounter() returns false, then no high performance timer exists on the system.
 

   Translating Timer Counts Into Real-Time

Consider an action game that needs to update the screen 70 times per second.  In this case, you need to know how many increments of the performance counter equate to 1/70th of a second.  To accomplish this, call the QueryPerformanceFrequency() function, which tell you how many timer increments occur in a second.  QueryPerformanceFrequency() has the following prototype:

BOOL QueryPerformanceFrequency( LARGE_INTEGER *lpFrequency);

lpFrequency is a pointer to a LARGE_INTEGER that will be filled with the number of timer increments that occur in one second.
 

Putting It All Together

The following functions provide a high-level interface for the high performance timer:

void InitTimer(const int updateFreq, LARGE_INTEGER & timerDiff)
    {
    LARGE_INTEGER freq;

    // exit if the system does not support a high performance timer
    if (!QueryPerformanceFrequency(&freq))
        exit(1);

    timerDiff.QuadPart = freq.QuadPart/updateFreq; // set the timer diff for DESIRED_FREQ times per second
    }

void CheckTimer(const LARGE_INTEGER & timerDiff)
    {

    static LARGE_INTEGER oldTimerVal;
    LARGE_INTEGER newTimerVal;

    QueryPerformanceCounter(&newTimerVal);

    // check for timer roll-over
    if (oldTimerVal.QuadPart > newTimerVal.QuadPart)
        {
        PostMessage(mainWindow, messageCodes[UPDATE_SCREEN], 0, 0);
        oldTimerVal = newTimerVal;
        return;
        }

    if (newTimerVal.QuadPart-oldTimerVal.QuadPart > timerDiff.QuadPart)
        {
        PostMessage(mainWindow, messageCodes[UPDATE_SCREEN], 0, 0);
        oldTimerVal = newTimerVal;
        }

    }

And the following is a sample message loop that uses these high-level functions:

// messageCodes is a global array initialized before this point.

const int UPDATE_FREQ = 70;
LARGE_INTEGER timerDiff;
InitTimer(UPDATE_FREQ, timerDiff);
bool ContinueFlag = true;

while (ContinueFlag)
  {

  while(!PeekMessage(&message,NULL,0,0, PM_NOREMOVE ))
      CheckTimer(timerDiff);

  ContinueFlag = GetMessage(&message, NULL, 0,0) != 0;

  TranslateMessage(&message);
  DispatchMessage(&message);

  }

Combined, this code posts an UPDATE_SCREEN message UPDATE_FREQ (70) times per second.  While this code can certainly be improved upon and made more general, its purpose it to convey an idea.
 

Author:RodneyMyers--5/15/99