Passer au contenu principal
Les fabricants de processeurs cherchent constamment à équilibrer les performances, la consommation d’énergie et la surface de la puce. La raison en est que les clients ont des habitudes d’utilisation et des priorités différentes. Une personne qui utilise un ordinateur de bureau s’intéresse davantage aux performances, tandis qu’un utilisateur d’ordinateur portable s’intéresse davantage à l’autonomie de la batterie. Une surface de puce plus petite peut se traduire par des coûts de production moindres. Pour répondre à ces exigences concurrentes, les fabricants de processeurs conçoivent des architectures hétérogènes qui permettent au système de s’adapter dynamiquement aux exigences de la charge de travail actuelle tout en maintenant une bonne rentabilité. Les fabricants de processeurs ont mis en œuvre une topologie hétérogène en utilisant des cœurs de processeur de différents niveaux d’efficacité. Cette approche a remplacé certains cœurs d’une architecture de processeur existante par des cœurs plus économes en énergie. Si l’utilisateur n’a pas besoin de toute la puissance du processeur, le système d’exploitation désactive les cœurs plus performants pour économiser une quantité importante d’énergie, ce qui prolonge l’autonomie de la batterie. Lorsqu’il faut plus de performances, le système d’exploitation peut activer dynamiquement les cœurs plus performants pour gérer la charge de travail accrue.

Matériel

Les divers fabricants de matériel indépendants (IHV) définissent les topologies de processeurs hétérogènes de façon différente. Intel et Qualcomm utilisent les termes Performance et Efficiency, tandis qu’AMD utilise les termes Performance et Compact. Chaque fabricant fait des compromis entre performances et efficacité lors de la conception de la topologie de ses cœurs. Les exemples suivants illustrent certains des choix de conception en jeu :
  • Tailles de cache différentes
    • Les différents cœurs peuvent avoir des tailles de cache différentes.
    • Par exemple, les cœurs performants peuvent avoir des caches L1 et L2 plus grands.
  • Partage du cache
    • Le niveau de partage des caches entre les cœurs peut varier.
    • Par exemple, les cœurs plus performants peuvent chacun disposer d’un cache L2 privé, tandis que les cœurs plus efficaces peuvent partager un seul cache L2.
  • Prise en charge du multithreading simultané (SMT)
    • Certains cœurs peuvent prendre en charge le SMT alors que d’autres non.
    • Intel désigne le SMT sous le nom d’Hyper-Threading.
  • Disposition interne des cœurs
    • Les ressources internes des divers types de cœurs peuvent être différentes.
    • Par exemple, les cœurs performants peuvent comprendre davantage de pipelines à virgule flottante, de pipelines ALU ou des voies de données plus larges.
  • Fréquence maximale
    • La fréquence maximale peut différer d’un type de cœur à l’autre.
    • Par exemple, les cœurs performants peuvent atteindre une fréquence plus élevée que les cœurs efficaces.
Ces différences visent à équilibrer les performances et la consommation d’énergie entre les cœurs d’un processeur. Un cœur à fréquence plus élevée offre de meilleures performances au prix d’une consommation d’énergie accrue. Plusieurs cœurs partageant tous le même cache réduisent la taille de la puce, ce qui diminue la consommation d’énergie, mais au prix de performances moindres. L’objectif est de permettre des choix plus dynamiques en matière de performances et de consommation d’énergie. Si l’utilisateur n’a pas besoin de performances maximales, le système d’exploitation bascule vers des cœurs plus efficaces pour réduire la consommation d’énergie. Il est important de noter que Windows exige que tous les cœurs du processeur prennent en charge la même architecture de jeu d’instructions (ISA). Cette exigence signifie que si un processeur prend en charge un jeu d’instructions particulier, tous ses cœurs prennent en charge ce jeu. Par exemple, si le processeur indique qu’il prend en charge AVX2, alors tous les cœurs prennent en charge AVX2. Pour obtenir des détails précis sur les différences entre les cœurs performants et efficaces, consultez la documentation officielle de chaque IHV.

Données de performances

