Mise à jour de réponse pour une question aussi ancienne.
Cette nouvelle réponse utilise C++11 <chrono>
des installations. Bien qu'il existe d'autres réponses qui montrent comment utiliser <chrono>
, aucun d'entre eux montre comment utiliser <chrono>
avec l' RDTSC
installation mentionné dans plusieurs des autres réponses ici. J'ai donc pensé que je voudrais montrer comment utiliser RDTSC
avec <chrono>
. En outre, je vais vous montrer comment vous pouvez templatize le code de test sur l'horloge, de sorte que vous pouvez rapidement basculer entre RDTSC
et de votre système d'horloge intégrée des installations (ce qui sera probablement fondée sur clock()
, clock_gettime()
et/ou QueryPerformanceCounter
.
Notez que RDTSC
est Intel uniquement. QueryPerformanceCounter
s'applique uniquement à Windows. Et clock_gettime()
est POSIX. Ci-dessous j'ai introduit deux nouvelles horloges: std::chrono::high_resolution_clock
et std::chrono::system_clock
, qui, si l'on peut supposer C++11, sont maintenant de la croix-plate-forme.
Tout d'abord, voici une façon de créer un C++11-compatible horloge de l'Intel rdtsc
instructions de montage. Je vais l'appeler x::clock
:
#include <chrono>
namespace x
{
struct clock
{
typedef unsigned long long rep;
typedef std::ratio<1, 2800000000> period; // My machine is 2.8 GHz
typedef std::chrono::duration<rep, period> duration;
typedef std::chrono::time_point<clock> time_point;
static const bool is_steady = true;
static time_point now() noexcept
{
unsigned lo, hi;
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
return time_point(duration(static_cast<rep>(hi) << 32 | lo));
}
};
} // x
Toute cette horloge n'est de compter les cycles CPU et de le stocker dans un 64 bits non signé entier. Vous devrez peut-être ajuster l'assemblée de la syntaxe du langage de votre compilateur. Ou votre compilateur peut offrir une intrinsèques vous pouvez utiliser à la place (par exemple, now() {return __rdtsc();}
).
Pour construire une horloge de vous donner la représentation (type de stockage). Vous devez également fournir la période d'horloge, qui doit être un moment de la compilation constante, même si votre machine peut changer la vitesse d'horloge dans les différents modes d'alimentation. Et à partir de ceux que vous pouvez facilement définir votre horloge "native" le temps de la durée et de temps en termes de ces principes fondamentaux.
Si tout ce que vous voulez faire est de sortie, le nombre de tops d'horloge, il n'importe pas vraiment ce que le numéro que vous donnez à la période d'horloge. Cette constante n'est mise en jeu si vous voulez convertir le nombre de tops d'horloge en temps réel de l'unité tels que nanosecondes. Et dans ce cas, la plus précise, vous êtes en mesure de fournir la vitesse d'horloge, plus précise sera la conversion de nanosecondes, (millisecondes, peu importe).
Ci-dessous est un exemple de code qui montre comment utiliser x::clock
. En fait, j'ai modélisé le code sur l'horloge que j'aimerais vous montrer comment vous pouvez utiliser différentes horloges avec exactement la même syntaxe. Ce test particulier est en montrant ce que la boucle de la charge lors de l'exécution de ce que vous voulez de temps en vertu d'une boucle:
#include <iostream>
template <class clock>
void
test_empty_loop()
{
// Define real time units
typedef std::chrono::duration<unsigned long long, std::pico> picoseconds;
// or:
// typedef std::chrono::nanoseconds nanoseconds;
// Define double-based unit of clock tick
typedef std::chrono::duration<double, typename clock::period> Cycle;
using std::chrono::duration_cast;
const int N = 100000000;
// Do it
auto t0 = clock::now();
for (int j = 0; j < N; ++j)
asm volatile("");
auto t1 = clock::now();
// Get the clock ticks per iteration
auto ticks_per_iter = Cycle(t1-t0)/N;
std::cout << ticks_per_iter.count() << " clock ticks per iteration\n";
// Convert to real time units
std::cout << duration_cast<picoseconds>(ticks_per_iter).count()
<< "ps per iteration\n";
}
La première chose que ce code n'est de créer un "temps réel" de l'appareil pour afficher les résultats. J'ai choisi de picosecondes, mais vous pouvez choisir les unités que vous souhaitez, soit entier ou à virgule flottante fonction. Comme un exemple, il y a un pré-fabriqué std::chrono::nanoseconds
unité, j'ai pu utiliser.
Comme autre exemple, je veux imprimer le nombre moyen de cycles d'horloge par itération comme un flottant, donc je créer un autre la durée, sur le double, qui a les mêmes unités que l'horloge tick (appelés Cycle
dans le code).
La boucle est chronométré avec des appels à des clock::now()
sur chaque côté. Si vous souhaitez nommer le type retourné par cette fonction, il est:
typename clock::time_point t0 = clock::now();
(comme le montre clairement le x::clock
exemple, et est également vrai de l'fournis par le système d'horloges).
Pour obtenir une durée, en termes de virgule flottante tops d'horloge on se soustrait les deux points dans le temps, et pour obtenir le par itération de la valeur, de diviser cette durée par le nombre d'itérations.
Vous pouvez obtenir le nombre dans la durée à l'aide de la count()
de la fonction membre. Ceci renvoie à la représentation interne. Enfin je utiliser std::chrono::duration_cast
pour convertir la durée Cycle
de la durée picoseconds
et l'imprimer.
Pour utiliser ce code est simple:
int main()
{
std::cout << "\nUsing rdtsc:\n";
test_empty_loop<x::clock>();
std::cout << "\nUsing std::chrono::high_resolution_clock:\n";
test_empty_loop<std::chrono::high_resolution_clock>();
std::cout << "\nUsing std::chrono::system_clock:\n";
test_empty_loop<std::chrono::system_clock>();
}
Ci-dessus, je exercer le test à l'aide de notre maison x::clock
, et de comparer ces résultats avec l'aide de deux fournis par le système d'horloges: std::chrono::high_resolution_clock
et std::chrono::system_clock
. Pour moi, cela m'affiche:
Using rdtsc:
1.72632 clock ticks per iteration
616ps per iteration
Using std::chrono::high_resolution_clock:
0.620105 clock ticks per iteration
620ps per iteration
Using std::chrono::system_clock:
0.00062457 clock ticks per iteration
624ps per iteration
Cela montre que chacune de ces horloges a une autre tique de cette période, comme les tiques par itération est très différente pour chaque horloge. Cependant lors de la conversion à une unité de temps (par exemple, picosecondes), j'ai environ le même résultat pour chaque horloge (votre kilométrage peut varier).
Notez comment mon code est complètement libre de la "magie constantes de conversion". En effet, il y a seulement deux numéros de magie dans l'ensemble de l'exemple:
- La vitesse d'horloge de ma machine afin de définir
x::clock
.
- Le nombre d'itérations de tester plus. Si la modification de ce nombre rend vos résultats varient grandement, alors vous devriez probablement faire le nombre d'itérations plus élevé, ou vider votre ordinateur de processus concurrents lors des tests.