Du simple outil de recherche au milieu du 20eme siècle, l’informatique est devenue en l’espace d’un demi-siècle indispensable. Aujourd’hui, il existe une large variété d’usages : calcul haute performance (HPC), internet des objets (IoT), calcul dans les nuages (cloud) etc. Cette diversité change la façon dont les architectes abordent la conception des processeurs. Dans certains cas, la simplicité est recherchée pour avoir un environnement contrôlé, comme dans le domaine de l’avionique. Dans d’autres cas, on recherche la rapidité de calcul, ce qui implique des processeurs optimisés et plus complexes. Néanmoins, quelque soit l’usage des processeurs, tous aujourd’hui ont un point en commun dans leur conception : diminuer le plus possible la consommation énergétique. La question de l’efficacité énergétique est un des grands enjeux de nos jours dans le domaine de l’informatique. A titre d’exemple, les États-Unis ont estimé en 2015 qu’une machine de calcul d’une puissance d’un exaflops (10¹⁸ opérations flottantes par seconde) basée sur l’infrastructure chinoise Tianhe-2 [107] consommerait autant d’énergie que les foyers de la ville de San Francisco [37]. Une telle puissance de calcul n’est économiquement pas rentable et la communauté scientifique doit apporter une réponse à ce challenge financier.
Consommation énergétique : nature et répartition
Depuis une quinzaine d’années, l’International Technology Roadmap for Semiconductors (ITRS) a identifié l’augmentation de la consommation énergétique comme un problème majeur [53]. L’analyse de cette consommation énergétique montre qu’il existe deux types de consommation : dynamique et statique. La consommation dynamique est le besoin en courant requis par un transistor pour le faire changer d’état (0 → 1 et 1 → 0). La consommation dynamique du circuit est la somme de toute l’énergie nécessaire à ces changements d’état sur tous les transistors. Cette énergie est nécessaire uniquement lorsqu’il y a une tâche à effectuer. A l’inverse, l’énergie statique, ou courant de fuite, est un besoin énergétique indépendant de toute activité. La miniaturisation à l’extrême des composants entraîne une fuite d’électrons permanente dans les transistors. Ces derniers doivent être remplacés en continu pour conserver l’état du transistor, générant une consommation électrique. Plus un composant contient de transistors, et donc occupe une grande surface de silicium, et plus son courant de fuite est important.
C’est de cette énergie statique que provient une part significative de la consommation énergétique des circuits [53]. A titre d’exemple, Carroll et al. [20] ont montré que dans certains cas, l’énergie statique d’un smartphone lorsqu’il n’est pas en veille est d’au moins 50%, et ce chiffre augmente considérablement si l’on ajoute le système d’affichage. La diminution de la finesse de gravure entraîne également une augmentation de la consommation statique. Les constructeurs intègrent donc des mécanismes d’économie d’énergie et les activent le plus souvent possible, sacrifiant les performances pour une durée de batterie plus élevée.
Principes des mémoires caches
Structure des caches et échange de données
Un cache est un composant mémoire intégré dans le processeur. De quelques kilooctets à plusieurs méga-octets, il s’intercale entre la mémoire principale et le cœur de calcul. Un cache contient un sous-ensemble des données de la mémoire principale. Il a pour but d’accélérer l’exécution du processeur en lui fournissant les données nécessaires aux calculs. L’intérêt d’un cache est sa rapidité d’accès, de l’ordre de quelques cycles d’horloge
Lorsqu’un cache reçoit une requête et que la donnée demandée est contenue dans ce cache, cela génère un hit. A l’inverse, lorsque la donnée demandée n’est pas dans le cache, on parle de miss. La donnée sera alors cherchée dans le niveau de mémoire supérieur.
Localité spatiale et temporelle
L’efficacité des caches repose sur les principes de localité spatiale et localité temporelle. La localité temporelle indique qu’une donnée accédée récemment dans le cache a une forte probabilité d’être accédée de nouveau dans un futur « proche ». La localité spatiale indique que les adresses ont une forte probabilité d’être accédées de manière consécutive.
Niveaux de cache
Plusieurs niveaux de cache sont généralement utilisés entre un cœur et la mémoire. Le niveau de cache L1 le plus proche du CPU contient quelques dizaines de kilo-octets de données, ce qui est suffisant lorsqu’une application respecte les deux principes de localité.
Les niveaux supérieurs sont plus importants en termes de capacité. Les derniers processeurs Intel-i7 de 8e génération contiennent par exemple un cache de niveau 3 de 12Mo. La combinaison de plusieurs niveaux de cache permet de profiter de ces principes sur un plus large volume de données. Ainsi, la hiérarchie de caches minimise les accès externes à la mémoire principale qui sont coûteux en temps et en énergie.
Mécanismes matériels générant des écritures
Mode d’écriture
Lorsque le CPU écrit dans son cache L1, il existe deux modes pour propager l’information à la hiérarchie mémoire : Write-Through et Write-Back. Avec le mode Write-Through, toute écriture dans le cache L1 est parallèlement propagée à l’ensemble de la hiérarchie mémoire, y compris la mémoire principale. De cette façon, la hiérarchie mémoire contient en permanence les valeurs les plus à jour pour toutes les données. Ce mode génère cependant un nombre important de transactions à gérer pour les systèmes d’interconnexion, ainsi que pour les caches. Ainsi, il n’est que rarement utilisé dans les architecture multicœurs classiques. A l’inverse, le mode Write-Back délaie l’écriture dans les niveaux supérieurs de la mémoire au plus tard. Typiquement, cela arrive lorsqu’une ligne de la mémoire cache L1 est pleine et qu’une donnée doit alors être retirée pour en stocker une nouvelle. Dans cette situation, la ligne qui est retirée est écrite dans le cache L2. Une autre possibilité est lorsque le protocole de cohérence des caches est utilisé (détaillé dans la section suivante).
Cohérence des caches
Dans la majorité des architectures multicœurs utilisant un mode d’écriture Write-Back, les données contenues dans les caches sont cohérentes. Cela signifie que si un cœur modifie une donnée dans son cache L1 privé et qu’un second cœur souhaite y accéder, il existe un mécanisme implémenté entièrement en matériel permettant de s’assurer que la valeur lue par le second cœur soit la valeur modifiée par le premier cœur. Ce mécanisme peut être implémenté de différentes manières, via du snooping [66] ou l’utilisation d’un directory .
1 Introduction |