12
votes

Que peut faire un compilateur avec des informations de ramification?

Sur un Pentium moderne, il n'est plus possible de donner des indices de ramification au processeur qu'il semble. En supposant qu'un compilateur de profilage tel que GCC avec une optimisation guidée de profil gagnait des informations sur le comportement de ramification susceptible, que peut-il faire pour produire du code qui s'exécutera plus rapidement?

La seule option que je connaisse est de déplacer des branches improbables vers la fin d'une fonction. Y a-t-il autre chose?

mise à jour.

http://download.intel.com/products/processor/manual/325462.pdf - a> volume 2a, section 2.1.1 dit

"Les préfixes d'indice de branche (2eh, 3eh) permettent un programme de donner un indice au processeur sur le chemin de code le plus probable pour une branche. Utilisez ces préfixes uniquement avec des instructions de branche conditionnelle (JCC). Autre utilisation des préfixes d'indice de branche et / ou d'autres opcodes non définis avec des instructions Intel 64 ou IA-32 sont réservées; Une telle utilisation peut causer imprévisible comportement. "

Je ne sais pas si ces éléments ont en réalité un effet cependant.

sur l'autre section 3.4.1. de http: / /www.intel.com/content/dam/www/public/us/fr/documents/manuals/64-ia-32-Architecture-Optimization-Manual.pdf dit

" Les compilateurs génèrent du code qui améliore l'efficacité de la prédiction des succursales dans les processeurs Intel. L'intel Compilateur C ++ l'accomplit par:

  • Garder le code et les données sur des pages distinctes
  • Utilisation des instructions de déplacement conditionnel pour éliminer les branches
  • Code de génération compatible avec l'algorithme de prédiction de la branche statique
  • l'inlinisation, le cas échéant
  • déroulant si le nombre d'itérations est prévisible

    avec optimisation guidée de profil, le compilateur peut déposer des blocs de base pour éliminer les branches du plus des chemins fréquemment exécutés d'une fonction ou d'améliorer au moins leur prévisibilité. Besoin de prédiction des succursales ne pas être une préoccupation au niveau source. Pour plus d'informations, voir Documentation Intel C ++ Compiler. "

    http://cache-www.intel.com/cd/00 /00/40/60/406096_406096.PDF dit dans "Améliorations de performance avec PGO"

    " PGO fonctionne mieux pour le code avec de nombreuses branches fréquemment exécutées difficiles à prédire au moment de la compilation. Un exemple est le code avec une vérification de l'erreur intensive dans laquelle Les conditions d'erreur sont fausses la plupart du temps. Le code d'erreur d'erreur (froid) rarement exécuté peut être déplacé de manière à ce que la branche soit rarement prédite de manière incorrecte. Minimiser Le code à froid entrelacé dans le code fréquemment exécuté améliore le cache d'instructions comportement. "


0 commentaires

4 Réponses :


3
votes

S'il est clair qu'une boucle est rarement entrée, ou qu'elle itre normalement très peu de fois, le compilateur pourrait éviter de dérouler la boucle, comme cela peut donc ajouter beaucoup de complexité nuisible pour gérer les conditions de bord (nombre impair). itérations, etc.). Vectorisation, en particulier, devrait être évité dans de tels cas.

Le compilateur peut réorganiser les tests imbriqués, de sorte que celui qui entraîne le plus souvent une coupe courte puisse être utilisé pour éviter d'effectuer un test sur quelque chose avec un taux de réussite de 50%.

L'allocation de registre peut être optimisée pour éviter d'avoir un registre de force de bloc de bloc rarement utilisé dans le cas commun.

Ce ne sont que quelques exemples. Je suis sûr qu'il y en a d'autres que je n'ai pas pensé.


1 commentaires

Savez-vous quels compilateurs font réellement ces choses? Par exemple, GCC?



2
votes

En plus du haut de ma tête, vous avez deux options.

Option n ° 1: informez le compilateur des indices et laissez le compilateur organiser le code de manière appropriée. Par exemple, GCC prend en charge les éléments suivants ... p> xxx pré>

si vous les mettez sous forme macro comme ... p> xxx pré> ... Vous pouvez maintenant les utiliser comme ... p>

x = -(a < b);   /* x = -1 if a < b, x = 0 if a >= b */
x &= (C - D);   /* x = C - D if a < b, x = 0 if a >= b */
x += D;         /* x = C if a < b, x = D if a >= b */


1 commentaires

Merci. Ma question est de savoir comment l'option 1 est-elle traduite en montage sur un Pentium moderne.



1
votes

Il peut faire tomber l'automne (c'est-à-dire le cas où une branche n'est pas prise) le chemin le plus utilisé. Qui a deux grands effets:

  1. Seulement 1 branche peut être prise par horloge, ou sur certains processeurs même par 2 horloges, donc s'il y a une autre branche (il y a généralement, la plupart du code qui compte est dans une boucle), une branche prise est une mauvaise nouvelle, une branche non prise de moins.
  2. Lorsque le prédicteur de la branche est faux, le code qu'il doit exécuter est plus susceptible d'être dans le cache de code (ou du cache μOP, le cas échéant). Si ce n'était pas, cela aurait été un double-whammy de redémarrer le pipeline et attendre un cache manquant. C'est moins un problème dans la plupart des boucles, car les deux côtés de la branche sont susceptibles d'être dans le cache, mais il entre en jeu dans de grandes boucles et autres code.

    Il peut également décider de décider de faire si la conversion en fonction de meilleures données qu'une hypothèse heureuse. Si-conversions peut sembler «toujours une bonne idée», mais ils ne sont pas «souvent une bonne idée». Si la branche de la mise en œuvre de la ramification est très bien prédite, le code IF-converti peut bien être plus lent.


