Partager via


Minutage des jeux et processeurs multicœurs.

Avec les technologies de gestion de l’alimentation de plus en plus courantes dans les ordinateurs d’aujourd’hui, une méthode couramment utilisée pour obtenir des minutages processeur haute résolution, l’instruction RDTSC, peut ne plus fonctionner comme prévu. Cet article suggère une solution plus précise et fiable pour obtenir des minutages d’UC haute résolution à l’aide des API Windows QueryPerformanceCounter et QueryPerformanceFrequency.

Arrière-plan

Depuis l’introduction du jeu d’instructions x86 P5, de nombreux développeurs de jeux ont utilisé le compteur d’horodatage de lecture, l’instruction RDTSC, pour effectuer un minutage haute résolution. Les minuteurs multimédias Windows sont suffisamment précis pour le traitement du son et de la vidéo, mais avec des durées d’images d’une douzaine de millisecondes ou moins, ils n’ont pas assez de résolution pour fournir des informations delta-time. De nombreux jeux utilisent encore un minuteur multimédia au démarrage pour établir la fréquence du processeur, et ils utilisent cette valeur de fréquence pour mettre à l’échelle les résultats de RDTSC afin d’obtenir une heure précise. En raison des limitations de RDTSC, l’API Windows expose le moyen le plus correct d’accéder à cette fonctionnalité par le biais des routines QueryPerformanceCounter et QueryPerformanceFrequency.

Cette utilisation de RDTSC pour le timing souffre de ces problèmes fondamentaux :

  • Valeurs discontinues. L’utilisation de RDTSC suppose directement que le thread s’exécute toujours sur le même processeur. Les systèmes multiprocesseurs et double cœur ne garantissent pas la synchronisation de leurs compteurs de cycle entre les cœurs. Cela est exacerbé lorsqu’il est combiné avec des technologies modernes de gestion de l’alimentation qui inactivent et restaurent différents cœurs à des moments différents, ce qui entraîne une non synchronisation des cœurs. Pour une application, cela entraîne généralement des problèmes ou des blocages potentiels lorsque le thread saute entre les processeurs et obtient des valeurs de minutage qui entraînent de grands deltas, des deltas négatifs ou un minutage arrêté.
  • Disponibilité du matériel dédié. RDTSC verrouille les informations de minutage que l’application demande au compteur de cycle du processeur. Pendant de nombreuses années, c’était le meilleur moyen d’obtenir des informations de minutage de haute précision, mais les cartes mères plus récentes incluent maintenant des appareils de minutage dédiés qui fournissent des informations de minutage à haute résolution sans les inconvénients de RDTSC.
  • Variabilité de la fréquence du processeur. L’hypothèse est souvent faite que la fréquence du processeur est fixe pendant la durée de vie du programme. Toutefois, avec les technologies modernes de gestion de l’alimentation, il s’agit d’une hypothèse incorrecte. Bien qu’initialement limité aux ordinateurs portables et autres appareils mobiles, la technologie qui modifie la fréquence du processeur est utilisée dans de nombreux PC de bureau haut de gamme; La désactivation de sa fonction pour maintenir une fréquence cohérente n’est généralement pas acceptable pour les utilisateurs.

Recommandations

Les jeux ont besoin d’informations de minutage précises, mais vous devez également implémenter le code de minutage de manière à éviter les problèmes associés à l’utilisation de RDTSC. Lorsque vous implémentez un minutage haute résolution, procédez comme suit :

  1. Utilisez QueryPerformanceCounter et QueryPerformanceFrequency au lieu de RDTSC. Ces API peuvent utiliser RDTSC, mais elles peuvent plutôt utiliser des appareils de minutage sur la carte mère ou d’autres services système qui fournissent des informations de minutage haute résolution de haute qualité. Bien que RDTSC soit beaucoup plus rapide que QueryPerformanceCounter, ce dernier étant un appel d’API, il s’agit d’une API qui peut être appelée plusieurs centaines de fois par image sans impact notable. (Néanmoins, les développeurs doivent essayer que leurs jeux appellent QueryPerformanceCounter aussi peu que possible pour éviter toute pénalité de performances.)

  2. Lors du calcul des deltas, les valeurs doivent être limitées pour s’assurer que les bogues dans les valeurs de minutage ne provoquent pas de blocages ou de calculs liés au temps instables. La plage de pinces doit être comprise entre 0 (pour empêcher les valeurs delta négatives) à une valeur raisonnable en fonction de votre fréquence d’images attendue la plus faible. Le serrage est susceptible d’être utile dans n’importe quel débogage de votre application, mais veillez à le garder à l’esprit si vous effectuez une analyse des performances ou exécutez le jeu dans un mode non optimisé.

  3. Calculez tout le minutage sur un seul thread. Le calcul du minutage sur plusieurs threads (par exemple, avec chaque thread associé à un processeur spécifique) réduit considérablement les performances des systèmes multicœurs.

  4. Définissez ce thread unique pour qu’il reste sur un seul processeur à l’aide de l’API Windows SetThreadAffinityMask. En règle générale, il s’agit du main fil de jeu. Si QueryPerformanceCounter et QueryPerformanceFrequency s’ajustent généralement pour plusieurs processeurs, des bogues dans le BIOS ou les pilotes peuvent entraîner le retour de valeurs différentes lorsque le thread passe d’un processeur à un autre. Il est donc préférable de conserver le thread sur un seul processeur.

    Tous les autres threads doivent fonctionner sans collecter leurs propres données de minuteur. Nous vous déconseillons d’utiliser un thread worker pour calculer le minutage, car cela deviendra un goulot d’étranglement de synchronisation. Au lieu de cela, les threads de travail doivent lire les horodatages du thread main, et comme les threads de travail lisent uniquement les horodatages, il n’est pas nécessaire d’utiliser des sections critiques.

  5. Appelez QueryPerformanceFrequency une seule fois, car la fréquence ne change pas pendant l’exécution du système.

Compatibilité des applications

De nombreux développeurs ont fait des hypothèses sur le comportement de RDTSC pendant de nombreuses années, il est donc très probable que certaines applications existantes présentent des problèmes lorsqu’elles s’exécutent sur un système avec plusieurs processeurs ou cœurs en raison de l’implémentation du moment. Ces problèmes se manifesteront généralement sous forme de gl démangeaisons ou de mouvement lent. Il n’existe pas de solution simple pour les applications qui ne connaissent pas la gestion de l’alimentation, mais il existe un shim existant pour forcer une application à toujours s’exécuter sur un seul processeur dans un système multiprocesseur.

Pour créer ce shim, téléchargez microsoft Application Compatibility Toolkit à partir de Compatibilité des applications Windows.

À l’aide de l’administrateur de compatibilité, qui fait partie du kit de ressources, créez une base de données de votre application et les correctifs associés. Créez un nouveau mode de compatibilité pour cette base de données et sélectionnez le correctif de compatibilité SingleProcAffinity pour forcer l’exécution de tous les threads de l’application sur un seul processeur/cœur. À l’aide de l’outil en ligne de commande Fixpack.exe (qui fait également partie du kit de ressources), vous pouvez convertir cette base de données en package installable pour l’installation, le test et la distribution.

Pour obtenir des instructions sur l’utilisation de l’administrateur de compatibilité, consultez la documentation du kit de ressources. Pour obtenir la syntaxe et des exemples d’utilisation de Fixpack.exe, consultez son aide en ligne de commande.

Pour obtenir des informations orientées client, consultez les articles base de connaissances suivants de l’aide et du support Microsoft :