Comment fonctionne un processeur : détail de l’architecture

Url : http://www.bestofmicro.com/guide/savoir-Processeur,5-aWRHdWlkZT0yOCZpZENsYXNzZXVyPTUw.html le 14/03/2007 à 16:12:14

Les organes fonctionnels

La mémoire cache

processeur
Un processeur possède une vitesse de fonctionnement vraiment supérieure à n’importe quel autre organe d’un ordinateur. Pour pouvoir correctement l’alimenter en calculs et données, il faut donc mettre à sa disposition une mémoire de proximité, la plus rapide possible. C’est ce rôle qui est dévolu à la mémoire cache. Jadis intégrée physiquement à proximité du processeur, elle est aujourd’hui souvent directement intégrée sur la même plaque silicium (aussi appelée « die ») que le(s) cœur(s) du processeur.

Deux subdivisions de mémoire cache

processeur
Il existe principalement deux subdivisions de mémoire cache sur les processeurs grand public. La mémoire cache de niveau 1 (aussi appelée cache L1) qui est aux prises directement avec le(s) cœur(s) du processeur et la mémoire cache de niveau 2 (cache L2) qui pourvoit le cache L1 en données. Habituellement, le cache L2 est plus grand que le cache L1 et, la majorité du temps, il est également plus lent. Cette architecture en cascade répond à divers besoins et découle de nombreux choix et contraintes technologiques complexes qui nécessitent à eux seuls un texte dédié. Sachez toutefois que cette architecture en cascade comprend actuellement (pour le grand public) deux organisations distinctes : les caches L1 et L2 inclusifs et les caches L1 et L2 exclusifs. La première option traduit la présence dans le cache L1 d’une copie partielle des données présentes dans le cache L2, alors que le choix d’une architecture en cache exclusif assure que les données présentes dans le cache L1 ne le sont pas dans le cache L2.

Synchronisation de la mémoire cache et du processeur

processeur
Aujourd’hui, la mémoire cache fonctionne la plupart du temps en mode synchrone avec le(s) cœur(s) du processeur, c’est-à-dire qu’ils fonctionnent à la même vitesse (fréquence en GHz). Leur organisation s’opère en général en xx-way associative ce qui correspond à un choix de découpage et d’adressage des zones mémoire (où xx est un nombre pair). De ces choix découle une foule de conséquences qui seraient trop longues à détailler ici. Sachez seulement que ces choix correspondent à des "besoins" différents et qu’il n’existe pas de choix meilleur que l’autre dans l’absolu.

Les registres

Il s’agit de la mémoire la plus intimement en interaction avec le cœur du processeur. Elle lui sert à lire et stocker directement les données entrées ou en sortie de calcul. Plus que cela, les registres sont souvent spécialisés dans un certain type de données/instructions comme le stockage ou la gestion de pointeurs, bien que certains gardent, pour des raisons de souplesse, une fonction générale.

processeur
Les registres sont plus ou moins étendus, mais, surtout, ils sont "codés" en xx bits. Ainsi, un processeur qui utilise des registres 32 bits est dit "processeur 32 bits" alors que les processeurs utilisant des registres 64 bits sont dits "processeurs 64 bits". Le principal impact aujourd’hui sur les machines grand public est la capacité du processeur à fonctionner avec plus de mémoire vive.

Les unités de contrôle, de fetch et de décodage

Le processeur dispose de nombreux organes dont ceux dédiés au contrôle, au fetch et au décodage. Schématiquement, l’unité de contrôle veille à ce que toute la machinerie du processeur soit bien coordonnée, en plus d’adresser, de rediriger et gérer les flux de communication entre le(s) cœur(s) d’exécution et les différents niveaux de mémoire (registres, cache L1 et L2) via le bus interne du processeur. L’opération de « fetch » fait partie de ses prérogatives et - comme nous le verrons un peu plus loin -, elle permet d’aller chercher les instructions et de charger en mémoire les données dont le processeur à besoin.

processeur
Bien que leur rôle soit très différent de celui des unités de contrôle, les unités de décodage sont à présent incontournables. Leur nécessité vient de ce qu’aujourd’hui les instructions qui sont chargées à partir de la mémoire sont complexes et demandent à être redécoupées en lots plus petits et plus facilement traitables par les unités d’exécution du processeur. Le rôle de traduction et de découpage de l’unité d’exécution influe fortement sur la longueur du pipeline dans les processeurs à pipeline long. Le pipeline est assimilable à la chaîne de production d’une usine, mais pour le calcul, chaque étape marque une opération. La succession des opérations vise à mener à bien le calcul.

Les unités de calcul

