Compileroptimierungen
-
Hallo allerseits!
Mich würde mal interessieren, welche Optimierungen ein C++-Compiler so durchführen kann. Zum Beispiel:
- Welche Rechnungen werden zur Compilezeit ausgewertet? Nur Integerarithmetik (beliebiger Komplexität?) oder auch sowas wie
double a = 2.0 * 3.14;oder gar
double sqrt2 = std::sqrt(2.0)?
- Unter welchen Voraussetzungen werden
for-Schleifen durchmemset/memcpyersetzt? - Strippen unerreichbarer Codeteile? Wie komplex dürfen die Bedingungen hierfür sein, damit der Compiler das noch checkt?
- ...
Habe schon Google bemüht, aber nicht wirklich was gefunden. Falls jemand ein paar gute Links zu dem Thema kennt oder direkt was dazu schreiben möchte, würde ich mich sehr darüber freuen.

Natürlich werden diese Optimierungen Compiler-spezifisch sein. In erster Linie interessiert mich der MS VC++ aber auch die Unterschiede (zum Beispiel zum g++) wären sicherlich interessant.
Grüße,
bloops
-
selber ausprobieren
-
Alle Rechenoperationen mit Literalen sollte ein Compiler direkt ausrechnen und nur noch das Endergebnis verwenden.
Allerdings kann es sein, daß er Teilausdrücke (bzgl. mathematischer Umformungen) nicht berücksichtigt, z.B. bei "10.0 * x / 2.0".Und bzgl. Optimierung von eingebauten Funktionen heißt das Stichwort: Intrinsic Functions (http://de.wikipedia.org/wiki/Intrinsic_Funktions)
Und memset/memcpy sind nur für große Datenmengen wirklich optimiert, da am Anfang und Ende eines Datenblocks noch jeweils auf die verschiedenen Alignments geprüft wird.
Und zuletzt bzgl. Ausziehen - ich mein natürlich 'Strippen'
:
da werden wohl nur statische Checks durchgeführt, d.h. à la... if(true) // oder ein anderer Ausdruck, der sich zu true optimieren läßt return; // strip it ...
-
Allerdings kann es sein, daß er Teilausdrücke (bzgl. mathematischer Umformungen) nicht berücksichtigt, z.B. bei "10.0 * x / 2.0".
Was auch vollkommen richtig wäre, dies nicht weg zu optimieren. Schließlich könnte da innerhalb der Fließkommaarithmetik etwas anderes rauskommen, als wenn man 5.0 * x rechnet.
-
Egal welcher Compiler, man versucht zunächst den Code selbst zu optimieren. Ob der Compiler dann mehr machen kann, bleibt seine Angelegenheit. Willst du mehr, dann musst du auf Assembler herunter steigen. Nichts anderes kann der Compiler für dich machen. Viel Spass beim Herauskitzeln von einigen Millisekunden weniger!

-
Aber bitte keine "premature optimization"!!!
-
Willst du mehr, dann musst du auf Assembler herunter steigen.
Ich behaupte, ein Nicht-Experte optimiert auf jeden Fall schlechter als ein Compiler.
-
Icematix schrieb:
Ich behaupte, ein Nicht-Experte optimiert auf jeden Fall schlechter als ein Compiler.
Volle Zustimmung. Also ist die Frage Quatsch, man kann seine Mühe besser in der Optimierung seines eigenen Code verwenden!
-
Zum Beispiel Variablen/Objekte erst deklarieren, wenn sie gebraucht werden, hilft dem Compiler ziemlich.
Dann eben wann immer Möglich Referenzen auf Objekte arbeiten anstatt sie zu kopieren etcGibt es eigentlich gute Online-Literatur zu dem Thema Quellcode-Optimierung?
-
Icematix schrieb:
Zum Beispiel Variablen/Objekte erst deklarieren, wenn sie gebraucht werden, hilft dem Compiler ziemlich.
Dann eben wann immer Möglich Referenzen auf Objekte arbeiten anstatt sie zu kopieren etcconstverwenden, wo sinnvoll und möglich. Das ermöglicht dem compiler den Code unter bestimmten Bedingungen umzustellen, so dass er schneller wird. z.B. durch das Zusammenfassen von Gleitkommaoperationen, um eine bessere Auslastung der Vektoreinheit (SSE, Altivec) des Prozessors zu erreichen.Wenn es Möglich ist, sollte man auf optimierte Bibliotheken, wie BLAS oder liboil verwenden. Da hat sich schon jemand die Arbeit gemacht, bestimmte Operationen zu optimieren. Wenn dann noch Operationen übrig bleiben, die nicht von diesen Bibliotheken abgedeckt sind, kann man (wenn man es denn kann) noch mit Assembler optimieren.
ABER: Bevor man das macht. Auf jeden Fall den Code erstmal korrekt haben. Und dann erstmal ein paar Opimierungsparameter vom Compiler durchprobieren!
-
ProgChild schrieb:
Icematix schrieb:
Zum Beispiel Variablen/Objekte erst deklarieren, wenn sie gebraucht werden, hilft dem Compiler ziemlich.
Dann eben wann immer Möglich Referenzen auf Objekte arbeiten anstatt sie zu kopieren etcconstverwenden, wo sinnvoll und möglich. Das ermöglicht dem compiler den Code unter bestimmten Bedingungen umzustellen, so dass er schneller wird.http://www.gotw.ca/gotw/081.htm
It's a common belief that const-correctness helps compilers generate tighter code. Const is indeed a Good Thing, but the point of this issue of GotW is that const is mainly for humans, rather than for compilers and optimizers.
-
Icematix schrieb:
Gibt es eigentlich gute Online-Literatur zu dem Thema Quellcode-Optimierung?
Weiss nicht, habe noch nicht gesucht. Das Thema ist aber so alt wie die Programmierung selbst. Ein paar Regeln sind schon genannt. Man kann entweder nach Laufzeit oder nach Speicherbedarf optimieren. Nach Speicherbedarf spielt heute meist keine grosse Rolle mehr. Noch ein paar Regeln zur Laufzeit hinzu:
- Zeigerarithmetik nutzen
- Multiplikation ist schneller als pow(). Beispiel a*a statt pow(a,2)
- Mehrdimensionale Arrays in der Reihenfolge der Speicherung bearbeiten
- Grössere Datentypen wie long und double nur verwenden, wenn sie tatsächlich nötig sind
- In Schleifen redundanten Code vermeiden, also nicht mehrfach dasselbe berechnen
Alle Möglichkeiten zur Optimierung lohnen aber nur, wenn dabei signifikante Unterschiede in der Laufzeit heraus kommen. Drei Tage am Code pfeilen für vielleicht 10 Millisekunden ist unsinnig.
-
Th69 schrieb:
Aber bitte keine "premature optimization"!!!
wo ist eigentlich volkard?
-
das Beste, worüber ich die letzte Zeit gestöbert bin, kommt von fefe (CCC), z.B.
-
Superlexx schrieb:
das Beste, worüber ich die letzte Zeit gestöbert bin, kommt von fefe (CCC), z.B.
Das beste da sind die letzten 2 Sätze
If you do an optimization, test it on real world data.
If it’s not drastically faster but makes the code less readable: undo it.
-
Th69 schrieb:
Aber bitte keine "premature optimization"!!!
Das war mein Part

Ansonsten kann ich dir nur folgende Tipps geben:
- Auswahl des passenden Algorithmus
- Parameterübergabe call-by-reference statt call-by-value
- Ausnutzen von Spracheigenschaften wie return value optimization
- Benutzen von Funktoren statt Funktionspointern in SchleifendurchläufenWas Berniebutt geschrieben hat stimmt auch nur teilweise, für Ganzkommazahlen solltest du den Datentyp benutzen, der genau der Breite des CPU Datenbus entspricht. Bei allen anderen Datentypen muss der Prozessor halbe/viertel/doppelte Datenwörter schreiben, was zusätzliches Maskieren bedeuten kann
Die FPU kann mit double schneller rechnen als mit float (vermutlich aus den gleichen Gründen wie oben), daher für Fliesskommaoperationen lieber double als float benutzen. Aber das ist alles CPU spezifisch und kann sich von Plattform zu Plattform ändern.
-
DocShoe schrieb:
- Parameterübergabe call-by-reference statt call-by-value
Ich mag solche allgemein formulierten Regeln nicht besonders. Auf nem 32-Bit system z.B. ist es völlig schnuppe ob du einen Zeiger oder gleich den integer selbst übergibst. Aber das nur als Beispiel.
-
In dem Artikel heißt es:
Use mul instead of shift: 5 cycles penalty.
Conditional branch mispredicted: 10 cycles.
Cache Miss to main memory: 250 cycles.Das erste verstehe ich. Aber was will er mit den anderen zwei Sätzen aussagen?
-
asdfasd schrieb:
In dem Artikel heißt es:
Use mul instead of shift: 5 cycles penalty.
Conditional branch mispredicted: 10 cycles.
Cache Miss to main memory: 250 cycles.Das erste verstehe ich. Aber was will er mit den anderen zwei Sätzen aussagen?
Branch predictor: Es ist günstiger, wenn if-Abfragen in Schleifen möglichst oft hintereinander das gleiche Ergebnis haben.
Cache miss: Kann zwei Ursachen haben:
Zu große Codesegmente in einer Schleife (das ist die dunkle Seite von inline).
Oder zu wildes Herumspringen im Arbeitspeicher. Es ist günstiger, Speicheradressen möglichst oft nacheinander zu benutzen. Und es ist günstiger Speicheradressen möglichst in durchgehender (oder zumindest vorhersehbarer) Reihenfolge zu benutzen.
-
Und noch ein Vortrag von ihm, diesmal ausführlicher:
http://www.linux-kongress.org/2009/slides/compiler_survey_felix_von_leitner.pdf