`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".