COMPTOIR
register

Zen 2 et Ice Lake embarquent une optimisation novatrice : le "renommage mémoire"

Un processeur, vous n’êtes sans le savoir, c’est compliqué. Caser plus de 1,75 milliard de transistors (pour un i7 Skylake quadcore), même amputés de la partie graphique, des contrôleurs USB/PCIe/RAM et du cache et lier tous ces bousins entre eux est source de nombreux choix et compromis. Néanmoins, et depuis une bonne dizaine d’années, les fabricants patinent de plus en plus pour trouver des solutions d’amélioration des performances de nos chers engins.

 

En effet, après avoir multiplié les cœurs, difficile de grignoter sans exploser le coût de production. Cependant, une analyse poussée du fonctionnement interne des derniers processeurs, à savoir Zen 2 chez les rouges et Ice Lake chez les bleus, a révélé la présence d’un nouveau mécanisme interne que l’on peut nommer Memory File. Qu’est-ce que cette sorcellerie ? Pour le comprendre, revenons à un peu plus haut niveau : pour accéder à des valeurs situées en mémoire, un CPU doit d’abord les stocker dans des registres avant d’effectuer ses opérations. Or, depuis le début des CPU x86 modernes (c’est-à-dire les premiers Pentium), ces registres ne sont plus des emplacements physiques distincts dans le processeur, mais sont tous sauvegardés dans un Register File, ce qui permet notamment d’implémenter en interne bien plus de registres que ce que le jeu d’instructions expose. Pourquoi cela ? Dans certains cas d’usage, le CPU peut ainsi augmenter le parallélisme — et donc l’IPC — lorsque différentes opérations utilisant les mêmes registres s’avèrent être tout de même exécutables en parallèle, typiquement lorsqu’un registre est réinitialisé pour une nouvelle utilisation, séparée de la précédente.

 

nehalem cache hierarchie

Comme si ça n’était pas déjà assez complexe ! (crédits : die de Nehalem, par Chip Architect)

 

Or, dans Zen2 et Ice Lake, les architectes ont également implémenté ce mécanisme pour la mémoire : si jamais vous stockez quelque chose à une adresse, la valeur semble en fait stockée d’abord dans un registre, afin d’être à nouveau accessible en un cycle sur un chargement futur. Bien entendu, si d’autres opérations de stockage sont effectuées entre temps, la valeur se retrouvera en cache, voire en RAM... par contre, lorsque seul du calcul se déroule, le Memory File reste inchangé. Cela semble toujours obscur ? Dans des manipulations complexes de passage de valeur par la pile (typiquement, des appels de fonction), l’opération peut diminuer le nombre de cycles d’un chargement-rangement de plus d’un facteur 4 ! Auparavant, les designs implémentaient bien déjà une Load Queue et une Store Queue, c’est à dire des buffers retenant les dernières opérations effectuées avant de les renvoyer en mémoire, ainsi que des ponts entre ces emplacements, mais les échanges restaient relativement coûteux. De plus, cet ancien mécanisme censé raccourcir les temps entre chargement et rangement pouvait avoir des effets contre-productifs sur les performances, du fait d’une latence d’accès à cette queue non nulle (de l’ordre de 4 cycles). Avec le Memory File, l’accès est gratuit, puisque directement accessible par le CPU : miracle ? Notez par contre que ces mémoires tampons ont été sujettes à certaines failles type Meltdown ; nous espérons donc très fortement que cet aspect ait bien été pris en compte lors de l’implémentation de cette heuristique. En outre, les adresses accédées sont également sujettes à spéculation, et la pénalité peut être grave : en cas de mauvaise spéculation, le processeur se bloquera pendant une durée de l’ordre de 40 cycles pour tout remettre en ordre! Enfin, il est fortement possible que ce Memory File partage en interne l’espace de stockage du Register File, celui-là même dont nous vous parlions un paragraphe plus haut.

 

