C ++ high-performance counters-microsecond-level time statistics, counters in microseconds
In C ++, performance information is often counted by timing, and performance bottleneck is analyzed by time consumption. Generally, the millisecond-level time statistics may be enough, but the millisecond-level statistics are not enough for the performance hotspot that is mandatory in milliliters. In this case, it requires at least microsecond-level statistics, or even accurate to the CPU instruction cycle level. Next we will focus on the millisecond-level timing statistics.
Competition for milliliters-microsecond timing
On Windows, two Windows APIs are required to measure the time consumption in microseconds:
BOOL WINAPI QueryPerformanceFrequency( _Out_ LARGE_INTEGER *lpFrequency);BOOL WINAPI QueryPerformanceCounter( _Out_ LARGE_INTEGER *lpPerformanceCount);
QueryPerformanceFrequency is used to obtain the performance count frequency, the number of times per second,
QueryPerformanceCounter is used to obtain the current performance Count value,
With these two APIs, we can use them to calculate time consumption. The idea is as follows:
Time consumed in seconds = (end Performance Count value-start performance Count value)/performance count frequency microsecond time consumed = (end Performance Count value-start performance Count value) * 1000000/performance count frequencyMicrosecond timing implementation
LARGE_INTEGER freq_;QueryPerformanceFrequency(&freq_);LARGE_INTEGER begin_time;LARGE_INTEGER end_time;QueryPerformanceCounter(&begin_time);Sleep(100);QueryPerformanceCounter(&end_time);double ns_time = (end_time.QuadPart - begin_time.QuadPart) * 1000000.0 / freq_.QuadPart;
Encapsulation of microsecond timing implementation
Although the microsecond precision timing has been implemented above, because variables and so on must be defined every time an API is called, there must be a lot of repeated or similar code in use, so in order to avoid this situation, this implementation is encapsulated as follows:
Class stop_watch {public: stop_watch (): elapsed _ (0) {QueryPerformanceFrequency (& freq _);}~ Stop_watch () {} public: void start () {QueryPerformanceCounter (& begin_time _);} void stop () {LARGE_INTEGER end_time; QueryPerformanceCounter (& end_time ); elapsed _ + = (end_time.QuadPart-begin_time _. quadPart) * 1000000/freq _. quadPart;} void restart () {elapsed _ = 0; start ();} // microsecond double elapsed () {return static_cast <double> (elapsed _);} // millisecond double elapsed_ms () {return elapsed _/1000.0 ;}// second double elapsed_second () {return elapsed _/1000000.0;} private: LARGE_INTEGER freq _; LARGE_INTEGER begin_time _; long elapsed _;};
Then, how can we use this encapsulated class? Let's take a look at the call example:
stop_watch watch;watch.start();Sleep(100);watch.stop();cout << watch.elapsed() << " ns" << endl;
Let's see if the call is more convenient. Isn't it a bit familiar? Yes, that's right. You guessed it...
References
QueryPerformanceFrequency
QueryPerformanceCounter