Comment passer d'un processeur ancestral à un processeur moderne à l'aide de cinq techniques pour optimiser l'architecture et les performances de chaque cycle d'horloge de ce composant.



Cet article s'inspire de la lecture de : Processor Architecture 101 - the heart of your PC de Jarred Walton :

A short primer on CPU architecture fundamentals : Briefly discuss the core concepts for processor pipelines, branch prediction, superscalar designs, and a few other items of interest.


Le processeur ancestral

Dans les années 70 - 80, la plupart des processeurs étaient au regard des architectures des processeurs modernes, simples, autrement dit des sortes de processeurs ancestraux. Le processeur exécutait les instructions qui se présentaient dans l'ordre du programme et un seul programme à la fois. Le processeur n'avait qu'un coeur (un core).

Processor pipeline

Concept apparu pour le grand public avec les 386, c'est le 486 qui sera la première véritable architecture de processeur avec un processor pipeline. L'IBM Stretch de 1961 représente la première expérimentation historique de ce concept d'architecture processeur.

The classic (RISC) 5-stage pipeline consists of fetch, decode, execute, memory, and write-back stages.

Le processor pipeline se propose de décomposer l'exécution d'une instruction en plusieurs étapes spécialisées. A chaque cycle d'horloge, chaque étape sera disponible pour une nouvelle instruction. Le nombre d'étapes détermine la profondeur du pipeline, pour l'architecture RISC, c'est une profondeur de 5, pour un Intel Pentium 4 c'est 20. Pour un RISC, il faut minimum 5 cycles pour exécuter une instruction, pour le Pentium 4 il en faut 20.

On en déduira pas que le Pentium 4 est 4 fois plus lent qu'un RISC, le jeu d'instruction lui-même, la taille de son adressage (8-16-32-64 bits) et la cadence de l'horloge seraient -entre autres- à considérer pour établir une telle comparaison.

On utilise souvent l'analogie de la chaine de production pour décrire le principe du pipeline. La production consiste à traiter une instruction.

CPU101 Pipeline 4 stages

Exemple avec un pipeline à 4 étapes - source

Le point important de cette architecture à pipeline est qu'idéalement chaque étape est disponible pour une nouvelle instruction à chaque cycle d'horloge.

Contrairement aux processeurs ancestraux, les processeurs fully pipelined peuvent lire une instruction à chaque cycle (tout comme décoder l'instruction n-1, exécuter l'instruction n-2, stocker le résultat de l'instruction n-3, écrire le résultat de l'instruction n-4).

Au premier cycle d'horloge, l'étape 1 de la première instruction est exécutée (memory fetch). Au second cycle d'horloge, cette instruction passe en étape 2 (decode), tandis que la seconde instruction peut entamer son étape 1 (fetch), celle-ci étant à nouveau disponible dans le pipeline.

Les instructions dans un pipeline sont alors bien traitées en parallèle. Le nombre d'instructions traitées est idéalement égal à la profondeur du pipeline.

Branch prediction

Idéalement on peut avoir au moins 2 instructions consécutives qui s'exécutent en paralléle et se complétent une fois finalisées.

Mais à de multiples reprises dans un programme, l'exécution compléte d'une instruction particulière est nécessaire pour déterminer la suite des instructions nécessaires. On ne peut rien deviner de la suite avant qu'un résultat donné soit calculé. Dans ce cas d'école où une telle instruction est dans le pipeline, que faire des étapes disponibles en attendant?

La prédiction de branche (branch prediction) intervient à ce stade, le processeur tente de prédire ce qui va suivre, les instructions qui devront peut-être être exécutées après l'embranchement sont envoyés dans le pipeline. C'est un pari.

Si la prédiction est correcte, alors le gain de temps est net, les instructions jusqu'alors hypothétiques de la branche donnée sont déjà en-cours voir largement avancées.

Si la prédiction est fausse, alors le gain potentiel du traitement en paralléle est nul, voir négatif, occupé à calculer une possibilité qui finalement ne se réalise pas, il prendra un temps à oublier cette erreur avant d'être disponible pour la suite des opérations.

Un bon taux de prédiction de branchement est déterminant pour les performances du pipeline processeur. Sans prédiction ou avec une mauvaise, le gain théorique et idéal de l'architecture pipeline n'aurait en pratique que de faibles résultats.

Super-scalaire

Notre processeur ancestral est un processeur scalaire, à un cycle d'horloge est exécuté une instruction (peut-être dirait les plus précis). Notre processeur pipeline est un processeur scalaire, à un cycle d'horloge est exécuté une instruction (idéalement dirait les plus précis).

En simplifiant, c'est en ajoutant au processeur d'autres pipelines au pipeline d'origine que l'on passe d'un processeur scalaire à super-scalaire. On considére toujours qu'un seul programme, suite d'instructions, un seul thread pour une seule unité d'exécution, mais avec 2 voir 4 à 6 pipelines qui fonctionnent en paralléle. Chaque pipeline exécute des instructions (idéalement) indépendantes des autres pipelines. Le super-scalaire nécessite donc des traitements spécifiques afin de s'assurer d'un dispatch le plus optimal des instructions parmis les pipes disponibles.