On s’attend à ce que des cœurs de niveaux d’efficacité différents offrent des performances différentes. Un cœur est conçu pour les performances et l’autre pour les économies d’énergie. La question est de savoir à quel point les cœurs diffèrent. Les données présentées sont un regroupement de plusieurs IHV. Chaque IHV présente une mise à l’échelle différente pour chaque test, selon les choix qu’il a faits pour sa topologie. Bien que les chiffres exacts diffèrent, les tendances sont semblables chez tous les IHV. De plus, chaque génération de processeurs fait des compromis différents, ce qui modifie leurs chiffres relatifs. La production de données pour tous les IHV et toutes les générations existants dépasse la portée de cet article.

Tests synthétiques

Les mathématiques vectorielles représentent une part importante du travail qu’un titre de jeu effectue dans une image. Cette charge de travail peut aller de la physique à l’IA en passant par le rendu. Le jeu effectue ce travail à l’aide de types vectoriels comportant trois ou quatre nombres à virgule flottante qui tiennent dans un seul registre SSE de 128 bits. Ces calculs couvrent un large éventail d’opérations, comme les produits scalaires, la multiplication de matrices, les calculs de racine carrée et les transformations de vecteurs. Les écarts de performances dans ces opérations peuvent avoir un effet important sur le temps d’image global. Les graphiques suivants montrent le coût relatif de sept opérations mathématiques courantes. Les mesures utilisent un vecteur de quatre valeurs à virgule flottante de 32 bits stockées dans un seul registre SSE de 128 bits. Une matrice est composée de quatre vecteurs, soit un total de seize valeurs à virgule flottante de 32 bits réparties sur quatre registres SSE de 128 bits. Ces opérations ont été choisies parce qu’elles sont couramment utilisées dans une image.
  • Produit scalaire : calculer le produit scalaire d’un vecteur.
  • Transformation de vecteur : transformer un vecteur en le multipliant par une matrice.
  • Addition de vecteurs : additionner deux vecteurs.
  • Produit vectoriel : calculer le produit vectoriel de deux vecteurs.
  • Sinus vectoriel : calculer une approximation du sinus de chaque élément d’un vecteur.
  • FMA vectoriel (multiplication-addition fusionnée) : multiplier deux vecteurs et ajouter un troisième.
  • Racine carrée inverse : calculer la racine carrée inverse de la longueur d’un vecteur.
Figure 1 : Temps nécessaire pour effectuer l’opération. Une valeur plus faible est préférable. Données de banc d'essai synthétique hétérogène Dans ce graphique, l’axe des y représente le temps nécessaire pour effectuer l’opération. Chaque barre représente la plage de temps de l’opération mesurée chez tous les IHV, soit le temps minimal et maximal lors de l’exécution du test sur un cœur performant ou sur un cœur efficace. Comme prévu, les performances diffèrent selon le type de cœur. Toutefois, le principal enseignement de ces données est que les performances n’évoluent pas de la même façon pour toutes les opérations et tous les IHV. Bien que la variabilité des résultats entre les IHV ait eu tendance à être semblable, certains présentaient une variabilité plus élevée. Les opérations à plus grande variabilité étaient surtout le sinus vectoriel et la racine carrée inverse. Cet écart s’explique par les choix d’architecture entre cœurs performants et cœurs efficaces. La cause exacte de cet écart peut provenir de plusieurs sources. Par exemple, les cœurs plus performants pourraient disposer de davantage de pipelines à virgule flottante, ce qui permet d’exécuter plus d’opérations en parallèle. La raison exacte est propre à chaque IHV et à chaque génération de processeurs. Il pourrait même exister une configuration où l’écart de performances n’existe pas pour certaines opérations. En fin de compte, un titre doit tenir compte de cette variabilité entre les IHV.

Conditions réelles

