Как использовать QueryPerformanceCounter?



недавно я решил, что мне нужно перейти от использования миллисекунд к микросекундам для моего класса таймера, и после некоторых исследований я решил, что QueryPerformanceCounter, вероятно, моя самая безопасная ставка. (Предупреждение о Boost::Posix то, что он может не работать на Win32 API, немного отпугнуло меня). Однако, я не совсем уверен, как это реализовать.

то, что я делаю, это вызов whatever GetTicks() функция esque, которую я использую и назначаю ее таймеру startingTicks переменной. Затем, чтобы найти количество прошло время я просто вычитаю возвращаемое значение функции из startingTicks, и когда я сброшу таймер, я просто снова вызову функцию и назначу ей startingTicks. К сожалению, из кода, который я видел, это не так просто, как просто позвонить QueryPerformanceCounter() и я не уверен, что я должен передать в качестве аргумента.

186   4  

4 ответов:

#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 (Windows sleep не так точен, но он должен быть похож на 999).

The StartCounter() функция записывает количество тиков счетчик производительности имеет в CounterStart переменной. Элемент GetCounter() функция возвращает количество миллисекунд, начиная с StartCounter() последний раз вызывался как двойник, так что если GetCounter() возвращает 0.001, то это было около 1 микросекунды с StartCounter() называлась.

если вы хотите иметь вместо того, чтобы затем использовать таймер секунд изменить

PCFreq = double(li.QuadPart)/1000.0;

до

PCFreq = double(li.QuadPart);

или если вы хотите микросекунды, то используйте

PCFreq = double(li.QuadPart)/1000000.0;

но на самом деле речь идет об удобстве, так как он возвращает двойной.

Я использую эти определяет:

/** 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) имеет низкое разрешение выше миллисекунд, и есть некоторые процессы, такие как сетевые пакеты или другие IRPs, которые могут нуждаться в лучшей метке времени;

пример так же просто:

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

где делитель 10^3 или 10^6 в зависимости от требуемого разрешения.

    Ничего не найдено.

Добавить ответ:
Отменить.