Wiki cpu

3
8
juin
2023

Sommaire

DĂ©tails de fonctionnement processeurs et architecture modernes

Les CPU ont beaucoup évolué ces dernières années. L'importante notion de "cycle par instruction" qui avait un sens au temps des vieux processeurs z80, 6502, M68000 ou autre i386, est dépassée depuis… Les CPU ont maintenant un pipeline qui a pour objectif de diviser les instructions par blocs indépendants afin que chacune puisse s'exécuter indépendamment, ce qui a pour effet que chaque instruction consomme idéalement 1 cycle. Pour donner un exemple simple, c'est comme si pour fabriquer une bouteille, on mettait 3 secondes pour :

  • faire le contenu en plastique
  • remplir de l'eau
  • crĂ©er et fermer le bouchon.

On fera chaque étape en 1 seconde (oui on est rapide), rien n'empêchera donc d'avoir une chaîne de fabrication avec 3 machines qui réaliseraient chacunes ces trois opérations. À part la première bouteille dont la fabrication demandera 3 secondes, les suivantes se feront certes en 3 secondes mais il en sortira une par seconde !

1ère seconde 2ème sec. 3ème sec. bouteille
Contenu 1
Contenu 2 Eau 1
Contenu 3 Eau 2 Bouchon 1 fin de la bouteille 1
Contenu 4 Eau 3 Bouchon 2 fin de la bouteille 2
Contenu 5 Eau 4 Bouchon 3 fin de la bouteille 3
etc.

On voit que tout se fait en parallèle et c'est comme si on avait une bouteille par seconde ! Le principe est le même pour les instructions. Mais on peut faire mieux, car sur un processeur on a au moins 3 unités de calcul :

  • ALU (arithmetic logic unit) pour les calculs arithmĂ©tiques (plus, moins, division, multiplication) et logiques (AND, OR, XOR, dĂ©calage binaire etc);
  • LSU (loadstore unit) pour les lectures/Ă©critures sur la RAM ou autre;
  • FPU (float point unit) pour les calculs Ă  nombres flottants.

Lorsque ces unités de calcul peuvent travailler en parallèle, on parle de processeur superscalaire qui peut donc exécuter plusieurs instructions par cycle. Mais est-ce si simple ? La réponse est non, il existe plusieurs choses qui feront que le processeur se bloquera avec le pipeline.

Pour optimiser vous avez quatre choses Ă  faire :

  1. Résoudre les dépendances de données;
  2. Paralléliser les instructions;
  3. Optimiser les conditions;
  4. Optimiser les caches.

Dépendances des données

Une « dépendance de données », c'est lorsqu'un calcul dépend d'un résultat précédent. Exemple :

  1. A = B + C
  2. D = A + 5

La deuxième opération ne peut se faire que quand on connaît A. Que fait un processeur s'il est dans ce cas-là ? Il se bloque. Pour éviter ces blocages, il y a plusieurs solutions. L'une d'elles est de faire autre chose entre-temps ou de faire un bypass (que l'on expliquera plus tard).

Parallélisation

La parallélisation est l'exécution simultanée de plusieurs instructions. La difficulté est de trouver le "maximum" d'instructions à exécuter en parallèle.

Optimisation des conditions

Les conditions (if/else) rendent complexes la parallélisation : sans optimisation, un processeur ne peut pas exécuter des instructions en parallèle avant de savoir si le code ira dans telle ou telle branche (dans le if ou dans le else). La prédiction de branchement est utilisé pour que "la plupart du temps", le code ne se trompe pas. En cas d'erreurs, les calculs sont oubliés (et si c'est mal fait on vient de créer une faille spectre ou meltdown).

Quand un processeur exécute les instructions dans l'ordre et qu'il est superscalaire, on le nomme tout simplement superscalaire in order. Je devrais être plus clair : un processeur superscalaire in order exécute plusieurs instructions, mais pour cela il doit regarder l'instruction suivante et s'il peut les exécuter en parallèle, il le fait. Cela demande au compilateur d'aider beaucoup le processeur pour éviter les divers blocages.

Sinon, un processeur peut faire automatiquement ce qu'on appelle l'exécution dans le désordre. Pour éviter les blocages et paralléliser les instructions, il va tenter d'exécuter plein d'instructions. En gros, il peuvent regarder les "100 suivantes" et il cherche les instructions parallélisables ou à faire pendant un blocage et à prédire les conditions. On parle alors de prédiction de branchement.

Actuellement les processeurs sont out or order pour atteindre de hautes performances. C'est ce que font Intel et AMD depuis 30 ans (depuis le Pentium 2 à peu près).

Les processeurs in order sont souvent peu performants, et sont plus utilisé actuellement dans l'embarqué. Même s'ils ont perduré assez longtemps dans le monde des consoles (la PS3 et la X360 avait des processeurs superscalaires in order).

Il y a une autre école (dont fait partie l'AltairX, le CPU de Kannagi) qui dit qu'il faut tout simplement être plus explicite avec le processeur. Par exemple, sur le nombre d'instructions à exécuter ou sur des informations internes (bypass, renommage de registre, prédiction de branche). Cela permet d'éviter d'avoir la complexité d'un superscalaire out of order tout en gardant de bonnes performances.
À la base, le VLIW explicite seulement le nombre d'instructions en parallèle. Le désavantage est qu'il faut un très, très bon compilateur. Certains comme LLVM ont beaucoup progressé, ce qui donne bon espoir dans cette approche.

Cache

Il existe 3 types de caches :

  • Direct mapped
  • Set associative
  • Full associative

Le direct mapped est assez simpliste, on va prendre l'adresse, on va stocker une partie de cette adresse, et ça sera l'index dans notre cache (comme un tableau). Mais du coup vous allez forcément avoir pas mal de conflits d'adresse.

Le set associative est une amélioration : c'est pareil que le direct mapped, mais vous rajoutez sur chaque "index" une comparaison pour chaque adresse (en groupe de 2, 4, 8 ou 16) et on garde l'adresse entière. Le nombre d'adresses stockées sur chaque "index" est appelé way.

Avec le full associative, on stocke les adresses en entier. Cela implique de comparer chaque adresse, ce qui est relativement long (c'est la raison pour laquelle il n'est utilisé que pour un cache très petit comme le TLB).

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.