Comment fonctionne la prédiction de branche, si vous devez toujours vérifier les conditions?

30

Je lisais la réponse populaire sur Branch Prediction de https://stackoverflow.com/q/11227809/555690 , et il y a quelque chose qui me déroute:

  • Si vous avez bien deviné, cela continue.
  • Si vous vous trompez, le capitaine s'arrête, recule et vous crie dessus pour actionner l'interrupteur. Ensuite, il peut redémarrer sur l'autre chemin.

Si vous devinez à chaque fois, le train n'aura jamais à s'arrêter.

Si vous vous trompez trop souvent, le train passera beaucoup de temps à s'arrêter, à reculer et à redémarrer.

Mais c'est ce que je ne comprends pas: pour savoir si votre supposition était bonne ou mauvaise, vous devez quand même vérifier l'état . Alors, comment fonctionne la prédiction de branche, si vous effectuez toujours la même vérification conditionnelle?

Ce que j'essaie de dire, c'est que la prédiction de branche n'est pas exactement la même chose que de ne pas avoir de prédiction de branche du tout parce que vous effectuez les mêmes vérifications conditionnelles de toute façon? (évidemment je me trompe, mais je ne comprends pas)

Oméga
la source
1
Cet article wiki fait un très bon travail pour l'expliquer.
enderland
8
Un processeur moderne est en pipeline et peut faire plusieurs choses en même temps. Ainsi, il peut commencer à exécuter sa supposition pendant qu'il cherche encore à savoir s'il a bien deviné. Si la supposition était juste, le pipeline continue de fonctionner. En cas de supposition erronée, le pipeline est lancé et l'exécution redémarre à partir du point "bonne réponse".
markspace
2
Lecture connexe: pipeline . Je recommanderais également de relire la réponse acceptée à cette question SO, car elle répond à votre question ici.

Réponses:

19

Bien sûr, l'état est vérifié à chaque fois. Mais au moment où il est vérifié, il est loin dans le pipeline du processeur. Entre-temps, d'autres instructions sont également entrées dans le pipeline et sont à divers stades d'exécution.

Habituellement, une condition est immédiatement suivie d'une instruction de branchement conditionnel, qui se branche si la condition est évaluée à VRAI, ou échoue si la condition est évaluée à FAUX. Cela signifie qu'il existe deux flux d'instructions différents qui peuvent être chargés dans le pipeline après l'instruction de condition et l'instruction de branchement, selon que la condition est évaluée à VRAI ou FAUX. Malheureusement, immédiatement après le chargement de l'instruction de condition et de l'instruction de branchement, le processeur ne sait pas encore à quoi la condition va être évaluée, mais il doit toujours continuer à charger des éléments dans le pipeline. Il choisit donc l'un des deux ensembles d'instructions en fonction d'une supposition quant à la condition à laquelle la condition sera évaluée.

Plus tard, alors que l'instruction de condition remonte le pipeline, il est temps de l'évaluer. À ce moment-là, le CPU découvre si sa supposition était bonne ou mauvaise.

Si la supposition s'avère juste, alors la branche est allée au bon endroit et les bonnes instructions ont été chargées dans le pipeline. S'il s'avère que la supposition était erronée, alors toutes les instructions qui ont été chargées dans le pipeline après que l'instruction de branchement conditionnel était erronée, elles doivent être rejetées et la récupération des instructions doit recommencer au bon endroit.

Amendement

En réponse au commentaire de StarWeaver, pour donner une idée de ce que le CPU doit faire pour exécuter une seule instruction:

Considérez quelque chose d'aussi simple que MOV AX,[SI+10]ce que nous, humains, considérons naïvement comme «charger AX avec le mot à SI plus 10». En gros, le CPU doit:

  1. émettre le contenu du PC (le "registre de compteur de programme") vers le bus d'adresse;
  2. lire l'opcode d'instruction du bus de données;
  3. incrémenter PC;
  4. décoder l'opcode pour savoir quoi en faire;
  5. émettre le contenu du PC vers le bus d'adresse;
  6. lire l'opérande d'instruction (dans ce cas 10) à partir du bus de données;
  7. incrémenter PC;
  8. fournir l'opérande et SI à l'additionneur;
  9. émettre le résultat de l'additionneur sur le bus d'adresse;
  10. lire AX depuis le bus de données.

C'est un énorme 10 étapes. Certaines de ces étapes seront optimisées même dans les processeurs non pipelinés, par exemple le CPU incrémentera presque toujours le PC en parallèle avec l'étape suivante, ce qui est une chose facile à faire car le PC est un registre très très spécial qui est jamais utilisé pour un autre travail, il n'y a donc aucune possibilité de conflit entre les différentes parties du CPU pour accéder à ce registre particulier. Mais encore, il nous reste 8 étapes pour une instruction aussi simple, et notez que je suppose déjà un certain degré de sophistication au nom du CPU, par exemple je suppose qu'il n'y aura pas besoin d'une étape supplémentaire entière pour le additionneur pour effectuer l'ajout avant de pouvoir en lire le résultat,

Maintenant, considérez qu'il existe des modes d'adressage plus compliqués, comme MOV AX, [DX+SI*4+10], et même des instructions beaucoup plus compliquées, comme celles MUL AX, operandqui effectuent réellement des boucles à l'intérieur du CPU pour calculer leur résultat.

Donc, mon point ici est que la métaphore du "niveau atomique" est loin d'être appropriée pour le niveau d'instruction CPU. Il peut convenir au niveau de l'étape du pipeline, si vous ne voulez pas aller trop loin jusqu'au niveau de la porte logique réelle.