Les données précédentes présentent des bancs d’essai précis pris isolément et ne racontent qu’une partie de l’histoire. Les données suivantes proviennent de bancs d’essai d’un moteur de jeu AAA qui utilise deux threads principaux (Simulation et Rendu) avec un ensemble de threads de tâches. Le banc d’essai utilise trois configurations de test.
  • Les deux threads principaux s’exécutent uniquement sur les cœurs plus performants.
  • Les deux threads principaux s’exécutent uniquement sur les cœurs efficaces.
  • Les deux threads principaux s’exécutent sur tous les cœurs du système.
Dans chaque configuration de test, les threads de tâches peuvent se déplacer librement sur tous les cœurs du système. Le travail de rendu utilise la résolution et la qualité les plus basses possible. Ce réglage garantit que le titre est limité par le processeur pendant toute la durée du test. Il fait également du thread de simulation le facteur déterminant de la fréquence d’images. Ce graphique montre le temps passé dans chaque thread pendant une image. Il présente à la fois le temps d’image moyen et le 1 % le plus élevé. Le 1 % le plus élevé est le seuil des 1 % d’images les plus longues. Seulement 1 % de toutes les images dépassent cette valeur. Ce chiffre donne une bonne idée du nombre d’images saccadées. Plus il s’éloigne de la moyenne, plus les saccades du titre sont importantes. Dans tous les cas, des valeurs plus faibles indiquent moins d’images longues et moins de saccades visibles. Comme mentionné précédemment, les données présentées sont un regroupement de plusieurs IHV. Chaque IHV présente une mise à l’échelle différente pour chaque test, selon les choix qu’il a faits pour sa topologie. Bien que les chiffres exacts diffèrent, les tendances sont semblables d’un IHV à l’autre. Chaque génération de processeurs peut faire des compromis différents, ce qui modifie leurs chiffres relatifs. La production de données pour tous les IHV de processeurs et toutes les générations existants dépasse la portée de ce document. Figure 2 : Temps moyen et 1 % le plus élevé. Une valeur plus faible est préférable. Données de banc d'essai hétérogène en conditions réelles Dans ce graphique, l’axe des y représente le temps nécessaire pour une image. Chaque barre représente la plage de temps de l’opération mesurée chez tous les IHV, soit le temps minimal et maximal pour chaque topologie de threads testée. Le planificateur de threads du système d’exploitation utilise des heuristiques pour déterminer la quantité de travail effectuée par un thread. Ces heuristiques combinent des choix du système d’exploitation et des ajustements de pilote apportés par un IHV. Le planificateur utilise ces informations pour choisir les cœurs sur lesquels un thread donné doit s’exécuter. Lorsqu’il détermine qu’un thread effectue une grande quantité de travail, le planificateur déplace ce thread vers un cœur plus performant. En raison des heuristiques du planificateur, un comportement contre-intuitif peut se produire : le titre s’exécute plus rapidement lorsque les threads critiques peuvent se déplacer librement. Ce comportement ne se produit pas toujours et dépend de la charge de travail, de la topologie des cœurs et des heuristiques exactes du planificateur. Dans le cas testé ici, le thread de simulation passe plus de temps à s’exécuter à chaque image que le thread de rendu. Le planificateur préfère placer ce thread sur un cœur plus performant. Il décide également de placer le thread de rendu sur un cœur moins performant, puisque celui-ci passe plus de temps suspendu à attendre du travail. L’effet net est que cette décision libère un cœur plus performant pour l’un des threads de tâches. Si le thread de rendu effectuait plus de travail, cette situation pourrait ne pas se produire. Toutefois, l’enseignement le plus intéressant de ce graphique réside dans la valeur du 1 % le plus élevé. Même si la moyenne est la même lorsque les threads critiques se déplacent librement, le 1 % le plus élevé est pire que lorsque les threads critiques sont verrouillés sur les cœurs performants. Cela signifie que la fréquence d’images est plus saccadée lorsque les threads critiques se déplacent librement. La raison la plus courante est que les heuristiques du planificateur fonctionnent sur une fenêtre glissante. Il leur faut du temps pour réagir à un pic de travail nécessaire pour une image. Pendant ce temps, un thread critique pourrait s’exécuter sur un cœur moins performant.
Chaque fabricant peut ajuster ces heuristiques du planificateur pour les adapter à son matériel. Par exemple, AMD dispose de sa technologie Workload Profile Scheduling et Intel de sa technologie Thread Director. Chaque IHV a aussi tendance à ajuster les heuristiques pour qu’elles correspondent à la topologie précise du SoC.

