Search code examples
cperformancetimetimermingw

Windows QueryPerformanceCounter with MinGW C


I'm trying to measure my response time on a serial protocol handshake by pulling QueryPerformanceCounter (QPC). My target system is a win7 on Asrock D1800b Intel Dual Core, compiling with latest version of MinGw (6.3.0-1).

In order to test QPC I have this code:

#include <windows.h>
#include <stdio.h>

void main() 
{
    //performance timers
    LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
    LARGE_INTEGER Frequency;

    QueryPerformanceFrequency(&Frequency);
    for (int i = 0 ; i < 10 ; i++) 
    {
        QueryPerformanceCounter(&StartingTime);
        Sleep(10); //ms
        QueryPerformanceCounter(&EndingTime);
        ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
        ElapsedMicroseconds.QuadPart *= 1000000;                //first scale up counts
        ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;     //then convert to us
        printf("elapsed=%li\n", ElapsedMicroseconds.QuadPart);
    }

}

When run on the target system I get: (no other loads)

elapsed=5341
elapsed=14086
elapsed=13818
elapsed=14322
elapsed=15305
elapsed=8867
elapsed=12162
elapsed=14225
elapsed=13333
elapsed=14751

But when run on the developing system (Win10, Intel i5), I get this much consistent result

elapsed=11326
elapsed=11556
elapsed=12630
elapsed=11583
elapsed=11749
elapsed=12644
elapsed=12562
elapsed=11690
elapsed=11726
elapsed=11664

Both above results are examples of a much larger run.

the expected result is somewhere above 10000us.

So, any ideas of what it going on on the target system?


Solution

  • You probably need to increase the tick rate, which may be defaulted to 64hz (15.625 ms per tick) in order to get Sleep(10) to work as expected. You can increase it to 1000hz (1 ms per tick). This will increase interrupt overhead, but results should be more consistent. Example code fragment:

        timeBeginPeriod(1);                     /* set ticker to 1000 hz */
        Sleep(128);                             /* wait for it to settle */
        /* ... benchmark code */
        timeEndPeriod(1);                       /* restore ticker to default */
    

    Note, although Windows is not a real time OS, it is possible in Windows to get a thread to run at a fixed frequency without any drift, and using Sleep(1) when possible to avoid going cpu bound in the fixed frequency thread. Running the thread at a slightly higher priority will help if there are competing threads. This is often used by games that need a "physics engine" thread that runs at a fixed frequency. Example code is included in the answer to this old question:

    How to coordinate threads properly based on a fixed cycle frequency?

    Example output from a program based on the example in the link, using a fixed frequency of 100hz, run 100 times. There's some variation in each step, but there is no overall drift.

     100 deltas in ms:
    
      9.99973023  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00676775  10.00002346 
     10.00002346  10.00002346  10.00794067  10.00002346 
      9.99973023  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00618129  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00002346   9.99973023  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00090315  10.00148961  10.00148961  10.00090315 
     10.00002346  10.00178284  10.00002346  10.00002346 
     10.00295576  10.00002346  10.00882036  10.00500837 
     10.00002346  10.00559483  10.00559483  10.00647452 
     10.00588806  10.00735421  10.00676775  10.00764744 
     10.00002346  10.00002346  10.00823390  10.00002346 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00002346   9.99973023  10.00002346 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00002346   9.99973023 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00002346   9.99973023 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00002346  10.00002346 
     10.00002346  10.00002346  10.00002346  10.00002346 
    
    elapsed time in ms:
    
    1000.000000000000