1 points par GN⁺ 2024-12-02 | 1 commentaires | Partager sur WhatsApp
  • Dans le nouveau BIOS de l’ASRock B650 PG Lightning, le loop buffer de Zen 4 n’apparaît plus comme une source de micro-ops, et il est de nouveau actif lorsque l’on revient à l’ancien BIOS
  • Cette structure semble destinée à réduire la consommation en rejouant de petites boucles dans le front-end ; sa capacité est estimée à 144 entrées en mono-thread, et à 72 entrées par thread avec deux threads SMT
  • Dans SPEC CPU2017, l’écart de score global entre loop buffer activé et désactivé est inférieur à 1 %, ce qui laisse penser que l’impact sur les performances générales est très faible
  • Quand le loop buffer est désactivé, Zen 4 fournit davantage de micro-ops depuis l’op cache ; la bande passante de l’op cache étant largement suffisante par rapport au débit du back-end, cela a peu de chances de créer un goulot d’étranglement côté front-end
  • La raison de la désactivation et son impact réel sur la consommation restent incertains, mais comme il s’agit d’une fonction limitée qu’AMD n’a presque pas documentée ni mise en avant, la plupart des utilisateurs et développeurs auront du mal à percevoir le changement

Rôle et limites du loop buffer de Zen 4

  • Le loop buffer est une structure du front-end CPU qui conserve un petit nombre d’instructions déjà récupérées, afin de pouvoir désactiver certaines étapes du front-end lors de l’exécution répétée de petites boucles
    • Il peut contribuer à réduire la consommation
    • Il peut aussi améliorer les performances en contournant certaines limites du front-end en amont
    • C’est une technique utilisée depuis longtemps dans les cœurs Intel, Arm et AMD
  • Zen 4 semble être le seul cas parmi les cœurs AMD hautes performances à disposer d’un loop buffer
  • Le Processor Programming Reference de Zen 4 mentionne le loop buffer, aux côtés de l’op cache et des décodeurs, comme source de dispatch de micro-ops
  • D’après des expériences avec les compteurs de performance, sa capacité est estimée comme suit
    • 144 entrées en exécution mono-thread
    • Partitionnement statique à 72 entrées par thread lorsque deux threads SMT sont actifs
  • Si une boucle contient CALL/RET, le loop buffer de Zen 4 ne parvient pas à capturer cette boucle
  • Le guide d’optimisation Zen 4 d’AMD ne traite pas du loop buffer et se contente de conseiller de maintenir les régions de code chaudes dans la capacité de l’op cache

Le loop buffer disparu après une mise à jour du BIOS

  • Après la mise à jour d’une ASRock B650 PG Lightning vers le BIOS 3.10, le monitoring matériel des performances indique que le loop buffer ne dispatche plus de micro-ops
  • En revenant au BIOS 1.21, le loop buffer est de nouveau activé
  • La désactivation semble être intervenue entre AGESA 1.0.0.6 du BIOS 1.21 et AGESA 1.2.0.2a du BIOS 3.10
  • AMD a appliqué ce changement sans annonce ni communication particulière
  • D’après des discussions complémentaires avec des employés d’AMD à Hot Chips 2024, le loop buffer était principalement une fonction destinée à l’optimisation énergétique

Un faible écart de performances dans SPEC CPU2017

  • Le score global des suites entiers et flottants de SPEC CPU2017 ne diffère que de moins de 1 % selon que le loop buffer est activé ou désactivé
  • Le gain de performances en SMT n’est pas non plus affecté par la désactivation du loop buffer
  • Si l’impact sur les performances est faible, c’est parce que l’op cache de Zen 4 fournit déjà davantage de bande passante que ce que l’étape de rename/allocate du back-end peut consommer
  • Même lorsque le loop buffer est activé, les compteurs de performance indiquent que seule une petite fraction des micro-ops en provient
  • Aucun gros recul n’est observé dans les benchmarks individuels
    • 523.xalanbmk faisait traiter au loop buffer une minorité significative de l’instruction stream, mais le score reste dans la marge d’erreur : 9,48 avec le nouveau BIOS contre 9,44 avec l’ancien
    • 544.nab recevait près d’un quart de ses micro-ops du loop buffer, mais son score progresse à 11,7 avec le nouveau BIOS où le loop buffer est désactivé, contre 11,5 auparavant, soit +1,7 %
    • Cette hausse peut relever de la variance d’une exécution à l’autre
  • Dans les compteurs de performance du nouveau BIOS, l’op cache reprend la part du loop buffer et traite une plus grande proportion de l’instruction stream
  • Dans 507.cactuBSSN, la couverture de l’op cache diminue en partie et les décodeurs semblent fournir environ un quart de l’ensemble des micro-ops
    • Les compteurs de performance sont des outils qui montrent des tendances générales plutôt que des mesures exactes à 100 %
    • Le dispatch front-end est un événement spéculatif et peut donc être influencé par des instructions récupérées à tort après une branche mal prédite

