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


답변

Windows (질문에 태그를 지정해야하는 경우)를 사용한다고 가정하면 이 MSDN 페이지HRTimer 에서 필요한 시스템 호출을 래핑 하는 간단하고 유용한 C ++ 클래스 의 소스를 찾을 수 있습니다. ( GetTicks()특히 필요한 작업을 정확히 수행 하기 위해 메서드 를 추가하는 것은 쉽습니다 ).

비 Windows 플랫폼에는 QueryPerformanceCounter 함수가 없으므로 솔루션을 직접 이식 할 수 없습니다. 그러나 위에서 언급 한 것과 같은 클래스로 래핑 HRTimer하면 현재 플랫폼이 실제로 제공 할 수있는 것을 사용하도록 클래스의 구현을 변경하는 것이 더 쉬울 것입니다 (아마도 Boost 등을 통해!).


답변

나는 시간을 얻는 것에 대한 NDIS 드라이버 예제로이 질문을 확장 할 것입니다. 아시다시피, KeQuerySystemTime (NdisGetCurrentSystemTime에서 모방)은 밀리 초 이상의 저해상도를 가지며 네트워크 패킷이나 더 나은 타임 스탬프가 필요할 수있는 기타 IRP와 같은 일부 프로세스가 있습니다.

예제는 다음과 같이 간단합니다.

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

여기서 제수는 필요한 해상도에 따라 10 ^ 3 또는 10 ^ 6입니다.


답변