Häufige Missverständnisse über Compiler
(sbaziotis.com)Missverständnisse über Compiler-Optimierung
- Optimierung liefert ein optimales Programm?
- Compiler zielen nicht darauf ab, das optimale Programm zu erzeugen, sondern ein vereinfachtes Programm zu verbessern.
- Eine Optimierung der Codegröße ist möglich, aber eine Optimierung der Laufzeit ist schwierig – wegen der Schwierigkeit der Messung, des Fehlens optimaler Teilstrukturen und ungenauer Hardwaremodelle.
- Die Laufzeit ist im Gegensatz zur Codegröße nur schwer exakt messbar, wird von vielen Faktoren beeinflusst und besitzt keine optimale Teilstruktur. Selbst wenn zum Beispiel zwei Schleifen einzeln optimiert werden, kann es für die Optimierung des Gesamtprogramms notwendig sein, beide Schleifen zusammenzuführen. Außerdem ist Optimierung schwierig, weil es kein präzises Modell der Zielhardware gibt. So erzeugt goSLP zwar global optimierten SLP-Vektorisierungscode, doch wegen ungenauer Hardwaremodelle ist das erzeugte Programm nicht nur nicht optimal, sondern kann sogar langsamer als LLVM sein.
Missverständnisse im Zusammenhang mit Branch Prediction
- Branch Weights werden vom Branch Predictor der CPU verwendet?
- Auf der x86-Architektur erzeugen Compiler keine Branch Hints.
- Branch Weights werden für die Platzierung von Codeblöcken durch den Compiler verwendet. (Beispiel: Wenn ein Sprung wahrscheinlich ist, wird der Zielblock direkt unter dem aktuellen Block platziert, um die Lokalität des Instruction Cache zu verbessern.)
- In der neueren Intel-Redwood-Cove-Architektur haben Branch Hints wieder gewisse Relevanz, doch in der Praxis erzeugen Compiler solche Hints nur selten.
Missverständnisse über Optimierungsstufen
- -O3 erzeugt deutlich schnelleren Code als -O2?
- Bei Clang ist der Leistungsunterschied zwischen -O2 und -O3 nicht groß; bei GCC gibt es einen kleinen Unterschied, weil -O2 dort weniger aggressiv ist als bei Clang.
- -O3 berücksichtigt die Codegröße fast gar nicht, wodurch Probleme mit dem Instruction Cache entstehen können.
- Am besten prüft man das per Benchmarking.
Missverständnisse über Javascript-Interpreter und JIT-Compiler
- Javascript-Interpreter führen JIT-Kompilierung zur Laufzeit aus, weil man vorher nicht wissen kann, welche Pfade hot sind?
- Es reicht nicht aus, nur die hot paths zu kennen; auch Typinformationen werden benötigt.
- Da Typinformationen erst zur Laufzeit bekannt sind, kompilieren JIT-Compiler den Code zur Laufzeit.
Missverständnisse über die Beziehung zwischen Compiler und Interpreter
- Wenn es einen Compiler gibt, braucht man keinen Interpreter?
- Bei C/C++ ist ein Interpreter wenig nützlich, aber bei WebAssembly kann ein Interpreter Vorteile für einfachere Entwicklung und Nutzung, Debugging, Sicherheit usw. bieten.
Missverständnisse über die Middle-End-Stufe eines Compilers
- Die Middle-End-Stufe ist ziel-/plattformunabhängig?
- Im Fall von LLVM ist die Middle-End-Stufe nicht vollständig ziel-/plattformunabhängig.
Missverständnisse über Optimierung der Datenlokalität
- Compiler optimieren die Datenlokalität?
- Compiler optimieren die Lokalität des Instruction Cache, aber die Datenlokalität fast gar nicht.
- Die Optimierung der Datenlokalität erfordert große Änderungen am Code, und C/C++-Compiler können solche Änderungen nicht vornehmen.
- Um die Datenlokalität zu verbessern, sollte man Techniken wie data-oriented design verwenden.
Missverständnisse über Kompiliergeschwindigkeit
- -O0 sorgt für schnelles Kompilieren?
- -O0 erzeugt debugbaren und vorhersehbaren Code, garantiert aber nicht immer schnelles Kompilieren.
- Im Allgemeinen ist -O0 schneller als -O2, doch das kann je nach Projektgröße und Compiler variieren.
- Für schnelles Kompilieren kann man erwägen, die Standard-Compiler-Pipeline zu umgehen (z. B. TinyCC) oder LLVM IR direkt zu erzeugen.
Missverständnisse über die Kompiliergeschwindigkeit von Templates
- Templates sind langsam zu kompilieren?
- Dass C++-Templates langsam kompilieren, liegt am Kompiliermodell von C++.
- Templates selbst verlangsamen die Kompilierung nicht in großem Maß.
- Die Dlang-Standardbibliothek Phobos verwendet viele Templates, lässt sich aber schnell kompilieren.
Missverständnisse über den Nutzen separater Kompilierung
- Separate Kompilierung ist immer sinnvoll?
- Separate Kompilierung kann zu langen Link-Zeiten führen.
- Bei vielen Projekten liefern Unity Builds (der gesamte Code wird in eine einzige Datei eingebunden) eine bessere Performance.
- Unity Builds bieten Vorteile wie Whole-Program-Optimierung, schnellere Kompilierung und bessere Fehlerprotokolle.
- Fälle, in denen separate Kompilierung besser als Unity Builds ist, sind selten.
Missverständnisse über Link Time Optimization (LTO)
- Warum findet Link Time Optimization (LTO) überhaupt beim Linken statt?
- LTO wird durchgeführt, um das gesamte Programm zu optimieren.
- Theoretisch wäre es sinnvoller, die Whole-Program-Optimierung in der Middle-End-Stufe durchzuführen, doch wegen praktischer Probleme in C/C++-Build-Systemen (Schwierigkeit, Quelldateien zu finden und Aufrufbeziehungen zu ermitteln) geschieht sie zur Link-Zeit.
- Da der Linker alle Objektdateien finden kann, bettet der Compiler Zwischenrepräsentationen wie LLVM IR in die Objektdateien ein, damit der Linker darauf zugreifen kann.
Missverständnisse über Inlining-Optimierung
- Inlining ist hauptsächlich nützlich, weil es Funktionsaufrufe entfernt?
- Das Entfernen von Funktionsaufrufen ist zwar ein Vorteil, aber der größte Nutzen von Inlining besteht darin, andere Optimierungen zu ermöglichen.
- Inlining ermöglicht funktionsübergreifende Optimierungen.
- Wenn durch Inlining der Code mehrerer Funktionen zu einer Funktion zusammengeführt wird, lassen sich darauf bestehende Optimierungstechniken innerhalb einer Funktion anwenden.
Missverständnisse über die Rolle des inline-Keywords
- Hat das
inline-Keyword mit der Inlining-Optimierung zu tun?- Das C++-Keyword
inlinewurde ursprünglich als Hinweis für Optimierer verwendet, bedeutet aber seit C++98 „mehrfache Definitionen erlaubt“. - Im Fall von LLVM wird bei vorhandenem
inline-Keyword das Attributinlinehinthinzugefügt und der Inlining-Schwellenwert erhöht, doch der Einfluss ist nicht groß. - Wenn eine Funktion immer inlined werden soll, muss der
always_inline-Specifier verwendet werden.
- Das C++-Keyword
Missverständnisse über Lernmaterialien für Compiler
- LLVM ist der beste Compiler zum Lernen?
- LLVM hat zwar auch pädagogische Aspekte, ist aber komplex und umfangreich, weil es viele verschiedene Anwendungsfälle unterstützt.
- Zum Lernen der Compilerentwicklung ist es besser, zunächst kleinere und einfachere Compiler wie den Go-Compiler, LDC oder DMD anzusehen.
Missverständnisse über Undefined Behavior
-
Undefined Behavior ermöglicht nur Optimierungen?
- Undefined Behavior kann Optimierungen auch deaktivieren.
-
Compiler können Undefined Behavior einfach definieren?
- Compiler können Undefined Behavior definieren, aber das kann die Performance beeinflussen.
- Es wäre ideal, wenn Compiler jedes Undefined Behavior als Verhalten der Plattform definieren würden, doch in der Praxis ist das nicht einfach.
Missverständnisse über KI-basierte Codegenerierung
- Codegenerierung mit 99 % Genauigkeit ist in Ordnung?
- 99 % Genauigkeit bei von einem Compiler erzeugtem Code ist in der Praxis schwer nutzbar.
- Schon 1 % Fehler im Code verursacht große Schwierigkeiten bei Debugging und Wartung.
- In großen Projekten können 1 % Fehler sehr gravierende Probleme auslösen.
- Aktuelle LLMs sind im Vergleich zu Compilern außerdem viel zu langsam und daher für Online-Codegenerierung ungeeignet.
Noch keine Kommentare.