Économies d’énergie possibles et activité du front-end

  • Le principal objectif du loop buffer n’est pas d’améliorer les performances, mais d’éteindre de manière opportuniste une grande partie du front-end, y compris l’op cache
  • Les fonctions de monitoring des performances de Zen 4 disposent d’un count mask permettant de compter les cycles pendant lesquels le nombre d’événements dépasse un seuil
    • En fixant le seuil à 1, on peut estimer le nombre de cycles pendant lesquels chaque source de micro-ops fournit effectivement des micro-ops
    • Cela permet d’évaluer à quelle fréquence le front-end pourrait être désactivé lorsque le loop buffer est actif
  • Dans SPEC CPU2017, la fréquence d’activation de chaque source correspond globalement bien à la proportion de micro-ops qu’elle transmet
  • Dans certaines charges de travail, les cycles où le front-end ne fournit rien sont également nombreux
    • 502.gcc et 520.omnetpp sont fortement contraints par la latence mémoire du back-end
    • Si le moteur d’exécution out-of-order ne parvient pas à maintenir suffisamment d’instructions en vol pour masquer la latence, le front-end ne peut plus envoyer davantage vers le back-end et se retrouve à l’arrêt
  • Dans la suite flottante, 544.nab et 508.namd utilisent le loop buffer pendant une part assez importante des cycles cœur
    • 508.namd est une charge de travail à IPC élevé, avec 3,64 IPC en moyenne, et demande donc un débit front-end important
    • Elle est favorable au loop buffer, ce qui offre des occasions d’éteindre l’op cache pour économiser de l’énergie
  • Quand le loop buffer est désactivé, l’op cache alimente le cœur pendant davantage de cycles
    • Dans 523.xalanbmk, sans loop buffer, l’op cache doit être actif pendant 12 % de cycles cœur supplémentaires
    • 548.exchange2 est une charge à IPC élevé, avec 4,31 IPC en moyenne, mais utilise très peu le loop buffer même lorsqu’il est activé, et l’op cache est actif pendant plus de 85 % des cycles cœur
    • Dans 508.namd, la part d’activation de l’op cache passe de 56,67 % lorsque le loop buffer est activé à 75,1 % lorsqu’il est désactivé
  • Un loop buffer de 144 entrées est trop petit pour contenir une grande partie de l’instruction stream
    • Il n’a de chances d’avoir un effet net que si un programme passe une part importante de son temps dans de petites boucles et n’est pas limité par le débit ou la latence du back-end

Observations dans Cyberpunk 2077

  • L’impact de la désactivation du loop buffer sur les performances en jeu a été vérifié avec le benchmark intégré de Cyberpunk 2077
  • Pour améliorer la cohérence, Core Performance Boost a été désactivé sur un Ryzen 9 7950X3D et tous les cœurs ont été limités à 4,2 GHz
    • Le bit 25 du registre Hardware Configuration MSR 0xC0010015 a été défini
    • La RX 6900 XT a été limitée à 2 GHz
    • Le benchmark a été exécuté en 1080p, preset medium, sans upscaling
  • Lorsque le jeu est épinglé au die VCache, la désactivation du loop buffer n’a presque aucun impact sur les performances
  • Lorsqu’il est épinglé au die non-VCache, une perte de performances de 5 % est observée avec la désactivation du loop buffer, mais la cause n’a pas été identifiée
    • Le benchmark a été relancé environ six fois
  • Dans Cyberpunk 2077, le loop buffer prend en charge en moyenne environ 22 % de l’instruction stream, ce qui le rend plus favorable au loop buffer que prévu
    • Après désactivation du loop buffer, la part des micro-ops fournies par l’op cache passe de 62 % à 82 %
  • Ce jeu n’est pas une charge de travail à IPC élevé : 0,89 IPC en moyenne avec le loop buffer désactivé, contre 1,02 IPC lorsqu’il est activé
    • La bande passante du front-end n’est pas un facteur majeur
    • Il est possible qu’il soit limité par le back-end ou par le délai du prédicteur de branchement
  • Lors de l’exécution sur le die VCache, les compteurs de performance affichent 1,25 IPC en moyenne avec le loop buffer activé, contre 1,07 IPC lorsqu’il est désactivé
    • Une légère baisse de performances est également observée avec le nouveau BIOS
    • À environ 155 FPS, la charge s’est peut-être rapprochée d’un goulot d’étranglement côté GPU

