Je souhaite calculer le temps qu'il a fallu à une API pour renvoyer une valeur. Le temps nécessaire pour une telle action est de l'ordre de nanosecondes. Comme l'API est une classe / fonction C ++, j'utilise le timer.h pour calculer la même chose:
#include <ctime>
#include <cstdio>
using namespace std;
int main(int argc, char** argv) {
clock_t start;
double diff;
start = clock();
diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
cout<<"printf: "<< diff <<'\n';
return 0;
}
Le code ci-dessus donne le temps en secondes. Comment obtenir la même chose en nanosecondes et avec plus de précision?
clock()
n'est pas aussi rapide que je le pensais.Réponses:
Ce que d'autres ont publié sur l'exécution répétée de la fonction dans une boucle est correct.
Pour Linux (et BSD), vous souhaitez utiliser clock_gettime () .
Pour les fenêtres, vous souhaitez utiliser QueryPerformanceCounter . Et voici plus sur QPC
Apparemment, il y a un problème connu avec QPC sur certains chipsets, donc vous voudrez peut-être vous assurer que vous ne disposez pas de ces chipsets. En outre, certains AMD double cœur peuvent également poser un problème . Voir le deuxième message de sebbbi, où il déclare:
EDIT 2013/07/16:
Il semble qu'il y ait une controverse sur l'efficacité de QPC dans certaines circonstances, comme indiqué dans http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx
Cependant, cette réponse de StackOverflow https://stackoverflow.com/a/4588605/34329 indique que QPC devrait fonctionner correctement sur n'importe quel système d'exploitation MS après le service pack 2 de Win XP.
Cet article montre que Windows 7 peut déterminer si le (s) processeur (s) ont un TSC invariant et revient à une minuterie externe si ce n'est pas le cas. http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html La synchronisation entre les processeurs est toujours un problème.
Autres bonnes lectures liées aux minuteries:
Voir les commentaires pour plus de détails.
la source
CLOCK_MONOTONIC_RAW
, s'il est disponible, afin d'obtenir l'heure du matériel non ajustée par NTP.Cette nouvelle réponse utilise la fonctionnalité de C ++ 11
<chrono>
. Bien qu'il existe d'autres réponses qui montrent comment utiliser<chrono>
, aucune d'elles ne montre comment utiliser<chrono>
avec l'RDTSC
installation mentionnée dans plusieurs des autres réponses ici. J'ai donc pensé montrer comment utiliserRDTSC
avec<chrono>
. De plus, je vais vous montrer comment vous pouvez modéliser le code de test sur l'horloge afin de pouvoir basculer rapidement entreRDTSC
les fonctions d'horloge intégrées de votre système (qui seront probablement basées surclock()
,clock_gettime()
et / ouQueryPerformanceCounter
.Notez que l'
RDTSC
instruction est spécifique à x86.QueryPerformanceCounter
est Windows uniquement. Etclock_gettime()
c'est POSIX uniquement. Ci-dessous, j'introduis deux nouvelles horloges:std::chrono::high_resolution_clock
etstd::chrono::system_clock
, qui, si vous pouvez supposer C ++ 11, sont maintenant multiplateformes.Tout d'abord, voici comment créer une horloge compatible C ++ 11 à partir des
rdtsc
instructions d'assemblage Intel . Je l'appelleraix::clock
:Tout ce que cette horloge fait est de compter les cycles CPU et de les stocker dans un entier 64 bits non signé. Vous devrez peut-être modifier la syntaxe du langage d'assemblage pour votre compilateur. Ou votre compilateur peut offrir un intrinsèque que vous pouvez utiliser à la place (par exemple
now() {return __rdtsc();}
).Pour construire une horloge, vous devez lui donner la représentation (type de stockage). Vous devez également fournir la période d'horloge, qui doit être une constante de temps de compilation, même si votre machine peut changer la vitesse d'horloge dans différents modes d'alimentation. Et à partir de ceux-ci, vous pouvez facilement définir la durée et le point temporel "natifs" de votre horloge en fonction de ces principes fondamentaux.
Si tout ce que vous voulez faire est de sortir le nombre de coups d'horloge, peu importe le nombre que vous donnez pour la période d'horloge. Cette constante n'entre en jeu que si vous souhaitez convertir le nombre de tics d'horloge en une unité en temps réel telle que les nanosecondes. Et dans ce cas, plus vous êtes en mesure de fournir la vitesse d'horloge avec précision, plus la conversion en nanosecondes sera précise (millisecondes, peu importe).
Voici un exemple de code qui montre comment utiliser
x::clock
. En fait, j'ai modelé le code sur l'horloge car j'aimerais montrer comment vous pouvez utiliser de nombreuses horloges différentes avec exactement la même syntaxe. Ce test particulier montre quelle est la surcharge de la boucle lors de l'exécution de ce que vous voulez chronométrer sous une boucle:La première chose que fait ce code est de créer une unité "en temps réel" pour afficher les résultats. J'ai choisi les picosecondes, mais vous pouvez choisir toutes les unités que vous aimez, en virgule flottante ou intégrale. À titre d'exemple, il y a une
std::chrono::nanoseconds
unité préfabriquée que j'aurais pu utiliser.Comme autre exemple, je veux imprimer le nombre moyen de cycles d'horloge par itération sous forme de virgule flottante, donc je crée une autre durée, basée sur le double, qui a les mêmes unités que le tick de l'horloge (appelé
Cycle
dans le code).La boucle est chronométrée avec des appels de
clock::now()
chaque côté. Si vous souhaitez nommer le type renvoyé par cette fonction, c'est:(comme clairement montré dans l'
x::clock
exemple, et cela est également vrai pour les horloges fournies par le système).Pour obtenir une durée en termes de ticks d'horloge en virgule flottante, on soustrait simplement les deux points temporels, et pour obtenir la valeur par itération, divisez cette durée par le nombre d'itérations.
Vous pouvez obtenir le décompte dans n'importe quelle durée à l'aide de la
count()
fonction membre. Cela renvoie la représentation interne. Enfin, j'utilisestd::chrono::duration_cast
pour convertir la duréeCycle
en duréepicoseconds
et l'imprimer.Pour utiliser ce code, c'est simple:
Ci-dessus, j'exerce le test en utilisant notre produit fait maison
x::clock
et je compare ces résultats avec deux des horloges fournies par le système:std::chrono::high_resolution_clock
etstd::chrono::system_clock
. Pour moi, ceci s'imprime:Cela montre que chacune de ces horloges a une période de ticks différente, car les ticks par itération sont très différents pour chaque horloge. Cependant, une fois converti en une unité de temps connue (par exemple, picosecondes), j'obtiens approximativement le même résultat pour chaque horloge (votre kilométrage peut varier).
Notez que mon code est totalement exempt de "constantes de conversion magiques". En effet, il n'y a que deux nombres magiques dans tout l'exemple:
x::clock
.la source
rdtsc
horloge aura probablement des conversions inexactes vers d'autres unités. C'est une bonne idée de configurer vos mesures afin de pouvoir facilement changer et comparer les horloges (comme indiqué dans cette réponse).Avec ce niveau de précision, il serait préférable de raisonner en tick CPU plutôt qu'en appel système comme clock () . Et n'oubliez pas que s'il faut plus d'une nanoseconde pour exécuter une instruction ... avoir une précision de nanoseconde est quasiment impossible.
Encore, quelque chose comme ça est un début:
Voici le code réel pour récupérer le nombre de ticks d'horloge du processeur 80x86 passés depuis le dernier démarrage du processeur. Il fonctionnera sur Pentium et supérieur (386/486 non pris en charge). Ce code est en fait spécifique à MS Visual C ++, mais peut être probablement très facilement porté vers n'importe quoi d'autre, tant qu'il prend en charge l'assemblage en ligne.
Cette fonction a également l'avantage d'être extrêmement rapide - son exécution ne prend généralement pas plus de 50 cycles CPU.
Utilisation des chiffres de chronométrage :
Si vous avez besoin de traduire les comptages d'horloge en temps réel écoulé, divisez les résultats par la vitesse d'horloge de votre puce. N'oubliez pas que le GHz «nominal» est susceptible d'être légèrement différent de la vitesse réelle de votre puce. Pour vérifier la vitesse réelle de votre puce, vous pouvez utiliser plusieurs très bons utilitaires ou l'appel Win32, QueryPerformanceFrequency ().
la source
Pour ce faire correctement, vous pouvez utiliser l'une des deux méthodes suivantes, soit avec,
RDTSC
soit avecclock_gettime()
. La seconde est environ 2 fois plus rapide et a l'avantage de donner le bon temps absolu. Notez que pourRDTSC
fonctionner correctement, vous devez l'utiliser comme indiqué (d'autres commentaires sur cette page comportent des erreurs et peuvent donner des valeurs de synchronisation incorrectes sur certains processeurs)et pour clock_gettime: (j'ai choisi arbitrairement la résolution microseconde)
le timing et les valeurs produites:
la source
J'utilise ce qui suit pour obtenir les résultats souhaités:
la source
Pour C ++ 11 , voici un simple wrapper:
Ou pour C ++ 03 sur * nix,
Exemple d'utilisation:
Sur https://gist.github.com/gongzhitaao/7062087
la source
En général, pour déterminer combien de temps il faut pour appeler une fonction, vous voulez le faire plusieurs fois qu'une seule fois. Si vous appelez votre fonction une seule fois et que son exécution prend très peu de temps, vous avez toujours la surcharge d'appeler les fonctions de minuterie et vous ne savez pas combien de temps cela prend.
Par exemple, si vous estimez que votre fonction peut prendre 800 ns pour s'exécuter, appelez-la en boucle dix millions de fois (ce qui prendra alors environ 8 secondes). Divisez le temps total par dix millions pour obtenir le temps par appel.
la source
Vous pouvez utiliser la fonction suivante avec gcc fonctionnant sous des processeurs x86:
avec Digital Mars C ++:
qui lit la minuterie haute performance sur la puce. J'utilise ceci lors du profilage.
la source
unsigned int
comme type interne.Si vous avez besoin d'une précision inférieure à la seconde, vous devez utiliser des extensions spécifiques au système et vous devrez consulter la documentation du système d'exploitation. POSIX prend en charge jusqu'à microsecondes avec gettimeofday , mais rien de plus précis puisque les ordinateurs n'avaient pas de fréquences supérieures à 1 GHz.
Si vous utilisez Boost, vous pouvez vérifier boost :: posix_time .
la source
J'utilise le code Borland, voici le code ti_hund qui me donne parfois un nombre négatif mais le timing est assez bon.
la source
En utilisant la méthode de Brock Adams, avec une classe simple:
Exemple d'utilisation:
Résultat:
le test a pris: 0,0002 ms
A une surcharge d'appel de fonction, mais devrait être encore plus que suffisamment rapide :)
la source
Vous pouvez utiliser Embedded Profiler (gratuit pour Windows et Linux) qui a une interface avec un minuteur multiplateforme (dans un nombre de cycles de processeur) et peut vous donner un nombre de cycles par seconde:
Le recalcul du nombre de cycles en temps est peut-être une opération dangereuse avec les processeurs modernes où la fréquence du processeur peut être modifiée de manière dynamique. Par conséquent, pour être sûr que les temps convertis sont corrects, il est nécessaire de fixer la fréquence du processeur avant le profilage.
la source
Si c'est pour Linux, j'utilise la fonction "gettimeofday", qui retourne une structure qui donne les secondes et les microsecondes depuis l'Epoch. Vous pouvez ensuite utiliser timersub pour soustraire les deux pour obtenir la différence de temps et la convertir en la précision de temps souhaitée. Cependant, vous spécifiez des nanosecondes, et il semble que la fonction clock_gettime () soit ce que vous recherchez. Il met le temps en termes de secondes et de nanosecondes dans la structure que vous y passez.
la source
Qu'est ce que tu penses de ça:
la source
Voici une belle minuterie Boost qui fonctionne bien:
la source
Copier-coller-struct minimaliste + utilisation paresseuse
Si l'idée est d'avoir une structure minimaliste que vous pouvez utiliser pour des tests rapides, alors je vous suggère de simplement copier et coller n'importe où dans votre fichier C ++ juste après le
#include
's. C'est le seul cas dans lequel je sacrifie le formatage de style Allman.Vous pouvez facilement ajuster la précision dans la première ligne de la structure. Les valeurs possibles sont:
nanoseconds
,microseconds
,milliseconds
,seconds
,minutes
ouhours
.Usage
Résultat de sortie standard
Si vous voulez un résumé après l'exécution
Si vous voulez le rapport après, parce que, par exemple, votre code entre les deux écrit également sur la sortie standard. Ajoutez ensuite la fonction suivante à la structure (juste avant MeasureTime ()):
Alors vous pouvez simplement utiliser:
Ce qui listera toutes les marques comme avant, mais après l'exécution de l'autre code. Notez que vous ne devez pas utiliser à la fois
m.s()
etm.t()
.la source