Dans les processeurs modernes grand public, le cœur exécutant des processeurs s’incarne dans les unités de calcul. Elles sont la matérialisation physique d’une grande partie du pipeline de calcul.

On distingue principalement deux grandes familles d’unités de calcul : les unités de calcul arithmétique et logique (ALU) et les unités de calcul en virgule flottante.

processeur
Le premier type d’unité (ALU) permet d’effectuer les calculs sur les nombres entiers et les opérations de logique booléenne. Essentielles dans les calculs génériques comme ceux qu’exigent les logiciels de bureautique, l’intelligence artificielle ou les navigateurs internet, les unités de calcul ALU ont longtemps été l’enjeu principal dans la course aux performances et tendent à le redevenir avec la part de plus en plus grande des applications consommatrices d’intelligence artificielle. Notons que sur certains processeurs les unités ALU peuvent calculer jusqu’à deux fois plus vite que ne le laisse supposer leur fréquence d’horloge.

Le second type d’unités de calcul (FPU) permet de calculer des nombres en virgules flottantes. Pour simplifier : elles calculent des chiffres à virgule avec plus ou moins de précision suivant les choix du concepteur ou du logiciel qui utilise les FPU. Ce type d’unités est très lourdement sollicité dans toutes applications de calculs lourds comme les jeux, les applications multimédias (vidéo, conception 3D, etc.) ou encore les calculs scientifiques.

Enfin, on trouve parfois des termes comme « unité de calcul vectoriel ». Rappelons que le calcul est dit vectoriel quand il agit d’une opération qui agit de façon déterminée sur un groupe de données de nature homogène (qu’on appelle vecteur). Il s’agit souvent de plusieurs unités de calcul FPU qui ont la possibilité de fonctionner en mode SIMD (une instruction appliquée sur plusieurs groupes de données) à l’aide d’instructions spécifiques dédiées à cet effet (MMX, 3D now, SSE1-2-3-4 ou encore Altivec, etc.). Bien entendu, il existe de « vraies unités » de calcul vectoriel mais elles se font rares dans les processeurs grand public qui ont plus vocation à effectuer des calculs de nature très variée.

L’architecture et les optimisations

Optimisation de la mémoire cache

La mémoire cache permet comme il a été détaillé précédemment de remplir un rôle de "tampon" entre le processeur et la mémoire centrale de l’ordinateur. Elle prend aujourd’hui une très grande importance dans les performances d’un ordinateur et occupe parfois plus de la moitié de la surface totale des transistors d’un "die".

processeur
Pour gérer cet espace de mémoire de plus en plus vaste, il y a des méthodes de gestion et d’optimisation de plus en plus avancées. En premier lieu et en raison des transistors présents en très grand nombre, le cache est une mémoire qui pose des problèmes de consommation électrique et donc de chauffe. Pour correctement maîtriser ces problèmes, les constructeurs (parfois désignés sous le terme de fondeurs) mettent en place des "politiques" de gestion de cache qui visent à n’alimenter que certaines lignes "utilisées" du cache. Cela permet de mieux maîtriser la consommation et donc l’autonomie ou le dégagement thermique du processeur.

Par ailleurs, le cache est l’objet de toutes les attentions depuis que les processeurs modernes multiplient les cœurs d’exécution. Partagés ou séparés, ils posent de nombreux problèmes. Dans le premier cas, il s’agit de prévenir des « interférences » possibles quand les deux cœurs d’exécution utilisent le cache commun. Dans le second cas, les problèmes d’alimentation des caches se posent. En effet, la mémoire cache est très rapide et consomme beaucoup de bande passante (débit mémoire), il faut donc pouvoir alimenter correctement deux caches L2 simultanément tout en évitant l’écueil de copier trop d’informations inutiles destinées à un cœur dans l’espace réservé à l’autre. Pour cela de nombreux complexes ont été développés.

Le prefetching et les tables de prédictions

Dans le processus de calcul, il est une étape qui est l’objet de nombreuses optimisations. En effet, si rapide soit-il le cache reste une source de temps de latence pour le cœur d’exécution, surtout quand celui-ci se retrouve « en rupture de stock » de données à traiter. Dans ce cas, le cœur d’exécution est en demande d’informations et attend que le cache les lui mette à disposition. L’optimisation de l’efficacité d’un processeur tient principalement en la réduction de ces temps de latence. Pour ce faire, et dans ce cas précis, on utilise un procédé de prefetching, c’est-à-dire de préchargement prédictif des instructions.

