Bonne question, ou au moins une avec une réponse intéressante. Une partie de cette réponse représente un monde où les processeurs pourraient évoluer efficacement en largeur plutôt qu'avec plusieurs cœurs séparés. Les modèles de licence / prix seraient différents!
Le reste explique pourquoi ils ne le peuvent pas. Sommaire:
- Le coût de plusieurs cœurs évolue de façon presque linéaire
- Le coût de l'élargissement des échelles du pipeline superscalaire à 1 cœur ~ quadratique Cela est possible avec suffisamment de force brute, jusqu'à un certain point de toute façon. Les performances à un seul thread sont très importantes pour une utilisation interactive (la latence de bout en bout, pas seulement le débit), donc les processeurs haut de gamme à gros cœurs actuels paient ce prix. par exemple Skylake (4 larges), Ryzen (5 ou 6 larges) et Apple A12 (7 larges pour les gros cœurs, 3 larges pour les petits cœurs éconergétiques)
- Une baisse sérieuse des rendements IPC en élargissant simplement le pipeline au-delà de 3 ou 4, même avec une exécution dans le désordre pour trouver l' ILP . Les échecs de branchement et les échecs de cache sont difficiles et bloquent tout le pipeline.
Vous n'avez pas mentionné la fréquence, juste l'IPC, mais la fréquence de mise à l'échelle est également difficile. Une fréquence plus élevée nécessite une tension plus élevée, donc la puissance évolue avec une fréquence au cube : à ^1
partir de la fréquence directement et ^2
de la tension. (Le condensateur stocke des échelles d'énergie avec V ^ 2, et la majeure partie de la puissance dynamique au-delà du courant de fuite provient de la charge de pompage dans les charges capacitives des portes FET + fils.)
Performance = fréquence multipliée par IPC. (Dans la même architecture. Un SIMD plus large vous permet de faire le même travail avec moins d'instructions, et certaines ISA sont plus denses que d'autres, par exemple, MIPS prend souvent plus d'instructions pour faire le même travail que x86 ou AArch64.)
Les coûts sont liés à la filière (coût de fabrication) et / ou à l'énergie (ce qui limite indirectement la fréquence car le refroidissement est difficile). En outre, la réduction de la puissance et des performances par Watt est un objectif en soi, en particulier pour les mobiles (batteries) et les serveurs (densité de puissance / coûts de refroidissement / coûts d'électricité).
Avant que le multi-core par socket ne soit une chose, vous aviez des systèmes multi-socket pour des cas d'utilisation haut de gamme où vous vouliez plus de débit que ce qui était réalisable avec un seul processeur qui pouvait être fabriqué, donc c'était les seuls systèmes SMP. (Serveurs, postes de travail haut de gamme).
Si un seul cœur pouvait évoluer aussi efficacement que vous le souhaitiez, nous aurions des systèmes avec 1 cœur physique par socket et SMT (par exemple HyperThreading) pour les laisser agir comme plusieurs cœurs logiques. Les ordinateurs de bureau / portables classiques n'auraient qu'un seul cœur physique, et nous n'aurions pas de mal à paralléliser des choses qui ne évoluent pas linéairement avec plus de cœurs. par exemple make -j4
pour profiter des serveurs multi-socket et / ou pour masquer la latence d'E / S sur un bureau. (Ou peut-être que nous essaierions toujours de paralléliser beaucoup si la largeur du pipeline évoluait facilement mais IPC ne le faisait pas, nous avons donc dû utiliser plus de threads SMT.) Votre noyau de système d'exploitation devrait toujours fonctionner sur tous les cœurs logiques, à moins que présente SMT à l'OS était très différent, donc des algorithmes de programmation et de verrouillage parallèles y seraient encore nécessaires.
Donald Knuth a déclaré dans une interview en 2008
Je pourrais tout aussi bien exprimer un peu mon mécontentement personnel face à la tendance actuelle à l'architecture multicœur. Pour moi, il semble plus ou moins que les concepteurs de matériel sont à court d'idées et qu'ils essaient de rejeter la responsabilité de la future disparition de la loi de Moore aux rédacteurs de logiciels en nous donnant des machines qui fonctionnent plus rapidement que sur quelques-uns. repères clés!
Oui, si nous pouvions avoir des processeurs monocœur miracles avec un débit 8 fois supérieur à de vrais programmes , nous les utiliserions probablement toujours. Avec les systèmes à double socket uniquement lorsque cela valait la peine de payer beaucoup plus pour plus de débit (pas de performances à un seul thread).
Plusieurs processeurs réduisent les coûts de changement de contexte lorsque plusieurs programmes sont en cours d'exécution (en les laissant réellement s'exécuter en parallèle au lieu de basculer rapidement entre eux); le multitâche préventif interrompant les énormes machines hors service dont un processeur aurait besoin serait probablement encore plus douloureux qu'aujourd'hui.
Physiquement, il s'agirait d'un seul cœur (pour une hiérarchie de cache simple sans interconnexion entre les cœurs) mais prendrait en charge SMT (par exemple, HyperThreading d'Intel) afin que le logiciel puisse l'utiliser comme 8 cœurs logiques qui rivalisent dynamiquement pour les ressources de débit. Ou lorsqu'un seul thread est en cours d'exécution / non bloqué, il en bénéficierait pleinement.
Donc, vous utiliseriez plusieurs threads lorsque cela serait plus facile / naturel (par exemple, des processus séparés s'exécutant simultanément), ou pour des problèmes facilement parallélisés avec des chaînes de dépendance qui empêcheraient de maximiser l'IPC de cette bête.
Mais malheureusement, c'est un vœu pieux de la part de Knuth que les processeurs multicœurs cessent jamais d'être une chose à ce stade.
Mise à l'échelle des performances sur un seul thread
Je pense que s'ils faisaient un équivalent à 1 cœur d'un processeur à 8 cœurs, ce cœur aurait une augmentation de 800% de l'IPC afin que vous obteniez les performances complètes dans tous les programmes, pas seulement ceux qui sont optimisés pour plusieurs cœurs.
Oui c'est vrai. S'il était possible de construire un tel processeur , ce serait très étonnant. Mais je pense que c'est littéralement impossible sur le même processus de fabrication de semi-conducteurs (c'est-à-dire la même qualité / efficacité des transistors). Ce n'est certainement pas possible avec le même budget de puissance et la même zone de matrices qu'un processeur à 8 cœurs, même si vous économisez de la logique pour coller les cœurs ensemble, et n'auriez pas besoin d'autant d'espace pour les caches privés par cœur.
Même si vous autorisez des augmentations de fréquence (puisque le véritable critère est le travail par seconde, pas le travail par horloge), rendre même un processeur 2x plus rapide serait un énorme défi.
S'il était possible à peu près à la même puissance et au même budget (donc le coût de fabrication) de construire un tel processeur, oui, les fournisseurs de CPU les construiraient déjà de cette façon.
Plus précisément les noyaux plus ou plus larges? section, pour le contexte nécessaire pour comprendre cette réponse; cela commence simplement par le fonctionnement des processeurs pipelinés dans l'ordre, puis superscalaire (plusieurs instructions par horloge). Explique ensuite comment nous avons atteint le mur de puissance à l'époque de P4, ce qui a conduit à la fin de la mise à l'échelle facile des fréquences, ne laissant principalement que l'IPC et plus de travail par instruction (par exemple SIMD) comme voie à suivre, même avec des transistors plus petits.
Rendre un pipeline plus large (instructions max par horloge) a généralement un coût en largeur au carré . Ce coût est mesuré en zone de matrice et / ou en puissance, pour une vérification de dépendance parallèle plus large (détection des dangers), et un planificateur hors service plus large pour trouver des instructions prêtes à exécuter. Et plus de ports de lecture / écriture sur votre fichier de registre et cache si vous souhaitez exécuter des instructions autres que nop
. Surtout si vous avez des instructions à 3 entrées comme FMA ou add-with-carry (2 registres + drapeaux).
Il y a également des rendements IPC décroissants pour élargir les CPU ; la plupart des charges de travail ont un ILP (Instruction-Level Parallelism) limité à petite échelle / courte portée pour les CPU à exploiter, donc élargir le cœur n'augmente pas IPC (instructions par horloge) si IPC est déjà limité à moins que la largeur de la noyau par des chaînes de dépendance, des échecs de branche, des échecs de cache ou d'autres décrochages. Bien sûr, vous obtiendrez une accélération dans certaines boucles déroulées avec des itérations indépendantes, mais ce n'est pas ce que la plupart du code passe la plupart de son temps à faire. Les instructions de comparaison / branchement représentent 20% de la combinaison d'instructions en code "typique", IIRC. (Je pense que j'ai lu des chiffres de 15 à 25% pour divers ensembles de données.)
En outre, un échec de cache qui bloque toutes les instructions dépendantes (puis tout une fois que la capacité ROB est atteinte) coûte plus cher pour un processeur plus large. (Le coût d'opportunité de laisser plus d'unités d'exécution inactives; plus de travail potentiel ne se fait pas.) Ou un échec de branche provoque également une bulle.
Pour obtenir 8 fois l'IPC, nous aurions besoin d'au moins 8 fois l'amélioration de la précision de la prédiction de branche et des taux d'accès au cache . Mais les taux d'accès au cache n'évoluent pas bien avec la capacité du cache au-delà d'un certain point pour la plupart des charges de travail. Et la pré-récupération HW est intelligente, mais ne peut pas être aussi intelligente. Et à 8x l'IPC, les prédicteurs de branche doivent produire 8x autant de prédictions par cycle et les rendre plus précises.
Les techniques actuelles de construction de CPU d'exécution hors ordre ne peuvent trouver ILP que sur de courtes plages . Par exemple, la taille ROB de Skylake est de 224 uops de domaine fusionné, le planificateur pour les uops non exécutés est de 97 domaine non fusionné. Voir Comprendre l'impact de lfence sur une boucle avec deux longues chaînes de dépendance, pour augmenter les longueurs dans le cas où la taille du planificateur est le facteur limitant pour extraire ILP de 2 longues chaînes d'instructions, si elles deviennent trop longues. Et / ou voir cette réponse plus générale et introductive ).
Donc, trouver ILP entre deux longues boucles distinctes n'est pas quelque chose que nous pouvons faire avec du matériel. La recompilation binaire dynamique pour la fusion de boucles pourrait être possible dans certains cas, mais les CPU durs et pas quelque chose peuvent vraiment faire à moins qu'ils ne choisissent la route Transmeta Crusoe. (Couche d'émulation x86 au-dessus d'un ISA interne différent; dans ce cas, VLIW). Mais les conceptions x86 modernes standard avec des caches uop et des décodeurs puissants ne sont pas faciles à battre pour la plupart des codes.
Et en dehors de x86, tous les ISA encore utilisés sont relativement faciles à décoder, il n'y a donc aucune motivation pour la recompilation dynamique autre que les optimisations à longue distance. TL: DR: espérer des compilateurs magiques qui peuvent exposer plus d'ILP au matériel n'a pas fonctionné pour Itanium IA-64 , et il est peu probable qu'il fonctionne pour un processeur super large pour tout ISA existant avec un modèle d'exécution en série.
Si vous aviez un processeur super large, vous voudriez certainement qu'il prenne en charge SMT afin que vous puissiez le nourrir avec du travail à faire en exécutant plusieurs threads à faible ILP.
Étant donné que Skylake a actuellement 4 uops de large (et atteint un véritable IPC de 2 à 3 uops par horloge, ou même plus proche de 4 dans le code à haut débit), un processeur hypothétique 8x plus large aurait une largeur de 32!
Être capable de sculpter cela en 8 ou 16 CPU logiques qui partagent dynamiquement ces ressources d'exécution serait fantastique: les threads non bloqués obtiennent toute la bande passante frontale et le débit back-end.
Mais avec 8 cœurs séparés, lorsqu'un thread se bloque, il n'y a rien d'autre pour alimenter les unités d'exécution; les autres fils n'en bénéficient pas.
L'exécution est souvent éclatante: elle s'arrête en attendant un chargement raté du cache, puis une fois que cela arrive, de nombreuses instructions en parallèle peuvent utiliser ce résultat. Avec un processeur ultra-large, cette rafale peut aller plus vite et peut réellement aider avec SMT.
Mais nous ne pouvons pas avoir de CPU magiques super larges
Donc, pour gagner du débit, nous devons plutôt exposer le parallélisme au matériel sous la forme d'un parallélisme au niveau des threads . Généralement, les compilateurs ne savent pas quand / comment utiliser les threads, sauf pour les cas simples comme les très grosses boucles. (OpenMP ou gcc -ftree-parallelize-loops
). Il faut encore de l'habileté humaine pour retravailler le code afin de réaliser efficacement des travaux utiles en parallèle, car la communication entre les threads est coûteuse, tout comme le démarrage des threads.
Le TLP est un parallélisme à grain grossier, contrairement à l'ILP à grain fin dans un seul thread d'exécution que HW peut exploiter.
Les processeurs destinés à des charges de travail interactives (comme Intel / AMD x86 et les cœurs haut de gamme Apple / ARM AArch64) poussent certainement dans les rendements décroissants de la mise à l'échelle IPC, car les performances à un seul thread sont toujours si précieuses lorsque la latence est importante, pas seulement le débit pour problèmes massivement parallèles.
Pouvoir exécuter 8 copies d'un jeu en parallèle à 15fps chacune est beaucoup moins précieux que pouvoir exécuter une copie à 45fps. Les éditeurs de CPU le savent, et c'est pourquoi les CPU modernes utilisent une exécution dans le désordre même si cela coûte beaucoup d'énergie et de matrice. (Mais les GPU ne le font pas parce que leur charge de travail est déjà massivement parallèle).
Le matériel à plusieurs cœurs Xeon Phi d'Intel (Knight's Landing / Knight's Mill) est un point intéressant à mi-chemin: exécution hors service très limitée et SMT pour garder les cœurs à 2 larges alimentés avec des instructions SIMD AVX512 pour calculer les nombres. Les cœurs sont basés sur l'architecture Silvermont à faible consommation d'Intel. (Exécutif hors service mais avec une petite fenêtre de réorganisation, beaucoup plus petite que la famille Sandybridge à gros cœurs. Et un pipeline plus étroit.)
BTW, tout cela est orthogonal à SIMD. Faire plus de travail par instruction est toujours utile, si cela est possible pour votre problème.
Modèles de tarification
Les modèles de tarification des logiciels sont basés sur le paysage actuel du matériel.
Les modèles de licence par cœur sont devenus plus répandus (et pertinents même pour les postes de travail à socket unique) avec l'avènement des processeurs multicœurs. Avant cela, cela ne concernait que les serveurs et les grandes stations de travail.
Si le logiciel n'avait pas besoin de plusieurs cœurs pour fonctionner à vitesse maximale, il n'y aurait pas vraiment de moyen de le vendre moins cher aux personnes qui n'en tirent pas autant d'avantages car ils l'exécutent sur un processeur plus faible. À moins que l'écosystème logiciel / matériel n'ait évolué des contrôles sur les "canaux SMT" qui vous permettent de configurer une largeur d'exécution maximale pour le code s'exécutant sur ce noyau logique. (Encore une fois, imaginer un monde où les processeurs évoluent en largeur de pipeline au lieu de plusieurs cœurs séparés.)