2017-08-30 2 views
3

Quel gain de performances, le cas échéant, peut-on obtenir en réorganisant les instructions x64 (x86-64) sur les processeurs Intel haut de gamme récents? Cela vaut-il la peine de se soucier de situations extrêmement critiques en termes de temps? Je m'interrogeais également sur la possibilité de réaliser des gains en changeant l'utilisation du registre/en utilisant des registres supplémentaires (si gratuits) afin de permettre le mouvement du code sur de plus longues distances dans certains cas bizarres?Réorganisation des instructions dans x86/x64 asm - optimisation des performances avec les processeurs les plus récents

+3

Voulez-vous dire réorganisation manuelle des instructions dans le code? Beaucoup! Considérez que vous pouvez masquer la latence entière d'une instruction longue (si vous avez suffisamment de chemins de données indépendants) en la réorganisant. Vous pouvez éviter la pression du port, faire quelques macros-instructions, éviter les décrochages (il y en a beaucoup, y compris avoir plusieurs instructions qui se retirent dans la même unité en même temps) et ainsi de suite. L'utilisation de registres supplémentaires est utile si elle évite de déplacer des données de/vers la mémoire, sinon le CPU renommera les registres lui-même (par exemple 'eax' n'est plus le même' eax 'plus tard) –

+0

Merci Margaret. La seule raison pour laquelle j'ai demandé était parce que je n'étais pas sûr de la quantité de mouvement que les derniers processeurs peuvent générer eux-mêmes en interne. –

Répondre

6

La programmation d'instructions n'est généralement pas très importante sur de courtes distances, car l'exécution hors service est généralement efficace. Il est beaucoup plus important sur les processeurs en ordre comme certains noyaux ARM, où la programmation se charge bien avant les instructions qui utilisent le résultat. Il peut cependant être utile même sur le x86 haut de gamme, selon le type de goulot d'étranglement qui limite le débit d'exécution. Voir http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ pour quelques trucs intéressants sur la taille de l'ORD par rapport au nombre de registres physiques étant un facteur limitant dans l'exécution hors d'ordre. Software-pipelining pourrait aider avec de longues chaînes de dépendances que l'exécution hors de l'ordre a du mal à se cacher.

La mise en place précoce d'instructions sur la chaîne de dépendances du chemin critique peut être utile, car la planification OOO tente généralement d'exécuter la plus ancienne en priorité. (Voir How are x86 uops scheduled, exactly?).

Les processeurs modernes sont des bêtes complexes, et parfois les réorganisations peuvent faire la différence quand vous ne vous attendez pas à ce que cela compte. Parfois, il n'y a aucun moyen de deviner exactement pourquoi cela a fait une différence. Des ordres différents peuvent affecter la bande passante frontale dans les décodeurs ou même dans le cache uop, car il existe de nombreuses règles sur la façon dont les uops décodés sont regroupés dans des lignes up-to-6op dans le cache uop (sur les processeurs Intel). Par exemple, Branch alignment for loops involving micro-coded instructions on Intel SnB-family CPUs

Parfois l'explication est très obscure. Par exemple, dans le manuel d'optimisation d'Intel, Example 3-25. Re-ordering Sequence to Improve Effectiveness of Zero-Latency MOV Instructions, ils discutent immédiatement de l'écrasement du résultat zero-latency-movzx pour libérer la ressource interne plus tôt. (J'ai essayé les exemples sur Haswell et Skylake, et j'ai constaté que la mov-elimination fonctionnait en fait beaucoup plus souvent, mais qu'elle était en fait légèrement plus lente dans les cycles totaux, plutôt que plus rapide. l'avantage sur IvyBridge, qui gêne probablement sur ses 3 ports ALU, mais HSW/SKL seulement goulot d'étranglement sur les conflits de ressources dans les chaînes dep et ne semble pas déranger en ayant besoin d'un port ALU pour plus d'instructions movzx.)

Probablement ceci s'applique également à eliminated mov instructions, pas seulement à movzx, mais ce n'est peut-être pas le cas. IDK si je l'aurais compris si je me trouvais dans une situation d'optimisation réelle (pour IvyBridge) si le manuel d'Intel ne l'avait pas utilisé comme exemple. Les compteurs de performance pour uops émis vs exécutés (domaine fusionné vs domaine non fusionné) montrent combien de mouvements sont éliminés, mais il serait presque impossible de comprendre pourquoi cela se produirait sans un manuel d'optimisation expliquant pourquoi. Réorganiser les instructions indépendantes à proximité juste pour essayer des choses peut aider comme une dernière étape dans le réglage, mais à ce moment-là, c'est du vaudou/magie noire/deviner. Comme le souligne Margaret, il existe des raisons de réorganiser les instructions autres que la simple planification. Voir Agner Fog's optimization and microarchitecture guides et d'autres ressources dans le wiki tag pour en savoir plus. Par exemple, grouper cmp/jcc et test/jcc ensemble est toujours une bonne idée à cause de la macro-fusion.Votre compilateur le fera pour vous lorsque vous compilerez avec -march=haswell ou quelque chose, parce que cela permet -mtune=haswell.

Il peut également ouvrir d'autres opportunités d'optimisation s'il vous permet d'éviter certaines instructions mov ou de renverser/recharger, mais cela va au-delà des simples instructions de planification.

+0

Quelle réponse superbement généreuse, merci pour ces nombreux liens - vous êtes une star! –