103 Stimmen

Wie verwendet man QueryPerformanceCounter?

Ich habe vor kurzem beschlossen, dass ich von der Verwendung von Millisekunden zu Mikrosekunden für meine Timer-Klasse zu ändern, und nach einigen Recherchen habe ich beschlossen, dass QueryPerformanceCounter ist wahrscheinlich meine sicherste Wette. (Die Warnung auf Boost::Posix dass es unter Win32 API nicht funktioniert, hat mich ein wenig abgeschreckt). Allerdings bin ich nicht wirklich sicher, wie es zu implementieren.

Ich rufe an, was auch immer ich tun soll. GetTicks() esque Funktion, die ich verwende, und weise sie der Timer-Funktion startingTicks variabel. Um die verstrichene Zeit zu ermitteln, subtrahiere ich einfach den Rückgabewert der Funktion von der Variablen startingTicks und wenn ich den Timer zurücksetze, rufe ich die Funktion einfach erneut auf und weise ihr startingTicks zu. Leider ist es nach dem Code, den ich gesehen habe, nicht so einfach, wie wenn ich einfach QueryPerformanceCounter() und ich bin mir nicht sicher, was ich als Argument übergeben soll.

2 Stimmen

Ich habe Ramonsters Codeschnipsel genommen und sie hier zu einer Bibliothek zusammengestellt: gist.github.com/1153062 für Follower.

3 Stimmen

Wir haben kürzlich die Dokumentation für QueryPerformanceCounter aktualisiert und zusätzliche Informationen zur richtigen Verwendung sowie Antworten auf häufig gestellte Fragen hinzugefügt. Sie können die aktualisierte Dokumentation hier finden msdn.microsoft.com/de-us/library/Windows/desktop/

0 Stimmen

Ich möchte nur erwähnen __rdtsc ist das, was QueryPerformanceCounter verwendet.

172voto

Ramónster Punkte 2288
#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;
}

Dieses Programm sollte eine Zahl nahe bei 1000 ausgeben (der Windows-Schlafmodus ist nicht so genau, aber es sollte etwa 999 sein).

El StartCounter() Funktion zeichnet die Anzahl der Ticks auf, die der Leistungszähler in der CounterStart variabel. Die GetCounter() Funktion gibt die Anzahl der Millisekunden seit StartCounter() zuletzt als Double aufgerufen wurde, wenn also GetCounter() 0,001 zurückgibt, ist es etwa 1 Mikrosekunde her, dass StartCounter() genannt wurde.

Wenn Sie möchten, dass der Timer stattdessen Sekunden verwendet, ändern Sie

PCFreq = double(li.QuadPart)/1000.0;

zu

PCFreq = double(li.QuadPart);

oder wenn Sie Mikrosekunden benötigen, verwenden Sie

PCFreq = double(li.QuadPart)/1000000.0;

Aber in Wirklichkeit geht es um die Bequemlichkeit, da es ein Double zurückgibt.

6 Stimmen

Was genau ist LARGE_INTEGER?

6 Stimmen

Es ist ein Windows-Typ, im Grunde eine portable 64-Bit-Ganzzahl. Seine Definition hängt davon ab, ob das Zielsystem 64-Bit-Ganzzahlen unterstützt oder nicht. Wenn das System keine 64-Bit-Integer unterstützt, wird er als 2 32-Bit-Integer definiert, ein HighPart und ein LowPart. Wenn das System 64-Bit-Integer unterstützt, ist es eine Vereinigung zwischen den 2 32-Bit-Integern und einem 64-Bit-Integer, dem QuadPart.

1 Stimmen

Nun, es gibt die Anzahl der Ticks der hochauflösenden Systemuhr zurück, die meines Erachtens hardwareabhängig ist, und deshalb müssen Sie QueryPerformanceFrequency verwenden, um die Frequenz dieser Uhr herauszufinden. Auf meinem System ist die Frequenz 2.272.000 hz, oder etwa 2,272 Ticks pro Mikrosekunde.

20voto

Ich verwende diese Definitionen:

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

Verwendung (in Klammern, um Neudefinitionen zu verhindern):

TIMER_INIT

{
   TIMER_START
   Sleep(1000);
   TIMER_STOP
}

{
   TIMER_START
   Sleep(1234);
   TIMER_STOP
}

Ausgabe des Anwendungsbeispiels:

1.00003 sec
1.23407 sec

2voto

Alex Martelli Punkte 805329

In der Annahme, dass Sie unter Windows arbeiten (wenn ja, sollten Sie Ihre Frage als solche kennzeichnen!), können Sie unter diese MSDN-Seite finden Sie die Quelle für ein einfaches, nützliches HRTimer C++-Klasse, die die benötigten Systemaufrufe umhüllt, um etwas zu tun, was Ihren Anforderungen sehr nahe kommt (es wäre einfach, eine GetTicks() Methode zu verwenden, insbesondere, um genau was Sie benötigen).

Auf Nicht-Windows-Plattformen gibt es keine QueryPerformanceCounter-Funktion, so dass die Lösung nicht direkt portabel ist. Wenn Sie sie jedoch in eine Klasse wie die oben erwähnte verpacken HRTimer wird es einfacher sein, die Implementierung der Klasse zu ändern, um das zu nutzen, was die aktuelle Plattform tatsächlich bieten kann (vielleicht über Boost oder was auch immer!).

1voto

kagali-san Punkte 2814

Ich würde diese Frage um ein Beispiel für einen NDIS-Treiber erweitern, um Zeit zu gewinnen. Wie man weiß, hat KeQuerySystemTime (nachgeahmt unter NdisGetCurrentSystemTime) eine geringe Auflösung über Millisekunden, und es gibt einige Prozesse wie Netzwerkpakete oder andere IRPs, die einen besseren Zeitstempel benötigen;

Das Beispiel ist genauso einfach:

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

wobei der Divisor 10^3 oder 10^6 ist, je nach gewünschter Auflösung.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X