Compte tenu de la prédiction de branche et de l'effet des optimisations du compilateur, quel code a tendance à offrir des performances supérieures?
Notez que bRareExceptionPresent représente une condition inhabituelle. Ce n'est pas le chemin normal de la logique.
/* MOST COMMON path must branch around IF clause */
bool SomeFunction(bool bRareExceptionPresent)
{
// abort before function
if(bRareExceptionPresent)
{
return false;
}
.. function primary body ..
return true;
}
/* MOST COMMON path does NOT branch */
bool SomeFunction(bool bRareExceptionPresent)
{
if(!bRareExceptionPresent)
{
.. function primary body ..
}
else
{
return false;
}
return true;
}
optimization
theory
dyasta
la source
la source
Réponses:
Dans le monde d'aujourd'hui, peu importe, voire pas du tout.
La prédiction de branche dynamique (quelque chose à laquelle on a pensé pendant des décennies (voir une analyse des charges de travail du système Schemeson de prédiction de branche dynamique publiée en 1996)) est assez courante.
Un exemple de cela peut être trouvé dans le processeur ARM. Du Arm Info Centre on Branch Prediction
La question est alors "qu'est-ce que la prédiction de branche dynamique dans le processeur de bras?" La lecture continue de la prédiction de branche dynamique montre qu'elle utilise un schéma de prédiction à 2 bits (décrit dans l'article) construit des informations sur si la branche est fortement ou faiblement prise ou non prise.
Au fil du temps (et par temps je veux dire quelques passages à travers ce bloc) cela accumule des informations sur la direction que prendra le code.
Pour la prédiction statique , il examine la façon dont le code se présente et la façon dont la branche est faite sur le test - à une instruction précédente ou à une autre dans le code:
Comme mentionné par Sparky, cela est basé sur la compréhension que les boucles, le plus souvent, bouclent. La boucle se ramifie vers l'arrière (elle a une branche à la fin de la boucle pour la redémarrer en haut) - elle le fait normalement.
Le danger d'essayer de deviner le compilateur est que vous ne savez pas comment ce code va être compilé (et optimisé). Et pour la plupart, cela n'a pas d'importance. Avec la prédiction dynamique, deux fois par le biais de la fonction, il prédira un saut sur l'instruction de garde pour un retour prématuré. Si la performance de deux pipelines vidés est d'une performance critique, il y a d'autres choses à craindre.
Le temps qu'il faut pour lire un style sur l'autre est probablement plus important - rendre le code propre pour qu'un humain puisse le lire, car le compilateur va très bien, peu importe à quel point vous êtes désordonné ou idéalisé, vous écrivez le code.
la source
Ma compréhension est que la première fois que le CPU rencontre une branche, il prédira (si pris en charge) que les branches avant ne sont pas prises et les branches arrière le sont. La raison en est que les boucles (qui se ramifient généralement en arrière) sont supposées être prises.
Sur certains processeurs, vous pouvez indiquer dans l'instruction d'assemblage le chemin le plus probable. Les détails de cela m'échappent pour le moment.
En outre, certains compilateurs C prennent également en charge la prédiction de branche statique afin que vous puissiez indiquer au compilateur quelle branche est la plus probable. À son tour, il peut réorganiser le code généré, ou utiliser des instructions modifiées pour tirer parti de ces informations (ou même simplement les ignorer).
J'espère que cela t'aides.
la source
__builtin_expect
?