Au niveau le plus bas (dans le matériel), oui, sis sont chers. Afin de comprendre pourquoi, vous devez comprendre comment les pipelines de travail.
L'instruction à exécuter est stocké dans quelque chose de généralement appelé le pointeur d'instruction (IP) ou compteur de programme (PC); ces termes sont synonymes, mais en des termes différents sont utilisés avec des architectures différentes. Pour la plupart des instructions, le PC de la prochaine instruction est juste le PC actuel, plus la longueur de l'instruction courante. Pour la plupart des architectures RISC, les instructions sont toutes de longueur constante, de sorte que le PC peut être incrémenté par une valeur constante. Pour CDCI architectures telles que les x86, des instructions peuvent être de longueur variable, de sorte que la logique qui décode l'instruction a la figure combien de temps l'instruction courante est de trouver l'emplacement de la prochaine instruction.
Pour la branche des instructions, cependant, la prochaine instruction à être exécutée n'est pas l'emplacement suivant, après l'instruction courante. Les Branches sont gotos - ils dire que le processeur où la prochaine instruction. Les Branches peuvent être soit conditionnelle ou inconditionnelle, et l'emplacement cible peut être soit fixe ou calculée.
Conditionnel vs inconditionnel est facile à comprendre, une branche conditionnelle n'est prise que si une certaine condition est remplie (par exemple si un nombre est égal à un autre); si la branche n'est pas pris, le contrôle passe à l'instruction suivante après que la branche comme d'habitude. Pour les inconditionnels de branches, la branche est toujours pris. Les branches conditionnelles montrent en if
états et les tests de contrôle de for
et while
boucles. Inconditionnel des branches apparaissent dans les boucles infinies, des appels de fonction, la fonction renvoie la, break
et continue
des déclarations, l'infâme goto
déclaration, et beaucoup d'autres (ces listes sont loin d'être exhaustive).
La direction de la cible est une autre question importante. La plupart des branches ont un fixe en direction de la cible - ils accéder à un emplacement spécifique dans le code qui est fixé au moment de la compilation. Cela inclut if
des déclarations, des boucles de toutes sortes, régulièrement des appels de fonction, et beaucoup plus. Calculé branches calculer la cible de la direction au moment de l'exécution. Cela inclut switch
des déclarations (parfois), de retour d'une fonction, la fonction virtuelle appels et appels de pointeur de fonction.
Donc, est-ce que cela signifie pour la performance? Lorsque le processeur voit une branche de l'instruction apparaissent dans son pipeline, il a besoin de comprendre comment continuer à remplir son pipeline. Afin de comprendre ce que les instructions viennent après la direction générale dans le flux de programme, il a besoin de savoir deux choses: (1) si la direction générale seront prises et (2) l'objectif de la direction générale. Essayant de se faire est appelée direction de la prévision, et c'est un problème difficile. Si le processeur devine correctement, le programme continue à pleine vitesse. Si, au contraire, le processeur devine de façon incorrecte, il a juste passé un peu de temps de calcul quelque chose de mal. Il a maintenant pour vider son pipeline et de le recharger avec des instructions de l'exécution correcte de chemin. Bottom line: un grand gain de performance.
Ainsi, la raison pour laquelle si les déclarations sont cher est due à la branche mispredictions. C'est seulement au niveau le plus bas. Si vous écrivez du code de haut niveau, vous n'avez pas besoin de vous soucier de ces détails. Vous devez uniquement les soins à ce sujet si vous êtes à l'écriture extrêmement critiques des performances de code en C ou de l'assemblée. Si c'est le cas, l'écriture de la branche-gratuit code peut souvent être supérieure à code branches, même si plusieurs instructions sont nécessaires. Il y a quelques frais de la bit-se tourner les trucs que vous pouvez faire pour calculer des choses telles que abs()
, min()
, et max()
sans ramification.