Ces pipelines et cette logique supplémentaire pour les alimenter représentent un ajout important de circuits qui fut notamment possible grâce au gain en finesse de gravure des processeurs.

Les premières expériences d'architecture super-scalaire se déroulèrent fin des années 60, des processeurs de ce type furent commercialisés à partir des années 80 pour le marché professionnel. Le grand public décrouvrit ces processeurs avec le Pentium 5 (Intel, 1993) et le K5 (AMD, 1996).

Séquençage des instructions dans un processeur superscalaire de degré 2. Il faut 9 cycles pour exécuter 10 instructions. À t = 5, toutes les unités du processeur sont sollicitées - source

CPU101 Illustration Pipeline superscalaire

In order to feed all of the pipelines, processors started fetching multiple instructions each cycle. Pentium (P5) processors fetch two instructions per clock, making them a '2-wide' architecture. P6 (Pentium Pro through Pentium III) processors were a 3-wide design, while its successor NetBurst (Pentium 4/Pentium D) was 2-way again—but far more complex in many other areas, and designed for higher clock speeds. The Core series and AMD's Bulldozer family were 4-wide designs that stuck around for a long time, but Skylake and now AMD's Ryzen are both moving to (sort of) 6-wide designs.

A ce stade le processeur multi-pipeline peut donc (idéalement) à chaque cycle d'horloge fournir le résultat d'autant d'instructions d'un programme/process/thread qu'il a de pipelines. Aujourd'hui les processeurs haut de gamme PC en propose généralement 6, qui peuvent se distinguer par leur spécialisation dans le traitement de types d'instructions.

Simultaneous Multithreading

Première version du simultaneous multithreading 2002, généralisation 2009. Intel appelle ça le Symmetric MultiThreading et tente de s'approprier l'acronyme SMT après l'avoir initialement baptisé hyper-threading.

Intel first introduced SMT with their Pentium 4 line and called it Hyper-Threading.

Le terme multithreading désigne en général la capacité de traiter simultanément deux threads, soit deux programmes/process/suites d'instructions.

Avec le simultaneous multithreading, on s'intéresse ici à la capacité, par cycle d'horloge, pour une unité de calcul (un core), d'exécuter plusieurs threads. Les threads sont répartis parmis les pipelines disponibles.

Le SMT est au multi-pipes ce que la prédiction de branchement est au multi-steps d'un pipe, une technique très utile voir indispensable.

En effet, tout comme les branchements sont fréquents dans un programme, au sein de ce même programme les dépendances sont nombreuses, de telle sorte que pour chaque cycle d'exécution il n'est pas toujours possible d'avoir 6 instructions usant de ressources indépendantes à fournir aux 6 pipelines. On se retrouve alors avec des capacités de traitements inutilisées dans un cycle. Le Simultaneous Multithreading se propose d'occuper ces pipelines disponibles avec des instructions provenant d'autres threads-programmes.

CPU101 Hyperthreading

Simultaneous multithreading aka SMT aka hyperthreading, crédit : intel

Le processeur moderne : multi-cœur

A ce stade, partant de l'architecture du processeur ancestral, on a ajouté plusieurs pipelines, et des sommes considérables de circuits pour optimiser leurs fonctionnement à chaque cycle d'horloge du processeur, à base de prédiction de branchement, de multithreading simultanée, et que-sais-je-encore?!

Le prochain coup est de considérer cet ensemble, cette unité de calcul, comme un core, un cœur de processeur, d'ajouter quelques circuits supplémentaires pour coordonner l'ensemble et se débrouiller pour porter ce nombre de core/cœur à 2, 4, 8 et plus si affinités!

L'opération achevée, on obtient un processeur moderne de PC, un processeur multi-core. Chaque thread est adressé sur un core par le système d'exploitation, l'OS, qui est le principal maitre d'oeuvre pour répartir ces programmes et process en-cours sur l'ensemble des cœurs. Si l'application le prévoit, elle peut instruire l'OS afin d'optimiser la répartition de ces threads sur plusieurs cœurs.

CPU101 abstraction layer

crédit : xkcd


Pour en savoir plus :

  • https://fr.wikipedia.org/wiki/Instruction_informatique
  • https://fr.wikipedia.org/wiki/Pipeline_(architecture_des_processeurs)
  • https://en.wikipedia.org/wiki/Pipeline_(computing)
  • https://en.wikipedia.org/wiki/Instruction_pipelining
  • https://en.wikipedia.org/wiki/Classic_RISC_pipeline
  • https://fr.wikipedia.org/wiki/Pr%C3%A9diction_de_branchement
  • https://fr.wikipedia.org/wiki/Branchement
  • https://en.wikipedia.org/wiki/Branch_predictor
  • https://fr.wikipedia.org/wiki/Processeur_superscalaire
  • https://en.wikipedia.org/wiki/Superscalar_processor
  • https://fr.wikipedia.org/wiki/Simultaneous_multithreading
  • https://en.wikipedia.org/wiki/Multithreading_(computer_architecture)
  • https://fr.wikipedia.org/wiki/Microprocesseur_multi-c%C5%93ur