Comment puis-je obtenir le nombre de cycles de processeur dans Win32?
-
02-07-2019 - |
Question
Sous Win32, existe-t-il un moyen d’obtenir un nombre unique de cycles cpu ou quelque chose de similaire qui serait uniforme pour plusieurs processus / langues / systèmes / etc.
Je crée des fichiers journaux, mais je dois produire plusieurs fichiers journaux, car nous hébergeons le runtime .NET, et j'aimerais éviter d'appeler de l'un à l'autre pour vous connecter. En tant que tel, je pensais que je produirais simplement deux fichiers, les combinerais, puis les trier, pour obtenir un calendrier cohérent impliquant des appels inter-mondiaux.
Toutefois, GetTickCount n'augmente pas à chaque appel. Ce n'est donc pas fiable. Existe-t-il un meilleur numéro pour que je puisse recevoir les appels dans le bon ordre lors du tri?
Modifier : grâce à @Greg qui m'a mis sur la bonne voie pour QueryPerformanceCounter , qui a fait le tour.
La solution
Vous pouvez utiliser l'instruction RDTSC (en supposant que x86). Cette instruction donne le compteur de cycle de l’UC, mais sachez qu’elle augmentera très rapidement jusqu’à sa valeur maximale puis qu'elle sera réinitialisée à 0. Comme le mentionne l’article Wikipedia, il serait peut-être préférable d’utiliser le fonction QueryPerformanceCounter .
Autres conseils
Voici un article intéressant! dit de ne pas utiliser RDTSC, mais de utilisez plutôt QueryPerformanceCounter .
Conclusion:
Utiliser des vieux
timeGetTime()
classiques à faire le timing n'est pas fiable sur beaucoup Systèmes d'exploitation Windows parce que la granularité du système la minuterie peut atteindre 10-15 millisecondes, ce qui signifie quetimeBeginPeriod(1)
n’est précis que pour 10-15 millisecondes. [Notez que le granularités élevées se produisent sur NT-basé systèmes d'exploitation tels que Windows NT, 2000 et XP. Windows 95 et 98 ont tendance d'avoir une bien meilleure granularité, environ 1-5 ms.]Cependant, si vous appelez
timeEndPeriod(1)
au début de votre programme (etSleep()
à la fin),Sleep(1)
sera généralement devenir précis à 1-2 millisecondes, et vous fournira extrêmement informations de synchronisation précises.
Sleep(2)
se comporte de la même manière; la durée de temps queQueryPerformanceFrequency
dort réellement pour va main dans la main avec le granularité deQueryPerformanceCounter
, donc après appeler <=> une fois, <=> dormira réellement pour 1-2 millisecondes, <=> pendant 2-3, etc. on (au lieu de dormir par incréments jusqu'à 10-15 ms).Pour un chronométrage plus précis (précision inférieure à la milliseconde), vous vouloir probablement éviter d'utiliser le mnémonique d'assemblage RDTSC parce qu'il est difficile à calibrer ; à la place, utilisez <=> et <=> qui sont précis à moins de 10 microsecondes (0,00001 secondes).
Pour un minutage simple, les deux timeGetTime et QueryPerformanceCounter fonctionnent bien, et QueryPerformanceCounter est évidemment plus précis. Toutefois, si vous devez faire n'importe quel type de " chronométré pauses " (tels que ceux nécessaires pour limite de framerate), vous devez être attention à rester assis dans une boucle QueryPerformanceCounter, en attente de atteindre une certaine valeur; cette volonté consommer 100% de votre processeur. Au lieu de cela, considérons un schéma hybride, où vous appelez Sleep (1) (n'oubliez pas timeBeginPeriod (1) first!) à chaque fois vous devez passer plus de 1 ms de temps, puis entrez seulement le Boucle QueryPerformanceCounter à 100% pour finir le dernier < 1 / 1000ème de seconde du délai dont vous avez besoin. Ce vous donnera des délais ultra précis (précis à 10 microsecondes), avec utilisation du processeur très minime. Voir le code ci-dessus.
System.Diagnostics.Stopwatch.GetTimestamp () renvoie le nombre de cycles du processeur depuis le début de l'heure (peut-être au démarrage de l'ordinateur, mais je ne suis pas sûr) et je ne l'ai jamais vu n'augmenter entre 2 appels.
Les cycles de la CPU seront spécifiques à chaque ordinateur. Vous ne pouvez donc pas l'utiliser pour fusionner le fichier journal de 2 ordinateurs.
La sortie RDTSC peut dépendre de la fréquence d'horloge du cœur actuel, qui n'est ni constante ni cohérente pour les CPU modernes.
Utilisez l'heure du système. Si vous utilisez des flux provenant de plusieurs systèmes, utilisez une source de temps NTP. Vous pouvez ainsi obtenir des lectures de temps fiables et cohérentes; si les frais généraux sont trop importants pour vous, utilisez HPET pour calculer le temps écoulé depuis la La dernière lecture fiable du temps connu est meilleure que l’utilisation du HPET seul.
Utilisez GetTickCount et ajoutez un autre compteur lors de la fusion des fichiers journaux. Vous ne obtiendrez pas une séquence parfaite entre les différents fichiers journaux, mais tous les journaux de chaque fichier seront au moins conservés dans le bon ordre.