Zusammenfassung mehrerer Haltungen, die bei der Linux-Kompilierungsoptimierung beherrscht werden müssen

Zusammenfassung mehrerer Haltungen, die bei der Linux-Kompilierungsoptimierung beherrscht werden müssen

01. Kompilierungsoptionen und Kernelkompilierung

Der Linux-Kernel (Englisch: Linux-Kernel) ist ein Computer-Betriebssystemkernel, der in der Programmiersprache C und Assembler geschrieben ist, dem POSIX-Standard entspricht und unter der GNU General Public License veröffentlicht wurde. Technisch gesehen ist Linux nur ein Kernel. „Kernel“ bezieht sich auf eine Systemsoftware, die eine Hardwareabstraktionsschicht, Festplatten- und Dateisteuerung, Multitasking und andere Funktionen bereitstellt.

Zunächst einmal wissen wir alle, dass der Linux-Kernel nicht kompiliert werden kann, wenn er mit O0 kompiliert wurde. Der Linux-Kernel wird entweder mit O2 oder Os kompiliert. Dies ist aus dem Linux-Makefile ersichtlich:

Wenn Sie wählen

CONFIG_CC_OPTIMIZE_FOR_SIZE

Es wird Os sein, andernfalls wird es O2 sein.

Tatsächlich sind O2 und Os eine Sammlung einiger Optimierungsoptionen:

gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts

gcc -c -Q -Os --help=optimizers > /tmp/Os-opts

Ersteres basiert eher auf Geschwindigkeitsoptimierung, während Letzteres eher auf kleinerer Größenoptimierung basiert. Vergleichen Sie die Schaltmöglichkeiten der beiden:

melde dich an /tmp/O2-opts /tmp/Os-opts

Der Unterschied ist erbärmlich gering:

Sowohl O2 als auch Os aktivieren kleine Inline-Funktionen und einmal aufgerufene Funktionen, aber -finline-functions ist in O2 deaktiviert und in Os aktiviert. In O2 ist optimize-strlen aktiviert, in Os ist diese Option jedoch deaktiviert. Die Bedeutung der jeweiligen Optionen erfährt man über "man gcc" (bei Fragen wendet man sich an man), beispielsweise nach der Suche nach inline-functions nach man gcc:

Von O0 über O1, O2 und O3 erfolgt eine schrittweise Erhöhung der Anzahl aktivierter Optimierungsoptionen:

Der Kernel kann nicht mit O0 kompiliert werden, da der Kernel selbst nicht für die Kompilierung mit O0 konzipiert ist. Sein Entwurf beinhaltet die Annahme, dass die Kompilierung optimiert wird. Lassen Sie uns dies anhand eines einfachen Beispiels veranschaulichen.

02. Ein einfaches Beispiel

Der folgende Code:

Bei der O0-Kompilierung wird der folgende Fehler gemeldet, der besagt, dass die Funktion f() nicht definiert ist:

$ gcc -O0 cc.c

cc.c:1:13: Warnung: „f“ verwendet, aber nie definiert [standardmäßig aktiviert]

 ungültig f(leer);

    ^

/tmp/ccTwwtHG.o: In der Funktion „main“:

cc.c:(.text+0x19): undefinierter Verweis auf „f“

collect2: Fehler: ld hat den Exit-Status 1 zurückgegeben

Aber bei der Kompilierung mit O2 gibt es kein Problem:

$ gcc -O2 cc.c

Der Grund hierfür liegt darin, dass O2 beim Kompilieren erkennt, dass a == 1 ist. Wenn also (a>2) nicht gilt, spielt es keine Rolle, dass f() nicht definiert ist.

Nach einer leichten Codeänderung:

O2 funktioniert derzeit nicht mehr:

$ gcc -O2 cc.c

/tmp/ccXiyBHn.o: In der Funktion „main“:

cc.c:(.text.startup+0x7): undefinierter Verweis auf „f“

collect2: Fehler: ld hat den Exit-Status 1 zurückgegeben

Anhand dieses Beispiels können Sie daher erkennen, warum derselbe Code mit O2 funktioniert, mit O0 jedoch nicht. Es gibt viel Code im Kernel, der vom Compiler optimiert werden soll.

3. Wir wollen nicht mehr inline

Aufgrund der Kompilierungsoptimierung werden einige Funktionen (z. B. kleine Funktionen und Funktionen, die im gesamten Projekt nur von einer Person aufgerufen werden) nicht explizit als Inline geschrieben, aber der Compiler optimiert sie für Inline. Dies führt zu einigen Problemen beim Debuggen, da das dieser Funktion entsprechende Symbol nicht gefunden werden kann.