Le plus amusant dans cette histoire reste le manque de communication des firmes à propos de cette avancée. Certes, le mécanisme ne fonctionne clairement pas dans 100 % des cas applicables (il faut que l’adresse source soit elle-même dans un registre, par exemple), mais la chose a un potentiel certain, surtout dans le cas d’ancien code produit par des compilateurs encore faiblement optimisant. Une bonne surprise, donc ? (Source : Agner Fog, dont la page d’accueil vaut le détour)

Un poil avant ?

Et voilà les RTX 3070 de GIGABYTE

Un peu plus tard ...

La RTX 3090 se déchaine (un petit peu) sur Ashes of the Singularity

Les 14 ragots
Les ragots sont actuellement
ouverts à tous, c'est open bar !
par Un ragoteur blond embusqué, le Mercredi 23 Septembre 2020 à 12h14  
par Nicolas D. le Mercredi 23 Septembre 2020 à 11h27
J'ai réparé les quotes cassées avec ma clef qui répare les quotes cassées .
Merci je me suis emmêler les pinceaux plusieurs fois d'affilées
 
Effectivement, il ne semble matcher que l'adressing mode... ca doit permettre d'éviter de calculer l'adresse directement, et donc minimiser au maximum la taille des clefs possibles pour le "Memory File".

Je pense oui, mais ne pas calculer l'adresse permet aussi de se passer de gerer toutes les operations possible qui peuvent modifier l'adresse dans le registre (à peu près toutes les instructions en faites).

En fouillant dans l'historique de wikichip sur la page Zen 2, j'ai pu retrouver la ref du brevet d'où vient le nom "MEMFILE" (1). Dans ce brevet c'est le même mecanisme que le brevet que j'ai link plus tôt ("Store-to-load forwarding" ), mais avec plus de detail sur l'implem.

Le "MEMFILE" y est decrit ramidement et il contient bien des metadatas sur l'adresse de la mémoire qui est "rename".
Et le brevet parle lui aussi de stocker les valeurs dans les registres physiques.

C'etait un peu flou ce qui est decrit dans wikichip, le brevet et "un peu" plus claire à ce sujet ( du moins autant que peut l'être un brevet ). Dans wikichip, l'explication melange un peu le Sideband Stack Optimizer (SSO) et le MEMFILE. Mais le SSO semble bien etre un autre composant, qui communique juste avec le MEMFILE.

(1) : https://patents.google.com/patent/US10331357B2/en
par Nicolas D., le Mercredi 23 Septembre 2020 à 11h27  
par Un ragoteur blond embusqué le Mercredi 23 Septembre 2020 à 09h58
Désolé les quote du messages precedant sont un peu cassé..
J'ai réparé les quotes cassées avec ma clef qui répare les quotes cassées . Effectivement, il ne semble matcher que l'adressing mode... ca doit permettre d'éviter de calculer l'adresse directement, et donc minimiser au maximum la taille des clefs possibles pour le "Memory File".
par Un ragoteur blond embusqué, le Mercredi 23 Septembre 2020 à 09h58  
Désolé les quote du messages precedant sont un peu cassé..

Mais j'en profite pour ajouter un autre de Agner de son microarchitecture manuel à la page 221 (1)
 
The memory operand must be specified in exactly the same way with the same unmodified pointer and index registers in all the instructions involved. For example, [rax+rbx]and [rbx+rax]are not recognized as the sameaddress.


Ce qui semble confirmer mon hypothèse selon laquelle il ne match que l'addressing mode des operandes. Et donc que l'exemple suivant presenterait un problème d'aliasing:
mov dword [rsi + 4], eax
add dword rsi, 4
mov ebx, dword [rsi]

