code

QueryPerformanceCounter를 사용하는 방법?

codestyles 2020. 9. 1. 07:31
반응형

QueryPerformanceCounter를 사용하는 방법?


최근에 Timer 클래스를 밀리 초에서 마이크로 초로 변경해야한다고 결정했고, 몇 가지 조사 끝에 QueryPerformanceCounter가 아마도 가장 안전한 방법이라고 결정했습니다. ( Boost::PosixWin32 API에서 작동하지 않을 수 있다는 경고 는 나를 약간 실망 시켰습니다.) 그러나 구현 방법을 잘 모르겠습니다.

내가하는 일은 GetTicks()내가 사용 하는 esque 함수를 호출 하고 Timer의 startingTicks변수에 할당하는 것 입니다. 그런 다음 경과 된 시간을 확인하기 위해에서 함수의 반환 값을 빼고 startingTicks타이머를 재설정 할 때 함수를 다시 호출하고 startingTicks를 할당합니다. 불행히도 코드에서를 호출하는 것만 큼 간단 QueryPerformanceCounter()하지 않으며 인수로 전달해야 할 내용이 확실하지 않습니다.


#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;
}

이 프로그램은 1000에 가까운 숫자를 출력해야합니다 (창 절전은 정확하지는 않지만 999와 같아야합니다).

StartCounter()함수는 성능 카운터가 CounterStart변수 에있는 틱 수를 기록합니다 . GetCounter()함수 StartCounter()는 마지막으로 double로 호출 된 이후의 밀리 초 수를 GetCounter()반환 하므로 0.001을 반환 하면 StartCounter()호출 된 이후 약 1 마이크로 초 입니다.

타이머가 초를 대신 사용하도록하려면

PCFreq = double(li.QuadPart)/1000.0;

PCFreq = double(li.QuadPart);

또는 마이크로 초를 원한다면

PCFreq = double(li.QuadPart)/1000000.0;

그러나 실제로는 double을 반환하기 때문에 편리합니다.


이 정의를 사용합니다.

/** 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;

사용법 (재정의를 방지하는 대괄호) :

TIMER_INIT

{
   TIMER_START
   Sleep(1000);
   TIMER_STOP
}

{
   TIMER_START
   Sleep(1234);
   TIMER_STOP
}

사용 예의 출력 :

1.00003 sec
1.23407 sec

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!).


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.

참고URL : https://stackoverflow.com/questions/1739259/how-to-use-queryperformancecounter

반응형