Im unteren Programm erwarte ich, dass test1 wegen der abhängigen Anweisungen langsamer läuft. Ein Testlauf mit -O2 schien dies zu bestätigen. Aber dann habe ich es mit -O3 versucht und jetzt sind die Timings mehr oder weniger gleich. Wie kann das sein?
%Vor%Ich bekomme diese Ergebnisse:
%Vor% Weil in -O3
gcc die Datenabhängigkeit effektiv eliminiert wird, indem der Wert von a[i]
in einem Register gespeichert und bei der nächsten Iteration wiederverwendet wird, anstatt a[i-1]
zu laden.
Das Ergebnis entspricht mehr oder weniger dem:
%Vor% Was in -O2
kompiliert wurde, ergibt genau die gleiche Assembly wie Ihr Code, der in -O3
kompiliert wurde.
Die zweite Schleife in Ihrer Frage wird in -O3
entrollt, daher die Beschleunigung. Die beiden angewendeten Optimierungen scheinen nichts mit mir zu tun zu haben, der erste Fall ist schneller, weil gcc eine Ladeanweisung entfernt hat, die zweite, weil sie abgerollt wird.
In beiden Fällen glaube ich nicht, dass der Optimizer irgendetwas speziell zur Verbesserung des Cache-Verhaltens getan hat, beide Speicherzugriffsmuster sind leicht vorhersehbar durch die CPU.
Optimierer sind sehr hochentwickelte Software und nicht immer vorhersehbar.
Mit g ++ 5.2.0 und -O2 test1
und test2
wird zu ähnlichem Maschinencode kompiliert:
aber mit -O3
test1 bleibt mehr oder weniger ähnlich
und test2
explodiert zu einer Rolle, die wie eine nicht gerollte Version aussieht, indem xmm
registers verwendet wird und einen völlig anderen Maschinencode generiert. Die innere Schleife wird
und arbeitet mit mehreren Additionen für jede Iteration.
Wenn Sie das Verhalten eines bestimmten Prozessors testen möchten, ist es wahrscheinlich eine bessere Idee, direkt in einem Assembler zu schreiben, da C ++ - Compiler das ursprüngliche Quellprogramm stark umschreiben.
Tags und Links optimization c++