Je dois calculer le temps d'exécution d'un extrait de code C ++ en quelques secondes. Il doit fonctionner sur des machines Windows ou Unix.
J'utilise le code suivant pour ce faire. (importer avant)
clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;
Cependant, pour les petites entrées ou les déclarations courtes telles que a = a + 1, j'obtiens le résultat "0 seconde". Je pense que ça doit être quelque chose comme 0,0000001 seconde ou quelque chose comme ça.
Je me souviens qu'en System.nanoTime()
Java fonctionne plutôt bien dans ce cas. Cependant, je ne peux pas obtenir la même fonctionnalité exacte de la clock()
fonction de C ++.
Avez-vous une solution?
c++
benchmarking
AhmetB - Google
la source
la source
Réponses:
Vous pouvez utiliser cette fonction que j'ai écrite. Vous appelez
GetTimeMs64()
, et il renvoie le nombre de millisecondes écoulées depuis l'époque Unix en utilisant l'horloge système - tout commetime(NULL)
, sauf en millisecondes.Cela fonctionne à la fois sur Windows et Linux; il est sans fil.
Notez que la granularité est de 15 ms sur windows; sous linux, cela dépend de l'implémentation, mais généralement aussi 15 ms.
la source
gettimeofday
peut donner un résultat inattendu si l'horloge système est modifiée. Si cela pose un problème pour vous, vous voudrez peut-être regarder à laclock_gettime
place.GetTickCount
?gcc -std=c99
GetTickCount
c'est le temps écoulé depuis le démarrage du système, alors que ma fonction renvoie le temps depuis l'époque UNIX ce qui signifie que vous pouvez l'utiliser pour les dates et les heures. Si vous n'êtes intéressé que par le temps écoulé entre deux événements, le mien est toujours un meilleur choix car c'est un int64; GetTickCount est un int32 et déborde tous les 50 jours, ce qui signifie que vous pouvez obtenir des résultats étranges si les deux événements que vous avez enregistrés se trouvent entre le débordement.J'ai un autre exemple de travail qui utilise des microsecondes (UNIX, POSIX, etc.).
Voici le fichier où nous avons codé ceci:
https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c
la source
#include <sys/time.h>
au début de votre exemple.Voici une solution simple en C ++ 11 qui vous donne une résolution satisfaisante.
Ou sur * nix, pour c ++ 03
Voici l'exemple d'utilisation:
Sur https://gist.github.com/gongzhitaao/7062087
la source
/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
Lorsqu'il
progress_timer
est hors de portée, il affichera le temps écoulé depuis sa création.MISE À JOUR : Voici une version qui fonctionne sans Boost (testé sur macOS / iOS):
la source
Windows fournit la fonction QueryPerformanceCounter () et Unix a gettimeofday () Les deux fonctions peuvent mesurer au moins 1 micro-seconde de différence.
la source
#ifdef
doit être ok (et il est en juger par la réponse que vous avez accepté), et je ne vois pas le problème:#ifdef WIN32 #include <windows.h> ... #else ... #endif
.Dans certains programmes que j'ai écrits, j'ai utilisé RDTS à cette fin. RDTSC ne concerne pas le temps mais le nombre de cycles depuis le démarrage du processeur. Il faut le calibrer sur votre système pour obtenir un résultat en seconde, mais c'est vraiment pratique quand on veut évaluer les performances, c'est encore mieux d'utiliser directement le nombre de cycles sans essayer de les remettre en secondes.
(le lien ci-dessus est vers une page wikipedia français, mais il contient des exemples de code C ++, la version anglaise est ici )
la source
Je suggère d'utiliser les fonctions standard de la bibliothèque pour obtenir des informations temporelles du système.
Si vous souhaitez une résolution plus fine, effectuez plus d'itérations d'exécution. Au lieu d'exécuter le programme une fois et d'obtenir des échantillons, exécutez-le 1 000 fois ou plus.
la source
Il est préférable d'exécuter la boucle interne plusieurs fois avec la synchronisation des performances une seule fois et de faire la moyenne en divisant les répétitions de la boucle interne plutôt que d'exécuter le tout (boucle + synchronisation des performances) plusieurs fois et en moyenne. Cela réduira la surcharge du code de synchronisation des performances par rapport à votre section profilée réelle.
Enveloppez vos appels de minuterie pour le système approprié. Pour Windows, QueryPerformanceCounter est assez rapide et "sûr" à utiliser.
Vous pouvez également utiliser "rdtsc" sur n'importe quel PC X86 moderne, mais il peut y avoir des problèmes sur certaines machines multicœurs (le saut de cœur peut changer la minuterie) ou si vous avez activé le pas de vitesse.
la source
(solution spécifique à Windows) La façon actuelle (vers 2017) d'obtenir des horaires précis sous Windows est d'utiliser "QueryPerformanceCounter". Cette approche a l'avantage de donner des résultats très précis et est recommandée par MS. Plop simplement le blob de code dans une nouvelle application console pour obtenir un exemple fonctionnel. Il y a une longue discussion ici: Acquisition d'horodatages haute résolution
la source
Une solution complète et sans faille à la planification des threads, qui devrait donner exactement les mêmes temps pour chaque test, consiste à compiler votre programme pour qu'il soit indépendant du système d'exploitation et à démarrer votre ordinateur afin d'exécuter le programme dans un environnement sans OS. Pourtant, cela est largement impraticable et serait au mieux difficile.
Un bon substitut à la suppression du système d'exploitation consiste simplement à définir l'affinité du thread actuel sur 1 cœur et la priorité sur la plus élevée. Cette alternative devrait fournir des résultats suffisamment cohérents.
Vous devez également désactiver les optimisations qui interféreraient avec le débogage, ce qui pour g ++ ou gcc signifie ajouter
-Og
à la ligne de commande , pour éviter que le code testé ne soit optimisé. Le-O0
drapeau ne doit pas être utilisé car il introduit une surcharge inutile supplémentaire qui serait incluse dans les résultats de synchronisation, faussant ainsi la vitesse chronométrée du code.Au contraire, à la fois en supposant que vous utilisez
-Ofast
(ou, à tout le moins,-O3
) sur la version de production finale et en ignorant le problème de l'élimination du code "mort",-Og
effectue très peu d'optimisations par rapport à-Ofast
;-Og
peut ainsi dénaturer la vitesse réelle du code dans le produit final.En outre, tous les tests de vitesse (dans une certaine mesure) parjure: dans le produit de production final compilé avec
-Ofast
, chaque extrait / section / fonction de code n'est pas isolé; au contraire, chaque extrait de code s'écoule en continu dans le suivant, permettant ainsi au compilateur de potentiellement joindre, fusionner et optimiser ensemble des morceaux de code de partout.Dans le même temps, si vous comparez un extrait de code qui fait un usage
realloc()
intensif, alors l'extrait de code peut s'exécuter plus lentement dans un produit de production avec une fragmentation de mémoire suffisamment élevée. Par conséquent, l'expression «le tout est plus que la somme de ses parties» s'applique à cette situation car le code de la version de production finale peut s'exécuter sensiblement plus rapidement ou plus lentement que l'extrait de code individuel que vous testez en vitesse.Une solution partielle qui peut réduire l'incongruité consiste à utiliser
-Ofast
pour les tests de vitesse AVEC l'ajout deasm volatile("" :: "r"(var))
aux variables impliquées dans le test pour empêcher l'élimination du code mort / boucle.Voici un exemple de comparaison des fonctions de racine carrée sur un ordinateur Windows.
Aussi, merci à Mike Jarvis pour son chronomètre.
Veuillez noter (ceci est très important) que si vous allez exécuter des extraits de code plus volumineux, vous devez vraiment réduire le nombre d'itérations pour éviter que votre ordinateur ne se fige.
la source
-O0
code est une grosse perte de temps car la surcharge-O0
au lieu d'une normale-O2
ou-O3 -march=native
varie énormément en fonction du code et de la charge de travail. par exemple, les variables tmp nommées supplémentaires coûtent du temps à-O0
. Il existe d'autres moyens d'éviter que les choses ne s'optimisent, comme cacher des choses à l'optimiseur avecvolatile
des fonctions non en ligne ou des instructions asm en ligne vides.-O0
n'est même pas presque utilisable car le code a des goulots d'étranglement différents-O0
, pas les mêmes mais pires.-Og
n'est toujours pas très réaliste, selon le code. Au moins-O2
, de préférence-O3
est plus réaliste. Utilisezasm volatile("" ::: "+r"(var))
ou quelque chose pour que le compilateur matérialise une valeur dans un registre et empêche la propagation constante à travers celui-ci.-O3
et l'extrait de code avecasm volatile("" ::: "+r"(var))
.asm volatile("" ::: "+r"( i ));
semble inutile. Dans le code optimisé, il n'y a aucune raison de forcer le compilateur à se matérialiseri
aussi bien qu'à l'i<<7
intérieur de la boucle. Vous l'empêchez d'optimiser autmp -= 128
lieu de changer à chaque fois. L'utilisation du résultat d'un appel de fonction est cependant bonne, si ce n'est pas le casvoid
. Commeint result = (*function_to_do)( i << 7 );
. Vous pouvez utiliser uneasm
déclaration sur ce résultat.function_to_do
afin qu'ellefunction_to_do
puisse être incorporée sans être éliminée. Veuillez me faire savoir si vous avez d'autres suggestions.Pour les cas où vous souhaitez chronométrer le même bout de code à chaque fois qu'il est exécuté (par exemple pour le profilage de code que vous pensez être un goulot d'étranglement), voici un wrapper autour (une légère modification de) la fonction d'Andreas Bonini que je trouve utile:
la source
juste une classe simple qui compare le codeblock:
la source
boost :: timer vous donnera probablement autant de précision que vous en aurez besoin. C'est loin d'être assez précis pour vous dire combien de temps
a = a+1;
cela prendra, mais quelle raison auriez-vous de chronométrer quelque chose qui prend quelques nanosecondes?la source
clock()
fonction de l'en-tête standard C ++.J'ai créé un lambda qui vous appelle un appel de fonction N fois et vous renvoie la moyenne.
Vous pouvez trouver l'en-tête c ++ 11 ici .
la source
J'ai créé un utilitaire simple pour mesurer les performances de blocs de code, en utilisant la high_resolution_clock de la bibliothèque chrono: https://github.com/nfergu/codetimer .
Les minutages peuvent être enregistrés par rapport à différentes touches et une vue agrégée des minutages pour chaque clé peut être affichée.
L'utilisation est la suivante:
la source
Vous pouvez également consulter le
[cxx-rtimers][1]
sur GitHub, qui fournit des routines d'en-tête uniquement pour collecter des statistiques sur l'exécution de tout bloc de code où vous pouvez créer une variable locale. Ces minuteries ont des versions qui utilisent std :: chrono sur C ++ 11, ou des minuteries de la bibliothèque Boost, ou des fonctions de minuterie POSIX standard. Ces minuteries indiqueront la durée moyenne, maximale et minimale passée dans une fonction, ainsi que le nombre de fois qu'elle est appelée. Ils peuvent être utilisés de la manière suivante:la source
C'est comme ça que je fais, peu de code, facile à comprendre, correspond à mes besoins:
Usage:
la source
la source