[gull] Above Meltdown & Spectre

Dominik Madon dominik at acm.org
Thu Feb 15 10:05:45 CET 2018


> J'ai fait un jour l'expérience suivante : J'ai écrit un programme (en asembleur) allant lire le registre des clock tick sur un CPU. Puis, dans mon programme C appelant la fonction, j'ai essayé de déterminer l'overhead de cet appel, afin de le soustraire de mes calculs lorsque je voulais mesurer une courte période de temps. A ma grande surprise, en collectant les valeurs, j'ai obtenu de grandes variations  dans mes mesures. Donc, à un moment on est confronté au choix d'utiliser la valeur minimum, ou une valeur moyenne... C'est ce jour là que j'ai véritablement saisi l'impact que les autres process peuvent avoir sur un code même très court. Et encore... je ne faisais pas appel à des valeurs en mémoires (caches), ni de stresse du BHT...

Ceci mesure surtout l'effet de l'OS et des différentes tâches qui tournent ou ne tournent pas à un moment donné. Même si les registres de caches de saut n'existaient pas, la variation resterait (probablement amplifiée par la perte de performance).

> Maintenant... on peut aborder ce que tu dis :
> 
> permet d’exécuter 3 instructions en parallèle par cycle au maximum.
> 
> 
> C'est justement dans le mot permet que ça devient intéressant. Donc, selon cette théorie, on devrait avoir un CPI de 0.33...

Un CPI minimum théorique de 0.33, c'est exact. Si je reprends mon exemple avec le Cortex-M15, un pipeline sans prédiction de branchement, qui ne fait donc rien entre 70% et 87% de son temps, on obtient un CPI compris entre: 3.33 et 5.88.

> Je me trompe où on en est loin ? Je n'ai pas de valeur pour l'ARM, mais les dernières valeurs que j'ai vu passées sont supérieures à 1. Bien que le CPI ne dise pas tout, c'est une indication. De plus, 3 instructions... mais lesquelles ? Tout ceci est fantastique si toutes les instructions ne s'exécute qu'en un seul cycle. Or, beaucoup d'instructions nécessitent bien plus de cycle. Certains mode d'adressage sont d'ailleurs des tueurs dans ce domaine, de même que les opérations de calcul, dont la division est un gros point noir. Alors, que ce passe-t-il dans ce cas dans le CPU ? Le CPU est-il en attente de la fin de toutes les instructions, ou est-il capable de shifter une partie des instructions dans le pipe (j'en doute). Qui plus est, si une instruction fait appel à une valeur qui ne se trouve pas dans la cache L1 ? Là le processeur est en "stall"...

Bien sûr, on peut toujours chercher les pires des cas, mais c'est comme pour les benchmarks que vous ne trouviez pas réalistes. Il faut regarder la moyenne sur un ensemble représentatif. Au moins les benchmarks sont une liste de plusieurs programmes différents.

> Les techniques que tu décris pour l'ARM ne sont pas nouvelles, car elles sont toutes issues de ce qui a été introduit avec les processeurs RISC dans les années 80. C'est aussi là que l'on s'est rendu compte qu'il y a loin de la théorie à la pratique. Les techniques d'optimisation ont permit de minimiser l'impact des pipe-flush, sans arriver à les éliminer complètement.

Le processeur Alpha 21064 introduit les pipelines longs (super pipeline) en 1992. MIPS et Sparc ont introduits les premiers processeurs RISC à pipeline court dans le domaine commercial quelques années avant. Le superscalaire, l'exécution dans le désordre et la spéculation de branchement n'apparaissent que dans le courant des années 90. Si j'ai raté quelque chose, je veux bien que vous m'en donniez quelques exemples.

> La théorie et les hypothèses c'est bien et passionnant, mais c'est lorsque l'on fait véritablement des mesures que l'on se rend compte que certaines choses ne sont pas ce que l'on croit.

Je suis bien d'accord. Je vous propose de faire une démonstration en prenant SimpleScalar (http://www.simplescalar.com/) qui est un simulateur de processeur RISC superscalaire avec exécution dans le désordre. Cous pouvez paramétrer tous les composants de l'architecture et passer toutes les caches à une taille de 0. Ensuite, vous prenez les programmes C qui composeront votre benchmark et vous les compilez pour l'architecture choisie avant de lancer le simulateur qui vous donne une exécution instrumentée de votre code. Vous reprenez ensuite avec des caches de taille classiques et vous faites la différence.

Au plaisir de lire vos résultats.


Dominik





More information about the gull mailing list