Recommandations

Affinité des threads

Le conseil concernant l’affinité des threads sur un ordinateur de bureau doté d’une seule classe d’efficacité est d’éviter de définir des affinités de threads strictes et de laisser plutôt les threads se déplacer sur tous les cœurs. La principale raison de cette incertitude est qu’on ne sait pas à l’avance quels autres processus pourraient s’exécuter sur l’ordinateur d’un utilisateur. Un thread doté d’une affinité stricte peut finir par partager un cœur avec un autre thread de haute priorité du système. L’effet net est que le thread du titre manque de temps d’exécution. Si cette contention se produit sur un thread critique pour l’image, le titre peut subir des temps d’image irréguliers. Vous voulez vous assurer que le système d’exploitation dispose d’un endroit où déplacer les threads du titre pour qu’ils continuent de s’exécuter. Toutefois, ce conseil doit changer lors de l’exécution sur des processeurs hétérogènes. La principale raison est que le système d’exploitation ne sait pas nécessairement quels threads ou quelles tâches du titre sont critiques pour l’image. Il dispose de certaines heuristiques pour déterminer ce qu’il considère comme les threads critiques pour l’image, mais ces heuristiques peuvent tout de même faire de mauvais choix. Il pourrait décider de déplacer l’un de ces threads ou l’une de ces tâches vers un cœur moins performant, ce qui augmente la probabilité de problèmes de performances dans le titre. La recommandation est de permettre aux threads du titre de s’exécuter sur au moins trois à quatre cœurs, et davantage de préférence. Par exemple, sur un système d’entrée de gamme doté d’un cœur plus performant et de trois cœurs moins performants, vous devriez permettre aux threads de se déplacer sur tous les cœurs. Sur les ordinateurs dotés d’au moins trois cœurs performants, vous pourriez restreindre les threads critiques pour l’image à ces seuls cœurs plus performants. Sur les ordinateurs haut de gamme dotés de nombreux cœurs qui prennent aussi en charge le SMT, certains titres pourraient tenter de verrouiller leurs threads sur des cœurs physiques. Cette technique évite la contention au niveau du cœur physique, puisque plusieurs threads de haute priorité partagent les mêmes ressources d’un cœur physique. En général, il n’est toutefois pas recommandé d’envisager ce cas. Le système d’exploitation applique déjà ce comportement à l’échelle du système. Il planifie d’abord les threads sur les cœurs physiques et n’utilise des cœurs logiques supplémentaires qu’au besoin. Le seul cas qu’un titre devrait envisager est celui où le système compte suffisamment de cœurs plus performants pour prendre en charge les threads critiques du titre. Dans ce cas, il peut être souhaitable de verrouiller les threads critiques pour l’image sur les cœurs plus performants. Toutefois, ces threads devraient pouvoir se déplacer sur tous les cœurs plus performants. Bien que, dans certains cas, permettre à tous les threads de se déplacer sur tous les cœurs puisse améliorer les performances, ce comportement n’est pas constant chez tous les fabricants de processeurs. Si le titre met en œuvre un système de vol de travail (work stealing) capable d’équilibrer entièrement la charge de travail entre tous les threads, alors tout thread de tâches devrait pouvoir se déplacer sur tous les cœurs. Peu importe qu’il s’agisse de threads de tâches de haute ou de basse priorité. L’algorithme de vol de travail équilibre automatiquement la charge et permet d’accomplir le plus de travail possible dans le plus court délai. Les threads situés sur les cœurs plus performants exécutent davantage de tâches pendant l’image. S’il existe plusieurs threads critiques pour l’image, il peut être utile de définir leur affinité de façon à ce que deux threads critiques ne puissent jamais s’exécuter sur le même cœur. Par exemple, s’il y a deux threads critiques pour l’image, définir leurs affinités comme mutuellement exclusives (OU exclusif) élimine la possibilité que le système d’exploitation les mette en contention. Encore une fois, n’envisagez cette option que s’il y a suffisamment de cœurs pour prendre en charge ce cas tout en permettant à chaque thread critique pour l’image de se déplacer sur au moins trois à quatre cœurs.