Incertitude des résultats des compteurs d’énergie cœur

  • Les compteurs d’énergie cœur de Zen 4 ont également été examinés afin de vérifier si l’exécution depuis le loop buffer améliore l’efficacité énergétique
  • Le benchmark de bande passante d’instructions a été modifié pour ne pas utiliser CALL/RET dans la section testée
    • En effet, Zen 4 n’utilise pas le loop buffer en présence de CALL/RET
  • Le test est épinglé à un cœur, et la puissance moyenne est calculée en lisant le Core Energy Status MSR avant et après le saut vers le tableau de test
  • Core Performance Boost a été désactivé, car les lectures de puissance fluctuaient fortement
  • Avec l’ancien BIOS, le Core Energy Status MSR indiquait 6 W en moyenne lors de la récupération de NOP depuis l’op cache, et une consommation bien plus faible depuis le loop buffer
  • Même en portant la taille du tableau de test à 128 KB, soit de quoi tenir dans le L2, afin d’abaisser la couverture de l’op cache sous 1 %, la puissance cœur moyenne indiquée était de 1,5 W
    • Ce résultat ne correspond pas à une situation où l’utilisation des décodeurs et du chemin de fetch L2 devrait augmenter
  • Avec le nouveau BIOS, le test depuis l’op cache indique 1,68 W en moyenne, et le test majoritairement alimenté par les décodeurs depuis le L2 affiche une puissance presque identique
  • Les fonctions de monitoring énergétique d’AMD peuvent relever d’une modélisation de puissance plutôt que d’une mesure réelle
    • La méthode de modélisation a peut-être changé entre les versions de BIOS, ou le modèle de puissance peut être inexact
    • Faute de matériel permettant une mesure directe, par exemple sur les connecteurs EPS 12 V, aucune vérification supplémentaire n’a été effectuée

Raisons de la désactivation et point de vue développeur

  • La raison pour laquelle AMD a désactivé le loop buffer de Zen 4 n’est pas connue
  • Des fonctions CPU sont parfois désactivées à cause de bugs matériels
    • Le LSD, loop buffer d’Intel Skylake, a été désactivé en raison d’un bug lié aux accès à des registres partiels dans de courtes boucles lorsque les deux threads SMT sont actifs
  • Zen 4 est la première tentative d’AMD d’intégrer un loop buffer à un CPU hautes performances, et valider une première implémentation est difficile
  • AMD a peut-être découvert en interne un bug non visible publiquement et désactivé le loop buffer à titre préventif
  • L’impact sur les performances devrait être nul ou très faible, car la bande passante de l’op cache est suffisante
  • L’impact sur la consommation est inconnu, mais il pourrait être faible et difficile à mesurer
  • AMD n’a presque pas documenté ni promu le loop buffer, hormis une ligne dans le Processor Programming Reference
    • Cela contraste avec Intel, qui documente souvent son loop buffer et recommande dans ses guides d’optimisation que les développeurs l’exploitent
  • Le loop buffer de Zen 4 est une fonction limitée, moins utile que l’op cache en raison de sa faible capacité et de la contrainte CALL/RET
  • Si l’on optimise consciemment pour le loop buffer de Zen 4 avec un ancien BIOS, les conditions suivantes peuvent être prises en compte
    • Maintenir les boucles sous 144 micro-ops
    • Si deux threads partagent un cœur physique, tenir compte d’une capacité environ divisée par deux
    • Pour les fonctions appelées dans de petites boucles, envisager l’inlining afin d’éviter CALL/RET
  • Même avec ces optimisations, il est très probable que le gain soit inexistant dans la plupart des cas

