Est-il un compilateur astuce pour GCC pour forcer la direction de la prévision pour aller toujours une certaine façon?
Pour les architectures Intel, est-il un moyen de demander le compilateur GCC de générer du code qui a toujours des forces direction de la prévision d'une manière particulière dans mon code? L'Intel matériel de soutien, même cela? Quels sont les autres compilateurs ou matériels?
Je voudrais utiliser ce code C++ que je sais être le cas, je souhaite courir vite et ne se soucient pas le ralentir lorsque l'autre branche doivent être prises, même lorsqu'il a pris récemment la direction.
for (;;) {
if (normal) { //How to tell compiler to always branch predict true value?
doSomethingNormal();
} else {
exceptionalCase();
}
}
Comme suite à la question de Evdzhan Mustafa, l'astuce il suffit de spécifier un indice pour la première fois le processeur rencontre l'instruction, tous les branchements, fonctionne normalement?
- pourrait aussi lever une exception si quelque chose devient anormale (ce qui est le compilateur indépendant)
- Étroitement liés: probable()/peu probable() les macros dans le noyau Linux - comment fonctionnent-ils? Quel est leur intérêt?
Vous devez vous connecter pour publier un commentaire.
La bonne façon de définir probable/peu probable macros en C++11 est le suivant:
Lorsque ces macros définies de cette façon:
Qui peuvent changer le sens de
if
états et de briser le code. Considérons le code suivant:Et sa sortie:
Comme vous pouvez le voir, la définition de la probabilité à l'aide de
!!
comme une troupe debool
sauts de la sémantique deif
.Le point ici n'est pas que
operator int()
etoperator bool()
devraient être liés. Ce qui est une bonne pratique.Plutôt que l'utilisation de
!!(x)
au lieu destatic_cast<bool>(x)
perd le contexte de C++11 contextuelle conversions.switch
, merci. Le contexte de la conversion en cause ici est partucluar de typebool
et les cinq contextes spécifiques qui y sont énumérés, qui ne comprennent passwitch
contexte.(_Bool)(condition)
, parce que le C n'a pas la surcharge d'opérateur.(condition)
, pas!!(condition)
. Les deux sonttrue
après le changement de cette (testé avec g++ 7.1). Pouvez-vous construire un exemple qui fait illustre le problème que vous parlez quand vous utilisez!!
à booleanize?operator!()
etexplicit operator bool()
qui reviennent tous les deux la même valeur, de sorte que!!
serait de retour à l'opposé de la conversion explicite de type bool. Un tel code serait probablement pas passer un examen du code, cependant, car il ne respecte pas le principe de moindre surprise.operator!
serait-il le faire 😛GCC prend en charge la fonction
__builtin_expect(long exp, long c)
à fournir ce type de fonctionnalité. Vous pouvez consulter la documentation ici.Où
exp
est la condition utilisée etc
est la valeur attendue. Par exemple dans votre cas, vous voulezEn raison de l'ennui, de la syntaxe ceci est habituellement utilisé par la définition des deux macros personnalisées comme
juste pour faciliter la tâche.
L'esprit que:
constexpr
fonction?constexpr
la fonction peut remplacer cette macro. Il doit être dans leif
déclaration directement je crois. Même raisonassert
ne pourrait jamais être unconstexpr
fonction.constexpr
ne parle que de la valeur de la sémantique, pas l'inlining de mise en œuvre spécifique de l'assemblée); l'interprétation directe (pas de inline) du code est dénuée de sens. Il n'y a aucune raison d'utiliser une fonction pour cela.-O1
ou plus, produit par GCC équivalent de l'assemblée pour leconstexpr
fonction et intrinsèques. En va de même avec Clang. Et, vraiment, il n'y a pas de point dans la fourniture de ramification de l'information quand votre niveau d'optimisation est de moins de 1.__builtin_expect
lui-même est un indicateur d'optimisation, afin de faire valoir qu'une méthode de simplification de son utilisation dépend de l'optimisation... n'est pas convaincante. Aussi, je n'ai pas ajouter leconstexpr
rédacteur de devis pour le faire fonctionner dans la première place, mais pour le faire fonctionner dans des expressions constantes. Et oui, il y a des raisons de l'utilisation d'une fonction. Par exemple, je ne voudrais pas polluer mon espace de noms avec un joli petit nom commelikely
. J'aurais à utiliser, par exemple,LIKELY
souligner que c'est une macro et éviter les collisions, mais c'est tout simplement laid.gcc a long __builtin_attendent (longue exp, longtemps c) (accent mine):
Que les notes de documentation vous devez vous préférez utiliser le profil réel de la rétroaction et cet article montre un exemple pratique de cette et comment, dans leur cas, au moins, finit par être une amélioration à l'aide
__builtin_expect
. Voir aussi Comment utiliser le profil guidée des optimisations dans g++?.On peut aussi trouver une Le noyau Linux débutants article sur le kernel macros probable() et rare() qui utilisent cette fonctionnalité:
Note le
!!
utilisé dans la macro on peut trouver l'explication de ce phénomène dans Pourquoi utiliser !!(condition) au lieu de (condition)?.Tout simplement parce que cette technique est utilisée dans le noyau Linux ne veut pas dire qu'il fait toujours sens pour l'utiliser. Nous pouvons voir à partir de cette question que j'ai récemment répondu à différence entre les performances de la fonction lors du passage de paramètre en tant que moment de la compilation constante ou variable que beaucoup roulé à la main optimisations techniques ne fonctionnent pas dans le cas général. Nous avons besoin de code de profil attentivement afin de comprendre si une technique est efficace. De nombreuses techniques anciennes peuvent ne pas être pertinents moderne, avec des optimisations du compilateur.
Remarque, bien que les objets internes ne sont pas portables clang prend également en charge __builtin_attendent.
Également sur certains architectures il ne peut faire une différence.
Non, il ne l'est pas. (Au moins sur les processeurs x86 modernes.)
__builtin_expect
mentionné dans d'autres réponses influence la façon dont les gcc organise le code assembleur. Il n'a pas directement influence de la CPU branche prédicteur. Bien sûr, il y aura des effets indirects de la branche de prédiction causée par la réorganisation du code. Mais sur les processeurs x86 modernes il n'y a pas d'instruction qui indique au PROCESSEUR "assumer cette direction est/n'est pas prise".Voir cette question pour plus de détails: Intel x86 0x2E/0x3E Préfixe Direction de la Prévision effectivement utilisés?
Pour être clair,
__builtin_expect
et/ou de l'utilisation de-fprofile-arcs
peut améliorer les performances de votre code, à la fois en donnant des conseils à la direction de la prédicteur par le biais de la disposition du code (voir Optimisation des performances de x86-64 de l'assemblée - l'Alignement et la direction de la prévision), et aussi l'amélioration du cache de comportement en gardant "peu probable" le code de "probable" du code.__builtin_expect
.__builtin_expect
. Ce qui devrait être juste un commentaire. Mais il n'est pas faux, donc j'ai enlevé mon downvote.Que les autres réponses ont suffisamment suggéré, vous pouvez utiliser
__builtin_expect
pour donner le compilateur un indice sur la façon d'organiser le code assembleur. Comme les docs officielles, dans la plupart des cas, l'assembleur intégré dans votre cerveau ne sera pas aussi bon que celui conçu par l'équipe de GCC. C'est toujours mieux d'utiliser le profil réel de données afin d'optimiser votre code, plutôt que de deviner.Le long des lignes similaires, mais pas encore mentionné, est un GCC-de manière spécifique pour forcer le compilateur à générer du code sur un "froid" chemin d'accès. Cela implique l'utilisation de la
noinline
etcold
des attributs, qui font exactement ce que ils semblent comme ils le font. Ces attributs ne peuvent être appliquées à des fonctions, mais avec le C++11, vous pouvez déclarer inline lambda fonctions et ces deux attributs peuvent également être appliqué à des fonctions lambda.Bien que cela tombe toujours dans la catégorie générale d'un micro-optimisation, et ainsi, la norme s'applique—test ne suppose—j'ai l'impression que c'est plus utile que
__builtin_expect
. À peine toutes les générations de la x86 processeur de l'utilisation de la branche de prédiction des indices (référence), de sorte que la seule chose que vous allez être en mesure d'affecter de toute façon, est de l'ordre de l'assemblée le code. Puisque vous savez ce qui est de l'erreur de manipulation ou de "cas limite" de code, vous pouvez utiliser cette annotation pour s'assurer que le compilateur ne pourra jamais prédire une branche et il se lier à l'écart de la "hot" dans le code lors de l'optimisation de la taille.Exemple d'utilisation:
Encore mieux, GCC mettra automatiquement ignorer cela en faveur de profil de commentaires quand il est disponible (par exemple, lors de la compilation avec
-fprofile-use
).Voir la documentation officielle ici: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
__builtin_expect
n'. Il n'est pas inutile. Vous avez raison, lacold
attribut est également utile, mais vous sous-estimer l'utilité de__builtin_expect
je pense.__builtin_attendent peut être utilisé pour indiquer au compilateur que vous attendez d'une branche à l'aller. Cela peut influencer la façon dont le code est généré. Processeurs exécuter du code plus rapide de manière séquentielle. Donc si vous écrivez
le compilateur génère un code comme
Si votre indice est correcte, cela va exécuter le code, sans ramifications effectivement réalisées. Il va courir plus vite que la séquence normale, où chacun s'déclaration branche autour du code conditionnel et à l'exécution de trois branches.
Nouveaux processeurs x86 d'instructions pour les branches qui devraient être prises, ou pour les branches qui sont censés ne pas être pris (il y a une instruction préfixe; pas sûr de connaître les détails). Vous ne savez pas si le processeur utilise que. Il n'est pas très utile, parce que la direction de la prévision va gérer ce juste fine. Donc, je ne pense pas que vous pouvez réellement influencer la direction de la prédiction.
En ce qui concerne l'OP, il n'y a aucune façon de GCC pour dire que le processeur à toujours assumer la direction est ou n'est pas prise. Ce que vous avez est __builtin_attendent, ce qui fait ce que d'autres disent qu'il n'. En outre, je pense que vous ne voulez pas dire que le processeur de savoir si la branche est prise ou pas toujours. Aujourd'hui, les processeurs, tels que l'architecture Intel peut reconnaître assez complexe de motifs et de s'adapter efficacement.
Cependant, il ya des moments que vous voulez prendre le contrôle de savoir si par défaut une branche est prévu prises ou non: Lorsque vous connaissez le code sera appelé "froid" à l'égard de la ramification de la statistique.
Un exemple concret: la gestion des exceptions code. Par définition, le code de gestion qui va arriver exceptionnellement, mais peut-être lorsqu'il se produit une performance maximale est souhaitée (il y a peut être une erreur critique à prendre en charge hors dès que possible), donc vous pouvez contrôler le défaut de prévision.
Un autre exemple: Vous pouvez classer vos commentaires et de sauter dans le code qui gère le résultat de votre classification. S'il existe de nombreuses classifications, le processeur peut collecter des statistiques, mais les perdre parce que le même classement ne se fait pas assez vite et la prédiction de ressources sont consacrées à récemment appelé code. Je souhaite qu'il y aurait une primitive de dire que le processeur "merci de ne pas consacrer de prédiction des ressources de ce code," le chemin parfois, vous pouvez dire "ne pas mettre en cache ce".