Topologie des threads

Lorsque vous déterminez comment attribuer le travail aux threads dans un environnement hétérogène, les données principales concernent la durée des diverses tâches et la façon dont elles interagissent entre elles : quelle est la durée moyenne de chaque tâche, quelles sont les dépendances entre les tâches, quelles sont les priorités de chaque tâche, etc. Dans quelle mesure les threads de tâches peuvent-ils absorber des pics de temps sur les threads ou tâches critiques? Si l’un de ces threads ou l’une de ces tâches s’exécute 35 % plus lentement, quel est l’effet sur le temps d’image? Par exemple, si une tâche dure plus longtemps, dans quelle mesure ce retard affecte-t-il le reste de l’image, et le système se bloque-t-il jusqu’à ce que cette tâche soit terminée? Il peut être utile de déterminer dans quelle mesure un système hétérogène affecte le temps d’image en ajoutant une surcharge supplémentaire dans les threads ou tâches critiques. À titre de test, faites en sorte qu’une tâche ou un bloc de travail choisi au hasard prenne de 25 % à 35 % de temps supplémentaire. L’ampleur de la variation du temps d’image global indique dans quelle mesure le système de tâches peut absorber les pics d’exécution. La situation idéale est que les temps d’image ne changent presque pas. Cela signifie que le système peut absorber des pics arbitraires de temps d’image. Les pics proviennent soit de l’exécution sur un cœur moins performant, soit d’un autre processus aléatoire du système qui utilise du temps processeur.

Communication entre threads

Il faut réfléchir à la communication entre threads au moyen de primitives de verrouillage. La surcharge d’un changement de contexte est étroitement liée au C-State du cœur récepteur avant que le nouveau thread commence à s’exécuter. Le cœur doit être en C0, l’état d’exécution, avant que le nouveau thread puisse commencer à s’exécuter. Le cas le moins coûteux est celui où le cœur était déjà en cours d’exécution, donc déjà en C0. Toutefois, si le cœur est inactif, il se trouve dans un C-State inférieur. Le niveau du C-State correspond à des niveaux de veille plus profonds. Une veille plus profonde réduit la consommation d’énergie du cœur. En revanche, il est plus coûteux de se réveiller et de recommencer à s’exécuter à partir d’une veille plus profonde. Le C-State de faible consommation le plus courant est C1, qui peut ajouter une surcharge de 2 à 7 μs. Le C-State suivant, C2, peut ajouter une surcharge d’environ 40 à 100 μs. Le chiffre exact dépend de l’IHV et du SoC. De nombreuses variables déterminent le C-State dans lequel se trouve un cœur inactif; il s’agit d’un équilibre entre réactivité et consommation d’énergie. Un C-State inférieur consomme moins d’énergie qu’un C-State supérieur. Il est courant qu’un cœur entre d’abord en C1, puis passe en C2 s’il n’a pas exécuté de code depuis un certain temps. Une autre préoccupation se pose : que se passe-t-il lorsque le thread qui soumet la tâche et le thread qui l’exécute se trouvent sur des cœurs ayant des profils de performances différents? Techniquement, il est possible que le thread de tâches termine les tâches plus rapidement que les nouvelles tâches ne sont créées. Cette situation est plus susceptible de se produire si le thread qui exécute la tâche se trouve sur un cœur plus rapide que le thread qui soumet les tâches. Si une tâche prend moins de temps à s’exécuter qu’à être créée, le titre peut se retrouver dans une situation où un thread de tâches est constamment suspendu en attente de nouvelles tâches. L’effet net est que l’exécution des tâches devient plus coûteuse, puisque le thread de tâches est constamment suspendu. Le coût de la surcharge d’un changement de contexte s’ajoute au temps d’exécution de chaque tâche. Cette surcharge peut paradoxalement entraîner des fréquences d’images plus faibles lors de l’exécution sur des cœurs plus performants. Par exemple, un travail qui prenait 250 μs peut soudainement prendre 275 μs; cette régression représente une baisse de performances de 10 %. En raison de ce cas, la recommandation est de soumettre plutôt les tâches par lots au lieu de les soumettre au fur et à mesure de leur création. Par exemple, si le système suit un modèle où il construit une tâche, la soumet, construit une tâche, la soumet, etc., ce modèle devrait être modifié pour effectuer d’abord un lot de constructions, puis les soumettre toutes en même temps. Si le titre utilise un objet qui nécessite WaitForSingleObject, celui-ci devrait être placé dans une petite boucle d’attente active (spin). Appelez la fonction avec un délai d’expiration de 0, puis, une fois la boucle terminée, utilisez la valeur de délai d’expiration normale du titre. La meilleure solution à ce problème est toutefois d’utiliser des API de synchronisation modernes comme les verrous SRW (Slim Reader/Writer), les sections critiques et WaitOnAddress. Ces API de synchronisation comprennent toutes une forme d’attente active interne, ce qui peut empêcher un thread d’être constamment suspendu. Cette attente active est particulièrement utile pour les verrous détenus pendant une courte période. Il est important d’éviter les longs verrous tournants (spin locks). C’est le cas, par exemple, d’un modèle où les threads tournent constamment en attendant du travail à effectuer. Si un autre travail doit être effectué sur le cœur, le planificateur finira par suspendre le thread en attente active pour effectuer ce travail. Lorsque cette préemption se produit, il est fort probable que le thread suspendu le reste pendant une période importante. Ce comportement vise à éviter la privation des autres threads. Comme le titre a peu de contrôle sur le moment de la suspension, cela peut entraîner des saccades dans la fréquence d’images.

