Betrachten Sie das folgende C-Programm:Statische Verzweigungsvorhersage/GCC Optimierung
void bar();
void baz();
void foo(int a) {
if (a) {
bar();
}
else {
baz();
}
}
Auf meinen x86-64-basierten Computern, die von GCC mit der -O1 Optimierungsstufe erzeugten Anweisungen geben:
0: sub $0x8,%rsp
4: test %edi,%edi
6: je 14 <foo+0x14>
8: mov $0x0,%eax
d: callq 12 <foo+0x12> # relocation to bar
12: jmp 1e <foo+0x1e>
14: mov $0x0,%eax
19: callq 1e <foo+0x1e> # relocation to baz
1e: add $0x8,%rsp
22: retq
wohingegen der -freorder Blöcke Optimierungsparameter Zugabe (in -O2 enthalten) in den Code schaltet:
0: sub $0x8,%rsp
4: test %edi,%edi
6: jne 17 <foo+0x17>
8: mov $0x0,%eax
d: callq 12 <foo+0x12> # relocation to baz
12: add $0x8,%rsp
16: retq
17: mov $0x0,%eax
1c: callq 21 <foo+0x21> # relocation to bar
21: add $0x8,%rsp
25: retq
was ist hauptsächlich eine Änderung von Sprung gleich zu Sprung nicht gleich. Ich weiß, dass bis zu Pentium 4 die statische Verzweigungsvorhersage auf einem bedingten Vorwärtszweig als vom Prozessor nicht angenommen betrachtet wurde (es scheint, dass die statische Vorhersage auf weiteren Intel-Prozessoren zufällig wurde), daher stelle ich mir vor, dass diese Optimierung damit zu tun hat.
dass Unter der Annahme, und was sich auf die jne optimierte Version, würde es bedeuten, dass die sonst Block in der Tat mehr betrachtet wird wahrscheinlich als die wenn Block im Programmablauf ausgeführt werden.
Aber was genau bedeutet das? Da es keine Annahme auf dem Wert in der Funktion durch den Compiler gibt, beruht diese Wahrscheinlichkeit nur auf den Schriften des Programmierers (wer könnte tatsächlich if (!a)
anstelle von if (a)
und invertierten Funktionsaufrufen verwendet haben).
Bedeutet dies, dass es als eine gute Praxis betrachtet werden sollte, zu behandeln, wenn bedingte Blöcke als Ausnahmefälle (und nicht die normale Ausführung Fluss)?
Das heißt:
if (!cond) {
// exceptional code
}
else {
// normal continuation
}
statt:
if (cond) {
// normal continuation
}
else {
// exceptional code
}
(natürlich könnte man return-Anweisung innerhalb relevanten Block lieber mit Eindrückungsgröße zu begrenzen).
Ja ... Aber die verschiedenen Rückgabepunkte hätten auch auf einer 'je' Version realisiert werden können. Und GCC tut dies, wenn/sonst Block reordering _consciously_ blockieren: im ursprünglichen Programm, das 'if (a) 'zu' if (! A) 'kompiliert zu genau das Gegenteil ändert: von einer' jne' (nicht optimierten) Version zu a 'je' (verzweigungsoptimierte) Version. Ich kann nicht glauben, dass GCC das ändert, nur um sich über mich lustig zu machen! :) – lledr
Ich denke in jedem Fall sollte __builtin_expect dabei helfen ;-). http://blog.man7.org/2012/10/how-much-do-builtinexpect-likely-and.html –