How to use QueryPerformanceCounter?

后端 未结 4 1729
难免孤独
难免孤独 2020-11-22 08:36

I recently decided that I needed to change from using milliseconds to microseconds for my Timer class, and after some research I\'ve decided that QueryPerformanceCounter is

相关标签:
4条回答
  • 2020-11-22 09:00

    I use these defines:

    /** Use to init the clock */
    #define TIMER_INIT \
        LARGE_INTEGER frequency; \
        LARGE_INTEGER t1,t2; \
        double elapsedTime; \
        QueryPerformanceFrequency(&frequency);
    
    
    /** Use to start the performance timer */
    #define TIMER_START QueryPerformanceCounter(&t1);
    
    /** Use to stop the performance timer and output the result to the standard stream. Less verbose than \c TIMER_STOP_VERBOSE */
    #define TIMER_STOP \
        QueryPerformanceCounter(&t2); \
        elapsedTime=(float)(t2.QuadPart-t1.QuadPart)/frequency.QuadPart; \
        std::wcout<<elapsedTime<<L" sec"<<endl;
    

    Usage (brackets to prevent redefines):

    TIMER_INIT
    
    {
       TIMER_START
       Sleep(1000);
       TIMER_STOP
    }
    
    {
       TIMER_START
       Sleep(1234);
       TIMER_STOP
    }
    

    Output from usage example:

    1.00003 sec
    1.23407 sec
    
    0 讨论(0)
  • 2020-11-22 09:07
    #include <windows.h>
    
    double PCFreq = 0.0;
    __int64 CounterStart = 0;
    
    void StartCounter()
    {
        LARGE_INTEGER li;
        if(!QueryPerformanceFrequency(&li))
        cout << "QueryPerformanceFrequency failed!\n";
    
        PCFreq = double(li.QuadPart)/1000.0;
    
        QueryPerformanceCounter(&li);
        CounterStart = li.QuadPart;
    }
    double GetCounter()
    {
        LARGE_INTEGER li;
        QueryPerformanceCounter(&li);
        return double(li.QuadPart-CounterStart)/PCFreq;
    }
    
    int main()
    {
        StartCounter();
        Sleep(1000);
        cout << GetCounter() <<"\n";
        return 0;
    }
    

    This program should output a number close to 1000 (windows sleep isn't that accurate, but it should be like 999).

    The StartCounter() function records the number of ticks the performance counter has in the CounterStart variable. The GetCounter() function returns the number of milliseconds since StartCounter() was last called as a double, so if GetCounter() returns 0.001 then it has been about 1 microsecond since StartCounter() was called.

    If you want to have the timer use seconds instead then change

    PCFreq = double(li.QuadPart)/1000.0;
    

    to

    PCFreq = double(li.QuadPart);
    

    or if you want microseconds then use

    PCFreq = double(li.QuadPart)/1000000.0;
    

    But really it's about convenience since it returns a double.

    0 讨论(0)
  • 2020-11-22 09:15

    Assuming you're on Windows (if so you should tag your question as such!), on this MSDN page you can find the source for a simple, useful HRTimer C++ class that wraps the needed system calls to do something very close to what you require (it would be easy to add a GetTicks() method to it, in particular, to do exactly what you require).

    On non-Windows platforms, there's no QueryPerformanceCounter function, so the solution won't be directly portable. However, if you do wrap it in a class such as the above-mentioned HRTimer, it will be easier to change the class's implementation to use what the current platform is indeed able to offer (maybe via Boost or whatever!).

    0 讨论(0)
  • 2020-11-22 09:17

    I would extend this question with a NDIS driver example on getting time. As one knows, KeQuerySystemTime (mimicked under NdisGetCurrentSystemTime) has a low resolution above milliseconds, and there are some processes like network packets or other IRPs which may need a better timestamp;

    The example is just as simple:

    LONG_INTEGER data, frequency;
    LONGLONG diff;
    data = KeQueryPerformanceCounter((LARGE_INTEGER *)&frequency)
    diff = data.QuadPart / (Frequency.QuadPart/$divisor)
    

    where divisor is 10^3, or 10^6 depending on required resolution.

    0 讨论(0)
提交回复
热议问题