Question

Est-il possible de faire portable conseils de prédiction de branchement? Prenons l'exemple suivant:

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

Est-ce différent que de le faire:

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

Ou est la seule façon d'utiliser des indications de spécifiques du compilateur? (Par exemple __builtin_expect sur GCC)

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

Était-ce utile?

La solution

La forme canonique pour faire une prédiction de branchement statique est que if est prédit non-ramifié (à savoir chaque clause if est exécutée, non else), et des boucles et en arrière-gotos sont prises. Alors, ne mettez pas le cas courant dans else si vous attendez la prédiction statique significative. Se déplacer une boucle est untaken pas aussi facile; Je ne l'ai jamais essayé mais je suppose que mettre une clause de else devrait fonctionner assez portably.

De nombreux compilateurs prennent en charge une certaine forme de #pragma unroll, mais il sera toujours nécessaire pour le garder avec une sorte de #if pour protéger d'autres compilateurs.

conseils de prédiction branche peut exprimer théoriquement une description complète de la façon de transformer le graphe flux de contrôle d'un programme et d'organiser les blocs de base dans la mémoire exécutable ... donc il y a une variété de choses à exprimer, et la plupart ne sera pas très portable.

GNU recommande dans la documentation __builtin_expect, l'optimisation guidée profil-est supérieure à des conseils, et avec moins d'effort.

Autres conseils

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 A » est déjà en cours. Le processeur se trouve la commande « jmp p2 » en avance, et charge le code p2 du pipeline.

Si A est faux, le « code! A » peut-être pas dans la construction de ce pipeline, donc il peut être plus lent.

Conclusions:

  1. Si faire (X) si X est plus probable qu'improbable! X
  2. essayer d'évaluer un plus tôt possible, afin que la CPU peut dynmically optimiser le pipeline.

:

evaluate(A)

do more stuff

if (A)
   ...

L'optimisation est en soi une chose du compilateur, vous devez utiliser le compilateur fonctionnalité pour l'aider. La langue elle-même ne se soucie pas des optimisations (ou mandat).

Donc, la meilleure que vous pouvez faire sans extensions spécifiques du compilateur est d'organiser votre code de telle manière où vos compilateurs « faire la bonne chose », sans aide. Mais si vous voulez être sûr, appuyez sur pour les extensions du compilateur. (Vous pouvez essayer les abstraire derrière le préprocesseur, de sorte que votre code reste portable.)

Juste être cohérent avec ce que vous faites. J'aime utiliser

if (!(someExpression))

Mais le compilateur doit traiter cette même.

Le mal de vérification Qu'est-ce avec un compilateur spécifique via #ifdef et cacher ces choses derrière une macro personnalisée? Vous pouvez #define à étendre à l'expression simple dans les cas vous ne disposez pas d'un compilateur qui prend en charge ces conseils d'optimisation. J'ai récemment fait quelque chose de similaire avec prélectures cache explicite qui prend en charge GCC via une fonction intrinsèque.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top