J'ai récemment décidé que je devais passer de millisecondes à microsecondes pour ma classe Timer, et après quelques recherches, j'ai décidé que QueryPerformanceCounter était probablement mon meilleur pari. (L'avertissement sur Boost::Posix
Indiquant que cela ne fonctionnerait peut-être pas sur l'API Win32 m'a un peu gêné). Cependant, je ne sais pas trop comment le mettre en œuvre.
Ce que je fais est d'appeler n'importe quelle fonction GetTicks()
esque que j'utilise et de l'assigner à la variable startingTicks
de Timer. Ensuite, pour trouver le temps écoulé, je soustrais simplement la valeur de retour de la fonction du startingTicks
et, lorsque je réinitialise le chronomètre, je réappelle la fonction et lui assigne de startTicks. Malheureusement, d'après le code que j'ai vu, ce n'est pas aussi simple que d'appeler QueryPerformanceCounter()
, et je ne suis pas sûr de ce que je suis censé passer comme argument.
#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;
}
Ce programme devrait générer un nombre proche de 1000 (Windows Sleep n'est pas si précis, mais il devrait ressembler à 999).
La fonction StartCounter()
enregistre le nombre de ticks du compteur de performance dans la variable CounterStart
. La fonction GetCounter()
renvoie le nombre de millisecondes écoulées depuis le dernier appel de StartCounter()
en double. Si GetCounter()
renvoie 0,001, il s'écoule environ 1 microseconde depuis StartCounter()
a été appelé.
Si vous voulez que le minuteur utilise les secondes à la place, changez
PCFreq = double(li.QuadPart)/1000.0;
à
PCFreq = double(li.QuadPart);
ou si vous voulez microsecondes puis utilisez
PCFreq = double(li.QuadPart)/1000000.0;
Mais c’est vraiment une question de commodité, car cela donne un double.
J'utilise ces définit:
/** 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;
Utilisation (parenthèses pour éviter les redéfinitions):
TIMER_INIT
{
TIMER_START
Sleep(1000);
TIMER_STOP
}
{
TIMER_START
Sleep(1234);
TIMER_STOP
}
Sortie de l'exemple d'utilisation:
1.00003 sec
1.23407 sec
En supposant que vous soyez sur Windows (si donc vous devriez taguer votre question comme telle!), Sur cette page MSDN , vous pouvez trouver le source d'une classe HRTimer
simple et utile, qui encapsule les appels système nécessaires pour faire quelque chose de très proche de ce dont vous avez besoin (il serait facile d’y ajouter une méthode GetTicks()
], en particulier de faire exactement ce dont vous avez besoin).
Sur les plateformes autres que Windows, il n'y a pas de fonction QueryPerformanceCounter, la solution ne sera donc pas directement portable. Cependant, si vous le placez dans une classe telle que le HRTimer
mentionné ci-dessus, il sera plus facile de changer l'implémentation de la classe pour utiliser ce que la plate-forme actuelle est en mesure d'offrir (peut-être via Boost ou autre chose!). ).
Je voudrais prolonger cette question avec un exemple de pilote NDIS sur obtenir du temps. Comme on le sait, KeQuerySystemTime (imité sous NdisGetCurrentSystemTime) a une résolution faible supérieure à la milliseconde et certains processus, tels que les paquets réseau ou d’autres IRP, peuvent nécessiter un meilleur horodatage;
L'exemple est aussi simple:
LONG_INTEGER data, frequency;
LONGLONG diff;
data = KeQueryPerformanceCounter((LARGE_INTEGER *)&frequency)
diff = data.QuadPart / (Frequency.QuadPart/$divisor)
où diviseur est 10 ^ 3, ou 10 ^ 6 en fonction de la résolution requise.