44 votes

Conseils de prédiction de branche portable

Existe-t-il un moyen portable de faire des conseils de prédiction de branche? Prenons l'exemple suivant:

   if (unlikely_condition) {
    /* ..A.. */
  } else {
    /* ..B.. */
  }
 

Est-ce différent de faire:

   if (!unlikely_condition) {
    /* ..B.. */
  } else {
    /* ..A.. */
  }
 

Ou est-ce la seule façon d'utiliser des astuces spécifiques au compilateur? (par exemple __builtin_expect sur GCC)

Les compilateurs traiteront-ils les conditions if différemment en fonction de l'ordre des conditions?

30voto

Potatoswatter Points 70305

La manière canonique pour ne statique de la direction de la prévision est qu' if est prévu non ramifié (c'est à dire chaque if clause est exécuté, pas else), des boucles et des arrière-gotos sont prises. Donc, ne mettez pas le cas courant en else si vous vous attendez statique de prédiction pour être significatif. Les déplacements untaken boucle n'est pas aussi facile; je n'ai jamais essayé, mais je suppose que mettre un else clause devrait fonctionner assez de façon portable.

De nombreux compilateurs soutien d'une certaine forme de #pragma unroll, mais il sera toujours nécessaire à la garde avec une sorte d' #if afin de protéger d'autres compilateurs.

Direction de la prévision conseils peuvent théoriquement exprimer une description complète de la façon de transformer un programme de contrôle de flux graphique et d'organiser les blocs de base dans la mémoire exécutable... alors il existe une variété de choses à exprimer, et la plupart ne seront pas très portable.

Comme GNU recommande dans la documentation pour l' __builtin_expect, le profil de l'optimisation orientée est supérieure aux indices, et avec moins d'effort.

21voto

Lior Kogan Points 8610

Dans la plupart des cas, le code suivant

if (a)
{
   ...
}
else
{
    ...
}

est en fait

evaluate(A)

if (!A)
{
   jmp p1
}

... code A

   jmp p2

p1:

... code !A

p2:

Notez que si A est vrai, "code" est déjà dans le pipeline. Le processeur va voir le "jmp p2" commande à l'avance, et les charger p2 code de la canalisation.

Si A est faux, le "code !Un" peut-être pas dans le pipleline, par conséquent, il peut être plus lente.

Conclusions:

  1. faire Si(X) si X est plus probable que les !X
  2. essayez d'évaluer le plus tôt possible, de sorte que le CPU peut dynmically optimiser le pipeline.

:

evaluate(A)

do more stuff

if (A)
   ...

7voto

GManNickG Points 155079

L'optimisation est intrinsèquement une chose du compilateur, vous devez donc utiliser la fonctionnalité du compilateur pour l'aider. Le langage lui-même ne se soucie pas (ni ne rend obligatoire) les optimisations.

Ainsi, le mieux que vous puissiez faire sans extensions spécifiques au compilateur est d'organiser votre code de telle manière que vos compilateurs "fassent la bonne chose" sans aide. Mais si vous voulez en être sûr, appuyez sur les extensions du compilateur. (Vous pouvez essayer de les résumer derrière le préprocesseur, afin que votre code reste portable.)

1voto

JonH Points 20454

Soyez juste cohérent avec ce que vous faites. J'aime utiliser

 if (!(someExpression))
 

Mais le compilateur devrait traiter cela également.

1voto

sellibitze Points 13607

Quel est le problème avec la vérification d'un compilateur spécifique via #ifdef et le masquage de ces choses derrière une macro personnalisée? Vous pouvez #define étendre à l'expression simple dans les cas où vous n'avez pas de compilateur qui prend en charge ces conseils d'optimisation. J'ai récemment fait quelque chose de similaire avec des préfixes de cache explicites que GCC prend en charge via une fonction intrinsèque.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X