Je porte un jeu, qui a été initialement écrit pour l'API Win32, sur Linux (enfin, le portage du port OS X du port Win32 vers Linux).
J'ai implémenté QueryPerformanceCounter
en donnant les uSecondes depuis le démarrage du processus:
BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
gettimeofday(¤tTimeVal, NULL);
performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
performanceCount->QuadPart *= (1000 * 1000);
performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);
return true;
}
Ceci, couplé au fait de QueryPerformanceFrequency()
donner une constante 1000000 comme fréquence, fonctionne bien sur ma machine , me donnant une variable 64 bits qui contient uSeconds
depuis le démarrage du programme.
Alors, est-ce portable? Je ne veux pas découvrir que cela fonctionne différemment si le noyau a été compilé d'une certaine manière ou quelque chose comme ça. Cependant, je suis d'accord avec le fait qu'il ne soit pas portable vers autre chose que Linux.
Synchronisation haute résolution et faible surcharge pour les processeurs Intel
Si vous utilisez du matériel Intel, voici comment lire le compteur d'instructions en temps réel du processeur. Il vous indiquera le nombre de cycles CPU exécutés depuis le démarrage du processeur. C'est probablement le compteur le plus fin que vous puissiez obtenir pour mesurer les performances.
Notez qu'il s'agit du nombre de cycles CPU. Sous Linux, vous pouvez obtenir la vitesse du processeur à partir de / proc / cpuinfo et la diviser pour obtenir le nombre de secondes. Le convertir en un double est assez pratique.
Quand je lance ça sur ma boîte, je reçois
Voici le guide du développeur Intel qui donne des tonnes de détails.
la source
CPUID
réutilisé après la premièreRDTSC
instruction et avant d'exécuter le code en cours de benchmark? Sinon, qu'est-ce qui empêche le code de référence d'être exécuté avant / en parallèle avec le premierRDTSC
, et par conséquent sous-représenté dans leRDTSC
delta?@Bernard:
C'est une bonne question ... Je pense que le code est correct. D'un point de vue pratique, nous l'utilisons dans mon entreprise tous les jours, et nous utilisons un assez large éventail de boîtiers, allant de 2 à 8 cœurs. Bien sûr, YMMV, etc., mais cela semble être une méthode de synchronisation fiable et à faible coût (car elle ne fait pas basculer le contexte dans l'espace système).
Généralement, son fonctionnement est:
Notes spécifiques:
une exécution dans le désordre peut entraîner des résultats incorrects, nous exécutons donc l'instruction "cpuid" qui, en plus de vous donner des informations sur le processeur, synchronise également toute exécution d'instruction dans le désordre.
La plupart des systèmes d'exploitation synchronisent les compteurs sur les processeurs lorsqu'ils démarrent, la réponse est donc bonne en quelques nano-secondes.
Le commentaire d'hibernation est probablement vrai, mais dans la pratique, vous ne vous souciez probablement pas des délais à travers les limites d'hibernation.
concernant speedstep: les nouveaux processeurs Intel compensent les changements de vitesse et renvoie un nombre ajusté. J'ai fait une analyse rapide de certaines des boîtes de notre réseau et n'ai trouvé qu'une seule boîte qui ne l'avait pas: un Pentium 3 exécutant un ancien serveur de base de données. (ce sont des boîtes Linux, j'ai donc vérifié avec: grep constant_tsc / proc / cpuinfo)
Je ne suis pas sûr des processeurs AMD, nous sommes principalement une boutique Intel, même si je sais que certains de nos gourous des systèmes de bas niveau ont fait une évaluation AMD.
J'espère que cela satisfait votre curiosité, c'est un domaine de programmation intéressant et (à mon humble avis) sous-étudié. Vous savez quand Jeff et Joel parlaient de savoir si un programmeur devait ou non connaître C? Je leur criais: "Hé, oubliez ce truc de haut niveau en C ... l'assembleur est ce que vous devez apprendre si vous voulez savoir ce que fait l'ordinateur!"
la source
Vous pourriez être intéressé par la FAQ Linux pour
clock_gettime(CLOCK_REALTIME)
la source
Wine utilise en fait gettimeofday () pour implémenter QueryPerformanceCounter () et il est connu pour faire fonctionner de nombreux jeux Windows sur Linux et Mac.
Démarre http://source.winehq.org/source/dlls/kernel32/cpu.c#L312
mène à http://source.winehq.org/source/dlls/ntdll/time.c#L448
la source
La structure de données est définie comme ayant des microsecondes comme unité de mesure, mais cela ne signifie pas que l'horloge ou le système d'exploitation est réellement capable de mesurer cela finement.
Comme d'autres personnes l'ont suggéré,
gettimeofday()
c'est mauvais car le réglage de l'heure peut entraîner un décalage de l'horloge et perturber votre calcul.clock_gettime(CLOCK_MONOTONIC)
est ce que vous voulez, etclock_getres()
vous indiquera la précision de votre horloge.la source
J'ai obtenu cette réponse de la mesure du temps et des minuteries à haute résolution, partie I
la source
Cette réponse mentionne des problèmes de réglage de l'horloge. Vos problèmes de garantie des unités de graduation et les problèmes avec l'heure d'ajustement sont résolus en C ++ 11 avec la
<chrono>
bibliothèque.L'horloge
std::chrono::steady_clock
est garantie de ne pas être ajustée, et en outre, elle avancera à une vitesse constante par rapport au temps réel, de sorte que les technologies comme SpeedStep ne doivent pas l'affecter.Vous pouvez obtenir des unités de type sécurisé en les convertissant à l'une des
std::chrono::duration
spécialisations, telles questd::chrono::microseconds
. Avec ce type, il n'y a aucune ambiguïté sur les unités utilisées par la valeur de graduation. Cependant, gardez à l'esprit que l'horloge n'a pas nécessairement cette résolution. Vous pouvez convertir une durée en attosecondes sans avoir une horloge aussi précise.la source
D'après mon expérience et ce que j'ai lu sur Internet, la réponse est «non», ce n'est pas garanti. Cela dépend de la vitesse du processeur, du système d'exploitation, de la saveur de Linux, etc.
la source
La lecture du RDTSC n'est pas fiable dans les systèmes SMP, puisque chaque CPU maintient son propre compteur et que chaque compteur n'est pas garanti d'être synchronisé par rapport à une autre CPU.
Je pourrais suggérer d'essayer
clock_gettime(CLOCK_REALTIME)
. Le manuel posix indique que cela doit être implémenté sur tous les systèmes conformes. Il peut fournir un nombre de nanosecondes, mais vous voudrez probablement vérifierclock_getres(CLOCK_REALTIME)
sur votre système pour voir quelle est la résolution réelle.la source
clock_getres(CLOCK_REALTIME)
ne donnera pas la vraie résolution. Il renvoie toujours "1 ns" (une nanoseconde) lorsque les hrtimers sont disponibles, vérifiez leinclude/linux/hrtimer.h
fichier pourdefine HIGH_RES_NSEC 1
(plus sur stackoverflow.com/a/23044075/196561 )