`GetSystemTimeAsFileTime` vs `GetSystemTimes` vs `QueryPerformanceCounter`

Recently, I made a test about retriving calculate the CPU usage of the specified process. In common, we have following steps:

1.

  a) Get process time at this point(proc_A).

  b) Get system time the this point(sys_A).

2. Sleep for a while.

3. 

  a) Get process time at this point(proc_B).

  b) Get system time the this point(sys_B).

Now we can say, the process CPU usage is (proc_B - proc_A) / (sys_B - sys_A). That easy, right?

Don't stop thinking it more. How can you get the system time? If you are familiar with winAPI(ring3), you're facing three chioces:

1. GetSystemTimeAsFileTime:               http://msdn.microsoft.com/en-us/library/ms724397(v=vs.85).aspx

2. GetSystemTimes:                              http://msdn.microsoft.com/en-us/library/windows/desktop/ms724400(v=vs.85).aspx

3. QueryPerformanceCounter:               http://msdn.microsoft.com/en-us/library/ms644904(v=VS.85).aspx

 

`GetSystemTimes` is a non-accurate time solution. This funciton is famouse for obtaining all processes time among all CPU. Let's see the impl:

I don't find the definition about `.Query`, but here is a good example proves this "lazy" function to be "out of time":

#include <windows.h>
#include <iostream>
using namespace std;

FILETIME operator+(FILETIME a, FILETIME b)
{
    FILETIME c = a;
    c.dwHighDateTime += b.dwHighDateTime;
    c.dwLowDateTime += b.dwLowDateTime;

    return c;
}
ostream &operator<<(ostream &os, FILETIME ft)
{
    os <<ft.dwHighDateTime + ft.dwLowDateTime;

    return os;
}

int main( int argc, char *argv[ ])
{
    FILETIME ft = {};
    FILETIME idle = {}, krnl = {}, usr = {};

    for( int i = 0 ; i< 10 ;i++ )
    {
        GetSystemTimeAsFileTime(&ft);        
        GetSystemTimes(&idle, &krnl, &usr);
        
        // Attempt display time elapsed.
        cout <<"`GetSystemTimeAsFileTime`: " <<ft <<endl;
        cout <<"`GetSystemTimes`: " <<krnl+usr <<endl;
    }

    return 0;
}

The picture shows that `GetSystemAsFileTime` is more accurate than `GetSystemTimes` since the former get the distance but the latter does not.

In addition, the idle time is contained in kernel time + user time. If you want to record the total time, just use kernel time + user time but NOT idle time.

 

`GetSystemTimeAsFileTime` is more accurate than `GetSystemTimes`, but which is a non-realtime time & busy loop(every fast) in impl. Let's see the impl:

It's amazing that the system time is obtained from `SharedUserData`, which is fill by system on every hardware clock interruption. 

Even the `SharedUserData` is synchronized with clock interrupt, you should NOT measure the elapsed time for source-code level performance. See below wrong example:

#include <iostream>
#include <windows.h>
using namespace std;

int main(int argc, char *argv[])
{
    FILETIME ft1 = {}, ft2 = {};

    // Before.
    GetSystemTimeAsFileTime(&ft1);
    // Do something.
    for (int i = 0; i < 100; ++i)
    {
        argc = argc;
    }
    // After
    GetSystemTimeAsFileTime(&ft2);

    // Attempt display time elapsed between two points.
    cout <<"before: " <<ft1.dwHighDateTime <<":" <<ft1.dwLowDateTime <<endl;
    cout <<"after:  " <<ft2.dwHighDateTime <<":" <<ft2.dwLowDateTime <<endl;

    return 0;
}

 

`QueryPerformanceCounter` is the most accurate time function in windows. It's based on the high-resolution performance counter hardware. Let's see the fantasic function.

#include <windows.h>
#include <iostream>
using namespace std;

int main( int argc, char *argv[ ])
{
    LARGE_INTEGER li1 = {}, li2 = {};
    QueryPerformanceCounter(&li1);
    for (int i = 0; i < 1000; ++i); // Very short period.
    QueryPerformanceCounter(&li2);

    cout <<"li1: " <<li1.QuadPart <<endl;
    cout <<"li2: " <<li2.QuadPart <<endl;

    LARGE_INTEGER li3 = {};
    QueryPerformanceFrequency(&li3);
    cout <<"li3: " <<li3.QuadPart <<endl;

    return 0;
}

 

The green circle shows the such a short period can be detected by `QueryPerformanceCounter`.

The red circle tells us a fact that the `QueryPerformanceFrequency` always return the CPU clock tick(in 1000 unit.It's to say, the out parameter * 1000 is equal to CPU clock tick of 1 second) within 1 second.

 

You can reference the code here to measure source level time elapse: 

  http://walfud.googlecode.com/svn/trunk/wCode/src/wTimeMeasurer.h

  http://walfud.googlecode.com/svn/trunk/wCode/src/wTimeMeasurer.cpp

 

Thank list:

  Thank WuPeng for the discuss about the impl of `GetSystemTimes` & `GetSystemTimesAsFileTime`, and specially the example that proves the `GetSystemTimes` to be "lazy".

 

 

 

 

 

posted @ 2013-08-08 21:07  walfud  阅读(3254)  评论(0编辑  收藏  举报