(le cpu ne devrait pas etre capable de remarquer qu'il peut forward la valeur de eax directement vers ebx)

Evidement quand je parlais d'un fonctionnement "assez simple" cela ne sous entendait pas que l'implementation est simple . Et j'ai bien mis des guillemets

(1) : https://www.agner.org/optimize/microarchitecture.pdf#page=221
par Un ragoteur blond embusqué, le Mercredi 23 Septembre 2020 à 09h34  
par Nicolas D. le Mercredi 23 Septembre 2020 à 09h09
Par contre, il peut y avoir un offset, donc [rdi + 4] est aussi dans le Memory File ; et c'est là ou ça devient super intéressant pour les passage d'argument de fonction qui sont ne général en [rsp + truc] . Vu que Agner parle de
Yet, this is a pretty amazing feature. Imagine how complicated it is to implement this in hardware without adding any latency.
Pour le "[rdi + 4]" je suppose qu'il match de la même manière là où tu utilises "[rdi + 4]". Parce que "[rdi + 4]" c'est juste un adressing mode que tu peux match comme les autres.
Mais si l'on utilise [rdi + 4], puis que l'on ajoute 4 à rdi, puis finalement que l'on utilise [rdi] je pense que le CPU n'est pas capable de tracker que cela correspond à la même adresse. Il faudrait des benchs pour cela, mais je n'ai ni Zen2 ni Ice Lake sous la main.

Là ou cela devient complexe c'est que pour la stack (tout ce qui utilise rsp, les push/pop, call/ret) il y a d'autres optimisations. Chez AMD depuis K10 il y a un Sideband Stack Optimizer (SSO) (1). Il permet de tracker la valeur de rsp lorsque l'on fait des pop/push call/ret et donc de calculer plus rapidement les adressing mode de la forme [rsp + truc].

Il y a fort à parier que la sortie du SSO est utilisé conjointement avec le store-to-load forwarding qui utilise la PRF dans la brevet que j'ai link plus tôt.

Agner precise bien:
 
This does not work if the stack pointer is modified by any other instructions

Ce qui sous entend que le SSO est impliqué. Mais c'est specifique à rsp (et ce qui est de la forme [rsp + truc]).

(1) : https://patents.google.com/patent/US7685406B2/en
par Un Linuxien pas inquiet embusqué, le Mercredi 23 Septembre 2020 à 09h16  
par Une ragoteuse à forte poitrine en Auvergne-Rhône-Alpes le Mercredi 23 Septembre 2020 à 06h49
Il ne faut pas non plus flipper pour rien. Il faut être un peu rationnel et réflechir à ce qui peut-être volé.
+1
Pour commencer, les utilisateurs comme vous et moi n'ont aucun besoin de s'en soucier, à condition de bien mettre à jour les logiciels qui sont vulnérables à ces types d'attaque; j'ai nommé les navigateurs web (et plus exactement leur moteur JavaScript) et leurs plugins (Flash & Co), les lecteurs PDF (JavaScript, là encore) les suites bureautiques (via leurs "BASIC" intégré ).

L'utilisateur "lambda" (qui ne partage pas son ordinateur via des comptes externes) n'a rien à craindre de ces attaques, mais beaucoup à faire pour se protéger des virus et vers classiques (bien plus efficaces et faciles à implémenter/injecter).

Pour ma part j'ai "mitigations=off" dans la ligne d'amorçage de mes PC sous Linux. Inutile de ralentir pour rien !

Ensuite, pour les applications professionnelles (fermes de VM, serveurs web ou de "cloud", etc), en plus des mitigations (pas toujours 100% efficaces), il est possible de rendre tout ou partie de ces attaques ineffectives en dédiant des coeurs de CPU aux logiciels vulnérables (e.g. un coeur avec SMT désactivé pour l'hyperviseur de la VM plus un coeur (SMT) par VM, quelques coeurs pour le serveur web, etc). Sous Linux, c'est déjà possible (isolcpus dans la ligne d'amorçage du noyau + taskset au lancement des logiciels).
par Nicolas D., le Mercredi 23 Septembre 2020 à 09h09  
par Une ragoteuse à forte poitrine en Auvergne-Rhône-Alpes le Mardi 22 Septembre 2020 à 22h59
Dans cette exemple de Agner le processeur peut voir que l'adressing mode [rsi] est utilisé à différent endroit, il n'est donc pas absurde d'assigner un registre physique qu'on pourrait nommer "[rsi]" (si il devait avoir un nom), tout en enregistrant comme metadata que l'on doit store la valeur de ce registre. Ce qui explique pourquoi si l'on remplace un [rsi] par [rdi] sur une instruction par exemple, alors le processeur ne peut pas le optimiser puisque l'addressing mode est différent, il y a un problème d' "aliasing".

J'ai pu trouver un brevet daté de 2014 de AMD (1) qui décrit un "Store-to-load forwarding" qui n'utilise pas le store buffer, mais bien les registres physiques comme décrit ici.
Je suis plutôt confiant en affirmant que ce brevet protège l'optimisation dont on est entrain de parler.

Chez Intel ils ont aussi des brevets qui parle de cela (2)(3).
Hou hou, merci pour les brevets ! Par contre, il peut y avoir un offset, donc [rdi + 4] est aussi dans le Memory File ; et c'est là ou ça devient super intéressant pour les passage d'argument de fonction qui sont ne général en [rsp + truc] . Vu que Agner parle de
[quote]
Yet, this is a pretty amazing feature. Imagine how complicated it is to implement this in hardware without adding any latency.
[quote]
Je suis moyennement confiant sur le "assez simple" ; mais je rejoins que ce n'est conceptuellement pas une révolution .
par Une ragoteuse à forte poitrine en Auvergne-Rhône-Alpes, le Mercredi 23 Septembre 2020 à 06h49  
par Jemporte le Mercredi 23 Septembre 2020 à 00h42
Plein de passoires liées aux optimisations de branchement ont été difficilement bouchées et là on nous révèle un nouveau boulevard pour des failles encore plus monstrueuses.
Il ne faut pas non plus flipper pour rien. Il faut être un peu rationnel et réflechir à ce qui peut-être volé.

Avec Meltdown on pouvait littéralement lire la mémoire du kernel à une adresse contrôlé, avec les MDS on pouvait écouter des load/store en vole qui sont dans les load/store buffer avec un peu de contrôle sur l'adresse.
Ici tout ce qu'on peut faire c'est récupérer une valeur qu'on vient de store nous même. Et on a 0 contrôle sur l'adresse de ce qu'on écoute. C'est plutôt limitant.
Il reste à savoir si l'on peut récupérer, en SMT, les stores du thread avec qui on partage le core physique. Ou alors si l'on peut récupérer des stores d'un processus qui a tourné juste avant nous.

Pour le premier cas: Je pense que non. Il suffit de tagger avec une id du thread.

Pour le deuxième cas: Si l'on peut faire ça c'est quand même très limitant. Récuperer les derniers store du kernel par exemple, sans que l'on ai le contrôle sur l'adresse ça ne donne pas beaucoup d'info. Et ça se fixe facilement en soft, et en hardware cela se fixe probablement assez facilement aussi. En hard, il "suffirait" de flush le buffer de metadata et les instructions associé lors des contextes switch ou de l'utilisation d'instruction spécifique pour les syscall rapide sans contexte switch comme les SYSENTER.

Donc ce n'est a priori donc pas non plus un "boulevard"
par Jemporte, le Mercredi 23 Septembre 2020 à 00h42  
"Le plus amusant dans cette histoire reste le manque de communication des firmes à propos de cette avancée."
Je ne sais pas s'il faut en rire. Plein de passoires liées aux optimisations de branchement ont été difficilement bouchées et là on nousrévèle un nouveau boulevard pour des failles encore plus monstrueuses.
par Une ragoteuse à forte poitrine en Auvergne-Rhône-Alpes, le Mardi 22 Septembre 2020 à 22h59  
par Nicolas D. le Mardi 22 Septembre 2020 à 20h50
D'acc merci pour la réponse.
Je pense que pour l'expliquer c'est effectivement pas mal de parler d'un mécanisme séparé, je réagissais surtout sur le fait d'appeler cela "un nouveau buffer interne" plutôt qu'un "nouveau mécanisme" .

Pour le fonctionnement je pense qu'il est "assez simple", le cpu doit simplement observer que l'addressing mode des operandes est le même. Par exemple:
mov dword [rsi], eax
add dword [rsi], 5
mov ebx, dword [rsi]

Dans cette exemple de Agner le processeur peut voir que l'adressing mode [rsi] est utilisé à différent endroit, il n'est donc pas absurde d'assigner un registre physique qu'on pourrait nommer "[rsi]" (si il devait avoir un nom), tout en enregistrant comme metadata que l'on doit store la valeur de ce registre. Ce qui explique pourquoi si l'on remplace un [rsi] par [rdi] sur une instruction par exemple, alors le processeur ne peut pas le optimiser puisque l'addressing mode est différent, il y a un problème d' "aliasing".

J'ai pu trouver un brevet daté de 2014 de AMD (1) qui décrit un "Store-to-load forwarding" qui n'utilise pas le store buffer, mais bien les registres physiques comme décrit ici.
Je suis plutôt confiant en affirmant que ce brevet protège l'optimisation dont on est entrain de parler.

Chez Intel ils ont aussi des brevets qui parle de cela (2)(3).

Et chez Intel comme chez AMD ils utilisent les registres physiques pour la data, et il y a un autre buffer qui contient des metadata sur l'operation en cours.

AMD:
(1) : https://patents.google.com/patent/US20140181482A1/en
Intel:
(2) : https://patents.google.com/patent/US10095522B2/en
(3) : https://patents.google.com/patent/US20140095814A1/en
par Nicolas D., le Mardi 22 Septembre 2020 à 20h50  
par Une ragoteuse à forte poitrine en Auvergne-Rhône-Alpes le Mardi 22 Septembre 2020 à 17h25
Nicolas peut-tu indiquer où tu as trouvé le terme de "Memory File" et sa description ?
Je ne le trouve pas dans tes sources (mais j'ai peut-être regardé trop rapidement). Ils parle,t de "memfile" mais pas de "Memory File". Et ce n'est jamais explicitement dit qu'il s'agirait d'un nouveau buffer dans le hardware pour contenir les datas. (ce qui impliquerait un ajout de complexité dans le datapath)
Hello ! C'est une traduction maison par analogie avec le "Register File" en fait, normale que tu ne trouve rien #patapé . Agner parle tout de même de "registre" donc je trouvais l'appellation adaptée, surtout qu'ils doivent probablement faire du renommage dessus aussi, tant qu'à faire. Dans le fonctionnement, ca doit effectivement être dans le Physical Register File ; bien que je préfère le voir comme une structure séparée (=> nécessité d'une table de routage adresse -> localisation dans le PRF). Je vais corriger néanmoins l'article en fonction !
par chambolle, le Mardi 22 Septembre 2020 à 18h49  
par Reflections_Auvg-Rhon-Alp en Île-de-France le Mardi 22 Septembre 2020 à 15h57
C'est typiquement ce genre de billet qui fait que CDH est le numéro 1 Français.

Merci !

Après, le quidam "moyen" s'en fout de tout ça à part les benchs. Par contre ça intéressera clairement ceux qui veulent devenir des gens meilleurs.
Tout à fait. La reference à la référence agner Fof est sympa aussi
par Une ragoteuse à forte poitrine en Auvergne-Rhône-Alpes, le Mardi 22 Septembre 2020 à 17h25  
Nicolas peut-tu indiquer où tu as trouvé le terme de "Memory File" et sa description ?
Je ne le trouve pas dans tes sources (mais j'ai peut-être regardé trop rapidement). Ils parle,t de "memfile" mais pas de "Memory File". Et ce n'est jamais explicitement dit qu'il s'agirait d'un nouveau buffer dans le hardware pour contenir les datas. (ce qui impliquerait un ajout de complexité dans le datapath)

De ce que j'avais lu les semaines précédentes du blog de Agner Fog et de discutions à ce propos, il était plutôt question d'une optimisation qui utilise le Physical Register File (PRF) pour stocker la donnée. Et si il y a un "memfile" ça serait pour contenir des metadata sur l'optimisation en cours (source et destination par exemple).

Utiliser les PRF me semblait une option très crédible car cela ne demande aucun ajout dans le datapath du core. Cela profiterait donc de tout le datapath déjà existant et des bypass qu'il y a avec.

(En résumé de ce que j'avais conclu: Les données dans le PRF pour utiliser le datapath existant + un nouveau buffer "memfile" pour les metadata sur l'optimisation)
Si tu as donc plus d'information je suis preneur merci.