2010-09-13 4 views
36

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

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 notes spécifiques du compilateur? (par exemple __builtin_expect on GCC)

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

+0

Je me demande si cela pourrait être quelque chose C++ 0x attributs à coller sur les conditions de 'if'? Comme 'if ([[improbable]] probability_condition) {...}'? Actuellement, la syntaxe ne le permet pas. Il * autorise * cependant 'if ([[improbable]] bool b = ...) {}'. Peut-être que l'on pourrait en abuser :) –

+4

Le code GNU contient une quantité ridicule de courrier indésirable 'if (probable (...))' dans un code complètement non critique, et c'est vraiment mauvais pour l'OMI. D'une part, il ne se lit pas naturellement en anglais - il semble que «si cette condition est susceptible d'être vraie» au lieu de «si cette condition est vraie, ce qui est probable». Et pour un autre, c'est juste un fouillis. Sauf si vous avez beaucoup de conditions critiques de performance qui ne seront pas compilées à 'cmov' ou similaire, ignorez simplement les indices de prédiction de branche. –

+0

@R .. Je pense que je comprends pourquoi le noyau Linux est jonché de 'if (improbable (...))'. Ils préfèrent les sorties anticipées qui facilitent le suivi du code. Si elles ne le faisaient pas, la prédiction de branchement statique échouerait toujours. –

Répondre

25

La forme canonique pour faire une prédiction de branchement statique est que if est prédits non ramifié (par exemple toutes les clauses if est exécutée, non else), et boucles et en arrière-goto s sont prises. Donc, ne mettez pas le cas courant dans else si vous prévoyez une prédiction statique significative. Se déplacer dans une boucle inachevée n'est pas aussi facile. Je n'ai jamais essayé, mais je suppose que mettre une clause else devrait fonctionner de manière assez portable.

De nombreux compilateurs prennent en charge une forme de , mais il sera toujours nécessaire de le protéger avec une sorte de #if pour protéger les autres compilateurs.

Les conseils de prédiction de branchement peuvent théoriquement exprimer une description complète de la transformation du graphe de contrôle de flux d'un programme et organiser les blocs de base dans la mémoire exécutable ... il y a donc une variété de choses à exprimer .

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

+0

Et VS a PGO aussi, donc c'est un gagnant-gagnant. :) – GManNickG

1

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

if (!(someExpression)) 

Mais le compilateur devrait traiter cela également.

7

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

Alors le mieux que vous pouvez faire sans extensions spécifiques au compilateur est organiser votre code de telle sorte que vos compilateurs vont "faire le bon choix" sans aide. Mais si vous voulez être sûr, tapez sur les extensions du compilateur. (Vous pouvez essayer les abstraire derrière le préprocesseur, de sorte que votre code reste portable.)

+4

Il y a beaucoup de précédents pour le langage fournissant des conseils d'optimisation, cependant ('inline',' restrict', 'register'). Certains sont plus pointus que d'autres sur les compilateurs modernes. Peu importe si une mise en œuvre particulière en fait quelque chose avec eux: s'il y a une chance raisonnable de faire quelque chose d'utile, alors ce serait une bonne fonctionnalité. Je pense que la prédiction de branchement statique ne répond pas à ce critère, donc je ne pense pas que ce soit un mauvais choix de le laisser de côté. C'est un jugement sur le fond de l'affaire, cependant, pas tout à fait "nous ne nous soucions pas de l'optimisation, jamais". –

+0

@Steve: Oui, je suppose que je les ignore automatiquement, donc je les oublie. Tu as raison. – GManNickG

+2

Je pense que «restreindre» vaut probablement une optimisation prématurée. Cela ne fera pas de mal, cela pourrait faire beaucoup de bien en empêchant les dépendances de stockage/chargement horribles, et où il s'applique c'est probablement une exigence documentée (comme dans 'memcpy') si cela est reflété dans la source ou non. Les autres (et en C++ 03), je suis d'accord avec ton retentissant "meh" :-) –

15

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 verra la commande "jmp p2" en avant, et chargera le code p2 dans le pipeline.

Si A est faux, le "code! A" peut ne pas être dans le pipleline, donc il peut être plus lent.

Conclusions:

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

:

evaluate(A) 

do more stuff 

if (A) 
    ... 
+0

l'ai eu! S'il vous plaît garder le code «si» dans les accolades pls-même si sa seule ligne. C'est un peu confus autrement! – Ayyappa

+0

« essayer d'évaluer un plus tôt possible, afin que la CPU peut dynmically optimiser le pipeline. » - Pouvez-vous s'il vous plaît fournir quelques indications pour cette déclaration? Je veux savoir comment ça va le faire. – Ayyappa

+0

Beaucoup d'informations ici: http://download.intel.com/design/pentiumii/manuals/24281603.pdf –

1

Quel est le problème avec la vérification d'un compilateur spécifique via #ifdef et cacher ces choses derrière une macro personnalisée? Vous pouvez #define pour étendre à l'expression simple dans les cas où vous n'avez pas un 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 supporte via une fonction intrinsèque.

+0

J'ai fait cela. Avec plus de deux ou trois compilateurs, cela peut devenir un vrai désordre, si différents compilateurs utilisent une syntaxe différente. –