Systèmes de tâches

Pour obtenir les meilleures performances, structurez le moteur autour de tâches plutôt que de compter sur des threads dédiés de longue durée critiques pour l’image. Par exemple, un modèle de threads Simulation/Rendu crée deux threads persistants critiques pour l’image. Toutefois, des tâches longues peuvent faire en sorte que n’importe quel thread de tâches se comporte comme un thread critique pour l’image. Si une tâche prend 10 ms, le thread qui l’exécute devient critique pour l’image pendant cette période, quel que soit son rôle d’origine.

Vol de travail

La recommandation principale est d’utiliser le vol de travail dans l’ensemble du système de tâches et de laisser tous les threads critiques pour l’image participer à l’algorithme de vol de travail. Par exemple, si le thread de rendu attend la fin de tâches liées au rendu, il devrait exécuter certaines de ces tâches. Ce comportement est déjà une pratique courante dans de nombreux moteurs de jeu. Toutefois, il vaut la peine de le mentionner ici, car ce type de comportement est essentiel pour que le moteur de jeu puisse absorber les pics d’images causés par les cœurs hétérogènes et une éventuelle préemption par le système d’exploitation. Lorsqu’une tâche prend plus de temps à s’exécuter, le risque de pic de temps d’image augmente. Ce comportement peut être causé soit par l’exécution de la tâche sur un cœur moins performant, soit par d’autres travaux sur le PC. La recommandation est que le moteur vise des tâches représentant environ deux pour cent de l’image. Ce budget signifie, par exemple, un maximum d’environ 333 μs pour un jeu fonctionnant à 60 images par seconde. Au besoin, plusieurs petites tâches devraient être regroupées en une tâche plus grande pour viser ces deux pour cent. Cette approche offre un bon compromis entre la taille des tâches, la communication entre threads et la capacité d’absorber les pics. Ces exemples montrent les effets que peuvent avoir de longues tâches critiques pour l’image sur les performances du système. Dans ces exemples, chaque tâche comprend le même nombre d’opérations. Dans cet exemple, une seule tâche prend 375 μs sur un cœur lent et 250 μs sur un cœur rapide. La tâche la plus longue (long pole) est six fois plus coûteuse que les autres tâches. Le pire scénario est celui où la tâche la plus longue se retrouve sur l’un des cœurs lents. Cela peut avoir un effet considérable sur les temps d’image. Dans ce scénario, le temps total d’exécution du travail est de 2 250 μs, soit six fois 375 μs. Figure 3 : Exemple de tâche la plus longue s’exécutant sur un cœur plus lent. Exemple de vol de travail hétérogène avec la tâche la plus longue sur un cœur plus lent La situation s’améliore lorsque la tâche la plus longue se retrouve sur un cœur plus rapide. Dans ce cas, le temps total est de 1 500 μs. Ce n’est toujours pas idéal, mais c’est mieux. Figure 4 : Exemple de tâche la plus longue s’exécutant sur un cœur plus rapide. Exemple de vol de travail hétérogène avec la tâche la plus longue sur un cœur plus rapide Le meilleur résultat consiste à éviter les tâches les plus longues en gardant des tailles de tâches petites et uniformément réparties. Dans cet exemple, le temps d’exécution total tombe à 1 125 μs, soit la moitié du temps de l’exemple précédent, pour la même quantité de travail accomplie. Figure 5 : Éviter les tâches les plus longues en utilisant des durées de tâches appropriées. Vol de travail hétérogène avec une durée de tâche appropriée Plus important encore, si le système d’exploitation tente d’interrompre l’exécution au milieu d’une tâche, le système équilibre automatiquement la charge de travail. Dans ce cas, le système d’exploitation a interrompu le titre avec une tâche de 375 μs sur un cœur rapide. Ce rééquilibrage n’a aucun effet sur le temps d’image global, qui reste à 1 125 μs. L’une des tâches a migré vers du temps libre sur un cœur lent. Figure 6 : Une interruption par le système d’exploitation avec rééquilibrage de la charge de travail maintient un temps d’image stable. Vol de travail hétérogène avec une durée de tâche appropriée et une interruption Ces exemples ne couvrent que le cas où la tâche la plus longue peut démarrer immédiatement; si elle ne peut démarrer que plus tard dans la file de tâches, la situation empire. Tout revient à la loi d’Amdahl, selon laquelle le temps d’exécution de tout système est lié à l’élément le plus long de ce système. Il est impossible pour le moteur d’absorber les pics qui augmentent le temps d’exécution de ces threads les plus longs. Ces pics peuvent provenir de l’exécution sur un cœur plus lent ou d’interruptions provenant d’autres processus de haute priorité du système.