An dieser Stelle können wir explizit angeben, dass wir bestimmte Funktionen nicht inline binden möchten:

Andernfalls werden die beiden oben genannten Funktionen möglicherweise automatisch vom Compiler inline geschrieben, auch wenn Sie in Ihrem Code nicht inline schreiben, da O2 und Os die entsprechenden Inline-Optionen aktivieren. Wenn wir Inline ablehnen möchten, können wir es mit noline markieren.

4. Ich möchte nicht optimiert werden

Wenn O1, O2, O3 und Os global aktiviert sind und wir keine Optimierung an einer einzelnen Funktion durchführen möchten, können wir die Funktion mit __attribute__((optimize("O0"))) ändern. Beispielsweise ändern wir den obigen Code, der mit O2 kompiliert werden kann, wie folgt:

Neukompilieren mit O2:

$ gcc -O2 cc.c

/tmp/cc8M338p.o: In der Funktion „main“:

cc.c:(.text+0x19): undefinierter Verweis auf „f“

collect2: Fehler: ld hat den Exit-Status 1 zurückgegeben

5. Fazit

Hier sind einige praktische Richtlinien:

  1. Versuchen Sie nicht, den Kernel mit O0 zu kompilieren, da dies nicht der tatsächlichen technischen Praxis entspricht und von der Mainstream-Linux-Community nicht gut unterstützt wird. Der Kernel ist für mehr Optimierungen auf O2/Os angewiesen.
  2. Achten Sie darauf, dass Ihr Code in O2 korrekt ist und der Code der Compileroptimierung standhält. Wenn beispielsweise O0 gut funktioniert, O2 jedoch nicht, sollten Sie versuchen, die Ursache selbst herauszufinden und die Assembly zu analysieren.
  3. Wenn Sie bei der globalen Optimierung die Optimierung für einen bestimmten Teil vermeiden möchten, können Sie versuchen, mit noinline, __attribute__((optimize("O0"))) usw. chirurgische Anpassungen vorzunehmen.

Zusammenfassen

Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Lernwert für Ihr Studium oder Ihre Arbeit hat. Wenn Sie Fragen haben, können Sie eine Nachricht hinterlassen. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM.

Das könnte Sie auch interessieren:
  • So dekomprimieren Sie mehrere Dateien mit dem Befehl „unzip“ in Linux
  • 30 unverzichtbare Linux-Befehlskenntnisse
  • Eine Methode zum Verbergen von Prozessen unter Linux und die dabei auftretenden Fallstricke
  • Detaillierte Erklärung der allgemeinen Verwendung der Linux-Befehle head und tail
  • Zusammenfassung der Unterschiede zwischen sudo, su und su - Befehle in Linux
  • So finden Sie schnell laufende Prozesse in Linux

<<:  JS realisiert die Kartenausgabe-Animation

>>:  Grafisches Tutorial zur kostenlosen Installationsversion von MySQL 5.7.17 winx64

Artikel empfehlen

Unterschied zwischen den Methoden querySelector und getElementById in JS

Inhaltsverzeichnis 1. Übersicht 1.1 Verwendung vo...

Vue implementiert Studentenverwaltungsfunktion

In diesem Artikelbeispiel wird der spezifische Co...

JS-Interviewfrage: Kann forEach aus der Schleife aussteigen?

Als mir diese Frage gestellt wurde, war ich unwis...

CentOS 8.0.1905 installiert ZABBIX Version 4.4 (verifiziert)

Zabbix Server-Umgebungsplattform Version: ZABBIX ...

React DVA-Implementierungscode

Inhaltsverzeichnis dva Verwendung von dva Impleme...

Xhtml-Sonderzeichensammlung

Name des Autors: &#160; no-break space = gesc...

Beispiel zum Festlegen der pseudostatischen WordPress-Eigenschaft in Nginx

Zitat aus Baidus Erklärung zu Pseudostatik: Pseud...

Implementieren eines Einkaufswagens mit nativem JavaScript

In diesem Artikel wird der spezifische JavaScript...

IIS7~IIS8.5 Löschen oder Ändern des Serverprotokollheaders Server

Anforderungen: Entfernen Sie HTTP-Antwortheader i...

Beispielcode zur Implementierung eines 3D-Zauberwürfels mit CSS

Lassen Sie uns heute einen einfachen 3D-Zauberwür...