1 commentaires

 
GN⁺ 2024-12-02
Avis sur Hacker News
  • On peut supposer que cette fonctionnalité a été désactivée pour tenter de prévenir une vulnérabilité matérielle non divulguée

    • L’article avance globalement une hypothèse similaire : Zen 4 est la première tentative d’AMD d’intégrer un tampon de boucle dans un CPU hautes performances, et valider une première implémentation est toujours difficile.
      Il n’est pas déraisonnable d’imaginer qu’AMD ait découvert en interne un bug que personne n’avait encore rencontré, et ait désactivé le tampon de boucle par excès de prudence. À ce stade du cycle de vie du cœur, on voit mal quelle autre raison AMD aurait de toucher au frontend de Zen 4
    • En réalité, il se peut que davantage de choses aient été désactivées. Les chiffres sont assez surprenants : dans Cyberpunk 2077, lorsqu’il tourne sur le die VCache, les compteurs de performance indiquent un IPC moyen de 1,25 avec le tampon de boucle activé, contre 1,07 lorsqu’il est désactivé, et pourtant le nouveau BIOS entraîne une légère baisse de performances.
      Personnellement, ça sent la mesure d’atténuation par microcode, mais il faut évidemment attendre un CVE
    • Le désactiver discrètement est aussi un gros risque. Cela signale qu’ils connaissaient la gravité du problème et l’ont jugé assez sérieux pour le corriger.
      Si la vulnérabilité n’est pas divulguée, les parties touchées n’ont aucun moyen de commencer à réagir, sauf par pure paranoïa. La divulgation d’une vulnérabilité est aussi une façon de transférer la responsabilité vers l’utilisateur final : si vous n’avez pas fait la mise à jour, ne venez pas vous plaindre. Il est rare qu’une divulgation débouche sur une responsabilité produit, et je ne me souviens pas que cette question se soit posée avec Meltdown ou Spectre. Donc je n’affirmerais pas qu’AMD cache délibérément quelque chose
    • Ça semble être la bonne réponse, mais je ne peux pas en dire plus :(
  • L’article semble suggérer que le tampon de boucle n’apporte ni gain de performances ni gain énergétique.
    Dans ce cas, ce pourrait être le grand classique de « une équipe d’ingénieurs a passé des mois à créer une nouvelle fonctionnalité brillante qui n’apporte finalement rien, mais quelqu’un l’a quand même lancée pour sauver la face ». J’ai déjà vu des équipes logiciel vouloir réécrire une base de code pour supprimer de la lourdeur legacy et améliorer les performances, pour finir avec plus de lignes de code et de moins bonnes performances. Dans les deux cas, il n’aurait pas fallu sortir ça

    • La raison pour laquelle ils l’ont quand même sorti est que cela pouvait être désactivé par une mise à jour du firmware, et qu’un gros changement de placement physique du matériel en plein milieu de la conception aurait probablement eu des effets encore pires
    • S’ils ont réalisé, une fois la fonctionnalité déjà intégrée au cœur, qu’elle n’aidait pas vraiment, la retirer aurait été un risque évident
    • L’article dit aussi qu’il était difficile de mesurer la consommation électrique de manière globale ; on ne peut donc pas conclure que cette fonctionnalité n’a aucun effet, et il ne faudrait d’ailleurs pas le faire.
      Il est difficile de croire que l’équipe d’ingénierie d’AMD soit assez peu rigoureuse pour laisser une fonctionnalité matérielle sans aucune valeur consommer de la surface et de l’énergie ; ici, j’aurais plutôt tendance à penser que Chips 'n Cheese n’a pas réussi à en mesurer l’impact
    • Je travaille dans une entreprise hardware assez connue, et côté logiciel, on est obsédé par le fait de faire quelque chose, même quand les bénéfices ne sont pas suffisamment démontrés, sauf pour quelques cas d’usage étroits ou des benchmarks ciblés.
      C’est très frustrant, mais personne ne veut prendre le temps de faire l’étude préalable. Pousser un nouveau projet satisfait davantage la hiérarchie et attire moins de questions
    • Il existe aussi une autre possibilité : les benchmarks de consommation sont exacts. Le tampon économisait de l’énergie, mais une meilleure optimisation a ensuite été trouvée au niveau du microcode pour rendre le chemin général plus économe, au point que le tampon est devenu un consommateur net d’énergie
  • Le paragraphe le plus intéressant de l’article est celui-ci : la meilleure façon de voir le tampon de boucle de Zen 4, c’est comme le signe qu’AMD dispose d’une marge de capacité permettant à ses ingénieurs d’essayer des choses.
    Cette fois, cela n’a peut-être pas donné de résultat, mais laisser des ingénieurs expérimenter sur des fonctionnalités à faible risque et faible impact est une bonne façon de bâtir de la confiance. J’espère que l’on verra davantage de cette confiance à l’avenir

  • Le passage disant qu’« étrangement, lorsqu’on force l’exécution sur le die non-VCache, désactiver le tampon de boucle fait chuter les performances en jeu de 5 %. Je ne sais pas pourquoi » me fait penser qu’avec des mesures d’énergie plus fines, on pourrait déterminer si c’est lié au budget thermique/énergétique.
    Cette fonctionnalité semble aussi avoir été pensée pour économiser de l’énergie

    • Ici, il n’y a pas assez de détails. Sur les puces Ryzen, le deuxième CCD est de qualité de binning inférieure au premier même sur les puces non-X3D, et cela varie d’une puce à l’autre.
      Sur ma puce non-X3D, la plupart des cœurs du CCD0 montent à 5,6–5,75 GHz, tandis que ceux du CCD1 plafonnent à 5,4–5,5 GHz. Les puces V-Cache Zen 4 subissent une forte pénalité de fréquence, mais le cache compense largement. Il faudrait savoir s’ils ont testé, sur le CCD1 de la même puce, la fonctionnalité activée puis désactivée, et s’ils ont essayé d’isoler d’autres changements comme des correctifs de sécurité ; l’article reconnaît lui-même que « non ». Pour le faire correctement, il faudrait trouver un moyen de désactiver uniquement cette fonctionnalité dans un BIOS où elle est activée, puis tester les deux configurations sur la même puce ; même là, d’autres conditions de branchement pourraient rendre les résultats imprécis. Un profil de performances complet améliorerait la précision, mais seuls des ingénieurs AMD peuvent probablement le faire
    • Il est indiqué que la désactivation s’est produite quelque part entre les deux versions UEFI testées. Elles incluaient sans doute d’autres changements, donc la mesure n’est pas un véritable test A/B rigoureux
  • Cela semble avoir été trop petit pour faire une vraie différence, et utile seulement dans des situations très spécifiques. En le rendant plus important, le coût d’implémentation aurait sans doute été trop élevé par rapport au bénéfice.
    Cela dit, il y aura quand même de légères régressions sur certaines charges de travail, mais AMD a aussi apporté de petites améliorations de performances après la sortie. Sur Zen 4, ils auraient simplement dû en faire une option BIOS. Le fait qu’ils ne semblent pas l’avoir fait suggère la possibilité d’un bug ou d’un problème de sécurité

    • Désactiver discrètement une fonctionnalité que la plupart des utilisateurs ne remarqueront pas, mais qui complexifie le frontend, donne l’impression qu’ils ont déclenché ce chicken bit pour éviter ou retarder la divulgation d’un bug matériel tout en déployant déjà la mesure d’atténuation. Foutus fournisseurs, quand apprendront-ils ?
  • À titre anecdotique, l’une des rares différences entre le 68000 de 1979 et le 68010 de 1982 était le « loop mode », c’est-à-dire l’ajout d’un tampon de boucle de 6 octets.

    • Le point bien plus important était la correction de la prise en charge de la MMU. À l’origine, le 68000 perdait une partie de l’état nécessaire pour reprendre après un défaut de page, et la solution de contournement était laide et coûteuse.
      Elle consistait à faire tourner deux CPU avec un cycle de décalage et à injecter une interruption récupérable dans le second CPU. Mais si l’on voulait un CPU avec MMU, un jeu d’instructions 32 bits et un bus d’adresses 24 bits, cela semblait tout de même moins cher que les alternatives de l’époque. Quelle période rude cela devait être.
    • Intéressant. Parmi les petits tampons de boucle, j’aime assez les cœurs Forth de GreenArrays.
      Un mot de 18 bits contient 4 instructions, et l’un des opcodes décrémente le compteur de boucle puis revient au début du mot. Dans ce cas, l’exécution peut être nettement plus rapide.
    • Le tampon de boucle du 68010 était presque inutile. Non seulement il ne faisait que 6 octets, mais il ne pouvait aussi contenir que deux instructions.
      L’une d’elles devait être l’instruction de boucle (DBcc), donc le corps de la boucle devait être une seule instruction. En pratique, à peu près la seule chose qui pouvait réellement accélérer était un memcpy non optimisé.
  • Il est intéressant de voir que, sur le Cortex-A15, c’est une fonction de conception clé. Je me demande s’il existe des chiffres sur son efficacité dans d’autres puces.
    Dans des appareils à durée de vie de conception plus longue, comme les consoles, cela pourrait au moins servir de cible d’optimisation.

    • Moi aussi, je suis curieux. Je m’attendrais à ce que, pour n’importe quelle architecture RISC, les gains tirés d’un tampon de boucle soient relativement faibles.
      Après tout, l’idée du RISC est de rendre la récupération et le décodage des instructions beaucoup plus faciles, voire presque triviaux.
  • J’ai un 7950X3D, après être passé d’un Skylake 6700K. Apparemment, je suis inconsciemment attiré par les puces dont le tampon de boucle matériel est désactivé par logiciel.

    • Si un jour tu comptes acheter une nouvelle machine, préviens-nous à l’avance. Qu’on puisse l’éviter !
  • Article intéressant, mais je ne sais pas combien de place le tampon de boucle occupe sur le die.
    Je me demande si, en le supprimant dans de futures puces, cet espace pourrait être utilisé pour quelque chose de plus utile, comme un cache L2 plus grand.

    • À mon avis, la plupart des puces modernes sont davantage limitées par les contraintes de routage que par la surface au sol. On peut concevoir énormément de fonctionnalités, mais leur fournir à toutes l’alimentation et des signaux normalisés est un vrai calvaire.
    • D’après ce que je comprends, c’est une optimisation assez petite dans le frontend. Il n’y a pas beaucoup d’entrées au départ, 144 seulement, donc l’espace économisé serait probablement négligeable.
      En théorie, un tampon de boucle peut économiser de l’énergie ou améliorer les performances dans des boucles serrées. En pratique, il semble ne faire ni l’un ni l’autre, et AMD l’a complètement supprimé dans Zen 5.
    • D’après le schéma, le tampon de boucle semble utiliser le même stockage que la file de micro-opérations qui existe de toute façon.
      Si c’est exact, c’est plausible, et le coût en surface se limite à peu près à de la logique de contrôle supplémentaire. La partie la plus coûteuse est probablement la détection même des boucles, mais cela doit rester assez petit par rapport à la taille de la file.
    • Il est question de 144 entrées de micro-opérations par cœur. Je ne sais pas combien d’octets cela représente, mais les caches L2 actuels font environ 1 Mo par cœur ; donc même en supposant que la surface du tampon de boucle soit surtout du stockage, cela ne ferait pas de différence notable.
  • L’analyse de la section « énergie » semble ne pas être divisée par le nombre d’instructions exécutées par seconde.
    Pour voir l’intérêt de ce tampon de boucle, il faut presque certainement regarder l’énergie par instruction, et non l’énergie par seconde, c’est-à-dire la puissance (en watts).

    • Chaque instruction prend un nombre de cycles d’horloge différent, et cela varie aussi entre générations d’architectures, comme de Zen 4 à Zen 5. Ce n’est donc pas vraiment faisable, sauf si la charge de travail produit exactement le même nombre d’instructions par cycle, ce qui est impossible à cause du multithreading et du traitement des tâches.
      Même l’ordre et le contenu de la RAM peuvent tout changer. On peut exécuter des centaines de fois avec et sans l’option pour isoler le phénomène dans une certaine mesure, mais cela prend énormément de temps et ne sera quand même pas exact à 100 %. Le simple fait de désactiver une fonctionnalité peut faire emprunter au code une autre branche, ce qui change toute la disposition. Je ne connais pas ce problème précisément, mais j’ai déjà vu des cas où la désactivation d’une fonctionnalité déplaçait la charge des unités entières vers le FPU ou le GPU, ou supprimait 5 instructions tout en en ajoutant 2.