Préfixe Intel x86 0x2e / 0x3e prédiction de branche réellement utilisée?
Dans les derniers processeurs Intel logiciel dev manuel, il décrit deux opcode préfixes:
Group 2 > Branch Hints
0x2E: Branch Not Taken
0x3E: Branch Taken
ceux-ci permettent la prédiction explicite de branche des instructions de saut (opcodes comme Jxx
)
je me souviens avoir lu il y a quelques années que sur x86 la prédiction explicite de branche était essentiellement un no-op dans le contexte de la prédiction de branche GCCS intrinsèques.
Je ne sais pas si ces indices de branche x86 sont une nouvelle fonctionnalité ou si ils sont pas coopératives dans la pratique.
quelqu'un peut clarifier ça?
(C'est-à-dire: les fonctions de prédiction de la branche GCC génèrent-elles ces indices de la branche x86? - et les processeurs Intel actuels ne les ignorent pas? - et quand est-ce arrivé?)
mise à jour:
j'ai créé un programme de test rapide:
int main(int argc, char** argv)
{
if (__builtin_expect(argc,0))
return 1;
if (__builtin_expect(argc == 2, 1))
return 2;
return 3;
}
désassemblage du suivant:
00000000004004cc <main>:
4004cc: 55 push %rbp
4004cd: 48 89 e5 mov %rsp,%rbp
4004d0: 89 7d fc mov %edi,-0x4(%rbp)
4004d3: 48 89 75 f0 mov %rsi,-0x10(%rbp)
4004d7: 8b 45 fc mov -0x4(%rbp),%eax
4004da: 48 98 cltq
4004dc: 48 85 c0 test %rax,%rax
4004df: 74 07 je 4004e8 <main+0x1c>
4004e1: b8 01 00 00 00 mov "151920920"x1,%eax
4004e6: eb 1b jmp 400503 <main+0x37>
4004e8: 83 7d fc 02 cmpl "151920920"x2,-0x4(%rbp)
4004ec: 0f 94 c0 sete %al
4004ef: 0f b6 c0 movzbl %al,%eax
4004f2: 48 85 c0 test %rax,%rax
4004f5: 74 07 je 4004fe <main+0x32>
4004f7: b8 02 00 00 00 mov "151920920"x2,%eax
4004fc: eb 05 jmp 400503 <main+0x37>
4004fe: b8 03 00 00 00 mov "151920920"x3,%eax
400503: 5d pop %rbp
400504: c3 retq
400505: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40050c: 00 00 00
40050f: 90 nop
Je ne vois pas 2E ou 3E ? Peut-être que gcc les a élidés pour une raison quelconque?
4 réponses
ces préfixes d'instructions n'ont aucun effet sur les processeurs modernes (rien de plus récent que le Pentium 4). Ils coûtent juste un octet d'espace de code, et donc, ne pas les générer est la bonne chose.
pour plus de détails, voir les manuels d'optimisation D'Agner Fog, en particulier 3. Microarchitecture: http://www.agner.org/optimize /
le "manuel de référence D'optimisation des Architectures Intel® 64 et IA-32" ne les mentionne plus dans le l'article sur l'optimisation des branches (section 3.4.1): http://www.intel.de/content/dam/doc/manual/64-ia-32-architectures-optimization-manual.pdf
ces préfixes sont une relique (inoffensive) de L'architecture de Netburst. Dans l'optimisation all-out, vous pouvez les utiliser pour aligner le code, mais c'est tout ce qui est bon pour aujourd'hui.
gcc a raison de ne pas générer le préfixe, car ils n'ont aucun effet pour tous les processeurs depuis le Pentium 4.
mais __builtin_expect
a d'autres effets, comme déplacer un chemin de code non prévu loin de la cache-points chauds dans le code ou décisions en cours d'exécution, il est donc encore utile.
alors que Pentium 4 est la seule génération qui respecte réellement les instructions d'indication de branche, la plupart des CPU ont une certaine forme de prédiction de branche statique , qui peut être utilisé pour atteindre le même effet. Cette réponse est un peu tangentielle à la question initiale, mais je pense que ce serait une information précieuse pour quiconque vient à cette page.
Le Intel optimisation guide et Agner Brouillard guide de l' (qui ont déjà été mentionnés ici) ont tous deux d'excellentes descriptions de cette caractéristique.
Intel a ceci à dire sur les générations plus récent que le Core 2 :
faire en sorte que le code de basculement suivant une branche conditionnelle soit la cible probable d'une branche avec une "forward target
donc branches conditionnelles qui sautent en avant dans le code sont prédits pour ne pas être pris, par l'algorithme de prédiction statique.
ceci est cohérent avec ce que GCC semble avoir généré en utilisant __builtin_expect
: le code" attendu " return 1
/ return 2
est placé dans les chemins non-pris des branches conditionnelles, qui seront statiquement prédites comme non-prises.
en outre:
Branches qui n'ont pas une histoire dans le La zone tampon cible de la branche est prédite à l'aide d'un algorithme de prédiction statique:
prédisent les branches inconditionnelles à prendre.
prédire branches indirectes à ne pas prendre.
ainsi dans les chemins non-pris "attendus" où GCC a placé inconditionnel jmp
s à la fin de la fonction, ces sauts seront statiquement prédites telles quelles (c.-à-d. non sautées).
Intel dit aussi:
faire de la chute-à l'aide de code à la suite d'une branche conditionnelle être le cas peu probable de la cible pour une branche avec une en arrière de la cible
ainsi les branches conditionnelles qui sautent en arrière dans le code sont prédites pour être prises, par l'algorithme de prédiction statique.
selon pour Agner Fog, la plupart des Pentiums suivent également cet algorithme:
sur PPro, P2, P3, P4 et P4E, une instruction de transfert de contrôle qui n'a pas été vue auparavant, ou qui n'est pas dans le tampon cible de la branche, est prédite tomber à travers si elle va en avant, et à prendre si elle va en arrière (par exemple une boucle). La prédiction statique prend plus de temps que la prédiction dynamique sur ces processeurs.
cependant, la noyau 2 famille (et Pentium M) a une politique tout à fait différente:
ces processeurs n'utilisent pas la prédiction statique. Le prédicteur fait simplement une prédiction aléatoire la première fois qu'une branche est vue, en fonction de ce qui se passe dans l'entrée BTB qui est assignée à la nouvelle branche. Il y a tout simplement une chance de 50% de faire la bonne prédiction de saut ou pas de saut, mais la cible prédite est correcte.
Comme AMD processeurs apparemment:
une branche est prédite non prise la première fois qu'elle est vue. Une branche est prévue toujours prise après la première fois qu'il a été pris. La prédiction dynamique n'est utilisée qu'après qu'une branche a été prise et non pas prise. Les préfixes d'indication de branche n'ont aucun effet.
il y a un facteur supplémentaire à considérer: les CPU aiment généralement exécuter dans un linéaire à la mode, donc même correctement prédites branches prises sont souvent plus coûteux que correctement prédites branches non prises.
Intel® 64 and IA-32 Architectures Software Developer's Manual -> Volume 2: Instruction Set Reference, A-Z - > Chapter 2: Instruction Format - > 2.1 Instruction Format for Protected Mode, real-address Mode, and virtual-8086 mode - > 2.1.1 Instruction Prefixes""
quelques microarchitectures antérieures ont utilisé ces derniers comme indices de branche, mais récente les générations n'ont pas et ils sont réservés pour l'usage futur indice.