1 commentaires

"Faire tomber le chemin le plus utilisé", c'est bien sûr déplacer du code autour. Exemple: "si (x <0) x = -x; étiquette: déclaration;", et x devraient être presque jamais négatifs. Nous déplacons le code "x = -x; suivi de" L'étiquette goto; "" Quelque part loin, puis changez le code d'origine en "si (x <0) goto farwaycode; étiquette: déclaration;" Maintenant, le code a changé de manière à ce que la branche conditionnelle ne soit presque jamais prise.



7
votes

Il existe deux sources possibles pour les informations souhaitées:

  1. Il y a le manuel du développeur de logiciels Intel 64 et IA-32 (3 volumes). C'est un énorme travail qui a évolué depuis des décennies. C'est la meilleure référence que je connaisse sur beaucoup de sujets, y compris le point flottant. Dans ce cas, vous souhaitez vérifier le volume 2, la référence de l'instruction.
  2. Il y a le manuel de référence d'optimisation Intel 64 et IA-32 Architectures. Cela vous indiquera quelque peu de brefs termes à quoi attendre de chaque microarchitecture.

    Maintenant, je ne sais pas ce que vous entendez par un processeur "Pentium moderne", c'est 2013, non? Il n'y a plus aucun Pentiums ...

    L'ensemble d'instructions prend en charge le traitement du processeur si la succursale devrait être prise ou non prise par un préfixe dans les instructions de la branche conditionnelle (telles que JC, JZ, etc.). Voir Volume 2A de (1), section 2.1.1 (de la version que j'ai) Préfixes d'instructions. Il y a les préfixes 2E et 3E pour non pris et pris respectivement.

    quant à savoir si ces préfixes ont effectivement un effet, si nous pouvons obtenir cette information, il s'agira d'un manuel de référence d'optimisation, la section de la microarchitecture que vous souhaitez (et je suis sûr que ce ne sera pas le Pentium).

    Outre l'utilisation de ceux-ci, il existe une section entière sur le manuel de référence d'optimisation à ce sujet, la section 3.4.1 (de la version que j'ai).

    Cela n'a aucun sens de reproduire qu'ici, car vous pouvez télécharger le manuel gratuitement. Brièvement:

    • Éliminer les branches à l'aide d'instructions conditionnelles (CMOV, SETCC),
    • Considérez l'algorithme de prédiction statique (3.4.1.3),
    • Inlinge
    • boucle déroulante

      En outre, certains compilateurs, GCC, par exemple, même lorsque CMOV n'est pas possible, exécutez souvent des arithmétiques biteux pour sélectionner l'une des deux choses distinctes calculées, évitant ainsi les branches. Cela le fait particulièrement avec les instructions SSE lors de la vectorisation des boucles.

      Fondamentalement, les conditions statiques sont les suivantes:

      • Les branches inconditionnelles devraient être prises (... type d'attente ...)
      • Les branches indirectes sont prévues à ne pas être prises (en raison d'une dépendance de données)
      • Les conditionnels en arrière sont prévus pour être pris (bien pour les boucles)
      • Les conditionnels avant sont prévus pour ne pas être pris

        Vous voulez probablement lire l'ensemble de la section 3.4.1.


5 commentaires

Merci. Je signifie bien sûr que les instructions Intel 64 ou AMD64 dans toutes les dernières versions sont pour les PC de consommation.


J'ai mis à jour la question. Cependant, je ne vois pas si 2eh ou 3eh a réellement un effet.


Il semble que l'on ne devrait pas utiliser ces notes de branche. "Le processeur Pentium® 4 a introduit de nouvelles instructions pour ajouter des astuces statiques aux branches. Il n'est pas recommandé d'utiliser un programmeur d'utiliser ces instructions, car ils ajoute légèrement à la taille du code et sont des indications statiques uniquement. Il est préférable d'utiliser un conditionnel branche de la manière que le prédicteur statique s'attend à ce que l'ajout de ces suites de branche. " Pris de logiciel.intel.com/ EN-US / Articles / ...


Un autre lien intéressant ... GODEVTOOL.COM/TESTBUGHELP/OPTIMISATION.HTM


@Marshall, je pense que "on ne devrait pas utiliser" est trop fort. Il semble que ce soit préférable d'utiliser les conditions statiques sur les conditionnels en avant et en arrière. Cependant, je voudrais imaginer qu'il existe des situations où le poids de cet octet supplémentaire dans la mémoire tampon de pré-correspond peut être compensé, par exemple, si vous utilisez uniquement ces conditions vous oblige à ajouter un saut supplémentaire (deux octets) ou si le code devient réorganisé défavorablement au préfetch (même section, 3.4). Comme toujours, les avantages et les inconvénients doivent être pondérés.