Conclusion

En mettant en œuvre ces recommandations, vous pouvez vous assurer que le jeu offre des performances fiables et demeure résilient face aux différentes architectures de processeurs et aux interférences d’autres processus Windows.

Annexe

Déterminer la classe d’efficacité des cœurs

Utilisez la fonction GetLogicalProcessorInformationEx pour déterminer la classe d’efficacité de chaque processeur du système. Parcourez les données renvoyées par la fonction à la recherche d’un bloc RelationProcessorCore contenant la classe d’efficacité et le masque de cœur.

Épinglage des threads en fonction de la consommation d’énergie

Comme mentionné, l’épinglage de cœurs au moyen de l’affinité n’est pas recommandé dans l’environnement de bureau en raison des interférences possibles d’autres processus sur l’ordinateur. Toutefois, Windows offre des moyens permettant à un titre de donner des indications au système d’exploitation pour recommander l’endroit où le travail doit être exécuté. L’un de ces moyens passe par les API de gestion de l’alimentation.

Utilisation des ensembles de processeurs pour interroger la classe d’efficacité

L’utilisation des ensembles de processeurs (CPU Sets) est une autre méthode pour interroger la classe d’efficacité de chaque cœur du système.

Utilisation des ensembles de processeurs pour attribuer les threads à des classes d’efficacité

Les ensembles de processeurs (CPU Sets) peuvent aussi être utilisés au lieu de définir explicitement le masque d’affinité d’un thread. La recommandation est d’utiliser les ensembles de processeurs plutôt que des masques d’affinité explicites.
Dernière modification le 6 octobre 2026