processeur
Comment est-il possible de deviner à l’avance les informations nécessaires ? Il suffit pour cela de tenir une table dite de prédiction de branchements. C’est une table de données qui tient à jour des statistiques sur les données et les situations qui se reproduisent souvent. Ainsi, on parvient à deviner à l’avance quel type d’instruction le processeur est susceptible de demander dans telle situation et d’y prévenir en préchargeant à l’avance les instructions dans le cache. Cette méthode de prédiction permet de couvrir à plus de 90 % les besoins en instructions d’un processeur. Les quelques % restants étant tout l’enjeu de l’optimisation et des recherches tant en architecture qu’en mathématiques.

Le pipeline et ses conséquences sur l'architecture super scalaire

L’évolution des processeurs a rapidement mené au constat que le « fordisme » (travail à la chaîne) pouvait apporter son lot de bienfaits dans les calculs. Ainsi, un pipeline d’exécution est la chaîne de traitement que suit l’information pour aboutir au résultat du calcul. Chaque étape joue son rôle et plus le découpage des étapes en tâches simples est grand, plus le pipeline est long. Cela permet de réduire grandement le temps que chaque étape prend pour mener à bien la tâche qui lui incombe. En pratique, cela se traduit par une capacité des unités de calcul à tenir des fréquences plus élevées (sans pour autant mener un même calcul en un temps plus court) et donc de cadencer le processeur à des vitesses plus élevées.

processeur
Mais un pipeline et des fréquences élevées ne sont pas une solution à tous les problèmes, notamment ceux que l’on rencontre lors d’une interruption de l’exécution des calculs. Cela se pose surtout dans des calculs où l’irrégularité des « branchements » est grande (c’est-à-dire schématiquement des opérations soumises à des conditions changeantes). Les processeurs à pipeline long sont alors obligés de consacrer de nombreux cycles à la réinitialisation des opérations pour reprendre le calcul dans le bon sens.

Cet équilibre entre fréquence de fonctionnement élevée (source de performance à longueur constante de pipeline) et nombre « d’étages » du pipeline est difficile à trouver et change suivant les architectures choisies.

Une des conséquences intéressante de ce découpage en étapes de calcul est qu’une fois qu’un « étage de calcul » s’est acquitté de son rôle, le calcul suivant peut être traiter. On remplit donc mieux tous les étages du pipeline et plusieurs opérations peuvent être en cours de traitement à un instant t. Bien entendu, leur état d’avancement n’est pas le même suivant qu’elles se situent au début ou à la fin du pipeline.

De cette astuce pour optimiser le rendement d’une unité de calcul découle une autre optimisation. Lorsque le résultat d’un calcul sert de point de départ à un autre, on comprend rapidement l’intérêt qu’on a de disposer de plusieurs unités de calcul en parallèle pour obtenir plusieurs opérations simultanément. Lorsqu’un processeur utilise cette voie de développement de puissance de calcul, on le qualifie de super scalaire.

processeur
Les processeurs super scalaires permettent une grande puissance de calcul à condition de les alimenter correctement en opérations. C’est le rôle des unités de contrôle et de traitement des données dans le désordre (on parle de traitement « ooo » pour Out of Order). Là encore, le juste équilibre est à trouver, car au-delà d’une certaine complexité, on perd plus de temps à s’évertuer à optimiser l’alimentation des unités de calcul qu’à les faire patienter un peu.

Le multicœur et multithread

Dans la quête à l’efficacité, la course au MHz a subi un coup de frein. Les nombreux problèmes de dégagements thermiques et de besoin en souplesse pour le grand public commençaient à peser trop lourd dans la balance. C’est pourquoi le multicœur constitue aujourd’hui un enjeu pour les fondeurs qui voient en lui une source de puissance supplémentaire certes, mais surtout de souplesse.

processeur
De quoi s’agit-il ? Partant du constat que l’utilisateur utilise de plus en plus souvent plusieurs logiciels simultanément, une forte parallélisation est avantageuse. C’est de là qu’est apparue l’idée d’inclure plusieurs cœurs de traitement dans un seul processeur. Ces derniers bénéficiant, au choix, de leur propre zone de mémoire cache, ou se la partageant grâce à un système de gestion de cache astucieux. Bien entendu, comme dans un tandem, un processeur disposant de deux cœurs ne va pas deux fois plus vite qu’un processeur disposant d’un seul cœur, mais le gain est appréciable et fournit un plus non négligeable en terme de confort.

Pour tirer parti de cette multiplication des cœurs d’exécution (parfois jusqu’à quatre pour les processeurs très haut de gamme), certains éditeurs de logiciels programment leurs applications en "multithread", c’est-à-dire de manière à ce que les opérations soient menées suffisamment parallèlement pour tirer pleinement profit des multiples cœurs mis à leur disposition. Cependant ce type de programmation est complexe et peu adapté à certains types d’application qui laissent peu de place au parallélisme.

Tom's Guide - http://www.tomsguide.fr/