Es gibt diese verwandte Frage: GCC: Wie unterscheidet sich march von mtune?
Die vorhandenen Antworten gehen jedoch nicht viel weiter als das GCC-Handbuch selbst. Höchstens erhalten wir:
Wenn Sie
-mtune
verwenden, generiert der Compiler Code, der funktioniert jeder von ihnen, aber wird Befehlssequenzen bevorzugen, die am schnellsten laufen die spezifische CPU, die Sie angegeben haben.
und
Die Option
-mtune=Y
stimmt den generierten Code so ab, dass er schneller auf Y ausgeführt wird auf anderen CPUs könnte es laufen.
Aber genau wie favorisiert der GCC eine bestimmte Architektur, wenn er building ist, während er trotzdem in der Lage ist, den Build auf anderen (normalerweise älteren) Architekturen auszuführen, wenn auch langsamer?
Ich kenne nur eine Sache (aber ich bin keine Informatikerin), die das könnte, und das ist ein CPU-Dispatcher. Es scheint jedoch nicht (für mich), dass mtune
hinter den Kulissen einen Dispatcher generiert und stattdessen ein anderer Mechanismus wahrscheinlich ist.
Ich fühle mich aus zwei Gründen so:
mtune
ist) und für cpuid
testen, um unterstützte Anweisungen zur Laufzeit zu erkennen, anstatt sich auf eine benannte Architektur zu verlassen zur Erstellungszeit bereitgestellt. Wie funktioniert es wirklich?
-mtune
erstellt keinen Dispatcher, er benötigt keinen. Wir teilen dem Compiler bereits mit, auf welche Architektur wir abzielen.
Aus den GCC-Dokumenten :
-mtune = CPU-Typ
Tune to cpu-type alles, was für den generierten Code gilt, außer ABI und dem
Satz von verfügbaren Anweisungen.
Dies bedeutet, dass GCC keine Anweisungen verwendet, die nur auf CPU-Typ 1 verfügbar sind, aber es wird Code generieren, der optimal auf CPU-Typ .
Um diese letzte Aussage zu verstehen, ist es notwendig, den Unterschied zwischen Architektur und Mikroarchitektur zu verstehen
Die Architektur beinhaltet eine ISA (Instruction Set Architecture), die nicht von -mtune
beeinflusst wird.
Die Mikroarchitektur ist, wie die Architektur in Hardware implementiert wird.
Für einen gleichen Befehlssatz (gelesen: Architektur) kann eine Codefolge aufgrund der internen Details der Implementierung optimal auf einer CPU (Lese-Mikroarchitektur), aber nicht auf einer anderen laufen.
Dies kann so weit gehen, dass eine Codesequenz nur auf einer Mikroarchitektur optimal ist.
Beim Generieren des Maschinencodes hat GCC oft einen Freiheitsgrad bei der Auswahl der Anweisungen und der zu verwendenden Variante.
Es wird eine Heuristik verwenden, um eine Folge von Anweisungen zu generieren, die schnell auf den gebräuchlichsten CPUs laufen, manchmal wird es eine 100% optimale Lösung für CPU x opfern, wenn das CPUs bestraft y , z und w .
Wenn wir -mtune=x
verwenden, optimieren wir die Ausgabe von GCC für CPU x und erzeugen damit einen Code, der auf der CPU 100% optimal ist (aus der GCC-Perspektive).
Betrachten Sie als konkretes Beispiel , wie dieser Code zusammengestellt wird :
%Vor%% ce_de% wird beim Targeting einer Skylake oder eines Core2 vektorisiert (wenn sich die Vektoren nicht überschneiden):
Himmelslake
%Vor%Core2
%Vor% Der Hauptunterschied besteht darin, wie ein a[i] += b[i];
-Register geladen wird, auf einem Core2 wird es mit zwei Ladevorgängen geladen, die xmm
und movlps
verwenden, anstatt einen einzelnen movhps
zu verwenden.
Der Ansatz mit zwei Lasten ist bei einer Core2-Mikroarchitektur besser. Wenn Sie sich die Agnator Fog-Befehlstabellen ansehen, sehen Sie, dass movups
in 4 Ups dekodiert wird und eine Latenz von 2 Zyklen hat, während jeder movups
ist 1 Uop und 1 Latenzzyklus.
Dies ist wahrscheinlich darauf zurückzuführen, dass 128-Bit-Zugriffe zu diesem Zeitpunkt in zwei 64-Bit-Zugriffe aufgeteilt wurden.
Auf Skylake ist das Gegenteil der Fall: movXps
ist besser als 2 movups
.
Also müssen wir eins holen.
Im Allgemeinen greift GCC auf die erste Variante zurück, weil Core2 eine alte Mikroarchitektur ist, aber wir können dies mit movXps
überschreiben.
1 Befehlssatz wird mit anderen Schaltern ausgewählt.
Tags und Links optimization gcc cpu-architecture instruction-set instructions