Mike Nakis
la source
2
Huh, je me demande si une partie du problème que les gens (y compris moi) ont à comprendre, c'est qu'il est très difficile (pour moi de toute façon) d'imaginer un processeur n'ayant qu'une connaissance partielle d'une seule instruction; ou d'avoir un tas d'instructions à moitié finies "en passant par le four à courroie à pizza" ... pour moi au moins, cela ressemble à un changement d'échelle vers l'atomique quand j'ai l'habitude de travailler avec des choses entre le montage de monteurs et le niveau du tour à métaux.
StarWeaver
1
@StarWeaver J'ai aimé votre commentaire, j'ai donc modifié ma réponse pour y répondre.
Mike Nakis
1
Wow, belle explication. J'ai tendance à oublier combien il faut pour déplacer des mots dans des endroits plus utiles. Je visualise toujours un processeur comme un ensemble de fours à pizza entraînés par courroie cependant: 3.
StarWeaver
Il convient de garder à l'esprit que la question de débordement de pile liée à l'OP - celle avec 1,3 million de vues qui a probablement introduit plus d'un million de programmeurs au fait auparavant inconnu que la "prédiction de branche" existe même - présente un exemple en Java . Pour les gens comme moi qui ont l'habitude de travailler au niveau d'abstraction que nous fournissent des langages comme Java, même ils MOV AX,[SI+10]sont étrangers, pas "simples"; la plupart des programmeurs n'ont jamais écrit d'assemblage. Nous ne «pensons pas naïvement» que cela signifie quelque chose.
Mark Amery
@MarkAmery bien, d'accord, je pensais qu'il était assez évident que par "nous les humains", je veux dire "nous les humains qui osons écrire l'assemblage". Le fait est que même les programmeurs en langage assembleur ne pensent pas tout le temps au pipeline, voire pas du tout.
Mike Nakis
28

Pensez-y comme un road trip sans GPS. Vous arrivez à une intersection et pensez que vous devez tourner, mais vous n'êtes pas complètement sûr. Vous prenez donc le virage, mais demandez à votre passager de vérifier la carte. Peut-être que vous êtes à trois miles sur la route au moment où vous avez fini de vous disputer sur votre position. Si vous aviez raison, vous êtes à trois milles plus loin que vous ne l'auriez été si vous vous étiez arrêté et argumenté avant de tourner. Si vous vous trompiez, vous devez vous retourner.

Les pipelines CPU fonctionnent de la même manière. Au moment où ils peuvent vérifier l'état, ils sont déjà en chemin. La différence est qu'ils n'ont pas à reculer de trois milles, ils perdent juste l'avance. Cela signifie qu'il n'y a aucun mal à essayer.

Karl Bielefeldt
la source
2
Cette explication est nette.
2015
2

D'après ma compréhension, la prédiction de branche est plus utile lorsque la condition que vous devez vérifier nécessite le résultat de quelque chose qui est cher ou encore en cours, et vous seriez sinon en train de tourner les pouces en attendant la valeur pour évaluer la condition.

Avec des choses comme l'exécution dans le désordre, vous pouvez utiliser la prédiction de branche pour commencer à remplir des espaces vides dans le pipeline que le CPU ne pourrait pas utiliser autrement. Dans une situation où il n'y a, pour une raison quelconque, aucun cycle inactif dans le pipeline, alors oui, il n'y a pas de gain dans la prédiction de branche.

Mais la clé ici est que le processeur commence le travail pour l'une des branches prédites car il ne peut pas encore évaluer la condition elle-même.

Chiens
la source
1

Forme courte:

Certains processeurs peuvent commencer à travailler sur une nouvelle instruction avant de terminer l'ancienne. Ce sont les CPU qui utilisent la prédiction de branche.

Un exemple de pseudocode:

int globalVariable;
int Read(int* readThis, int* readThat)
{
    if ((globalVariable*globalVariable % 17) < 5)
       return *readThis;
    else
       return *readThat;
}

Le code ci-dessus vérifie une condition et en fonction du résultat, il doit renvoyer la valeur stockée à l'emplacement de mémoire addThisou la valeur stockée à readThat. Si la prédiction de branchement prédit la condition true, le CPU lira déjà la valeur stockée à l'emplacement de mémoire addThistout en effectuant le calcul nécessaire pour évaluer l' ifinstruction. Ceci est un exemple simplifié.

Peter
la source
1

Oui, la condition est vérifiée dans les deux cas. Mais l'avantage de la prédiction de branche est que vous pouvez travailler au lieu d'attendre le résultat du contrôle de condition.

Disons que vous devez écrire un essai et qu'il peut s'agir du sujet A ou du sujet B. Vous savez d'après les essais précédents que votre professeur aime mieux le sujet A que B et le choisit plus souvent. Au lieu d'attendre sa décision, vous pouvez commencer à rédiger l'essai sur le premier sujet. Maintenant, il y a deux résultats possibles:

  1. Vous avez commencé votre essai sur le mauvais sujet et devez abandonner ce que vous avez écrit jusqu'à présent. Vous devez commencer à écrire sur l'autre sujet et c'est le même effort de temps que si vous aviez attendu.
  2. Vous avez bien deviné et vous avez déjà fait du travail.

Les processeurs modernes tournent au ralenti la plupart du temps car ils attendent des réponses d'E / S ou le résultat d'autres calculs. Ce temps peut être utilisé pour effectuer des travaux futurs.

Même si vous devez ignorer ce que vous faites en cette période d'inactivité - il est plus probable que ce soit plus efficace si vous avez la possibilité de deviner quel chemin le programme choisira. Et les processeurs modernes ont cette capacité.

Otomo
la source