Erzwinge Compiler, um seiteneffektelose Anweisungen nicht zu optimieren

8
___ answer1152379 ___
  

Ich möchte also sicherstellen, dass wenn ich profiliere, ich keine verzerrten Ergebnisse bekomme. Daher möchte ich sicherstellen, dass der Compiler keine output-Anweisungen

optimiert

Sie sind per Definition schief die Ergebnisse.

So beheben Sie das Problem, dass Sie versuchen, "Dummy" -Code zu schreiben, den Sie nur zum Testen geschrieben haben: Speichern Sie Ihre Ergebnisse für die Profilerstellung in einem globalen / statischen Array und drucken Sie ein Mitglied des Arrays an die Ausgabe am Ende des Programms. Der Compiler ist nicht in der Lage, out irgendwelche der Berechnungen zu optimieren, die Werte in das Array eingetragen haben, aber Sie erhalten immer noch andere Optimierungen, die er einsetzen kann, um den Code schnell zu machen.

    
___ answer1152574 ___

Die Zuweisung zu einer float -Variable sollte niemals wegoptimiert werden, damit Sie das gewünschte Ergebnis erhalten:

%Vor%     
___ answer1152717 ___

Was bei allen bisher verwendeten Compilern funktioniert hat:

%Vor%

Beachten Sie, dass dies die Ergebnisse verfälscht, boith-Methoden sollten in int schreiben.

fabs() sagt dem Compiler "der Wert darf ohne Ihre Nachricht aufgerufen werden", daher kann der Compiler die Berechnung nicht überspringen und das Ergebnis löschen. Um die Propagierung von Eingabekonstanten zu blockieren, müssen Sie sie möglicherweise auch über ein externes volatiles ausführen:

%Vor%

Dennoch können alle Optimierungen zwischen dem Lesen und dem Schreiben "mit voller Kraft" angewendet werden. Das Lesen und Schreiben in die globale Variable sind oft gute "FencePosts" beim Überprüfen der generierten Assembly.

Ohne den i += 10 kann der Compiler bemerken, dass ein Verweis auf die Variable niemals genommen wird, und somit bestimmen, dass er nicht flüchtig sein kann. Technisch gesehen, mit Link Time Code Generation, ist es vielleicht nicht genug, aber ich habe keinen Compiler gefunden, der aggressiv ist. (Für einen Compiler, der tatsächlich den Zugriff entfernt, müsste der Verweis an eine Funktion in einer zur Laufzeit geladenen DLL übergeben werden)

    
___ answer1152409 ___

Sie müssen nur zu dem Teil springen, in dem Sie etwas lernen und das veröffentlichte Intel CPU Optimierungshandbuch .

Diese stellen ganz klar fest, dass das Gießen zwischen float und int eine sehr schlechte Idee ist, da es einen Speicher vom int-Register zum Speicher benötigt, gefolgt von einem Laden in ein float-Register. Diese Vorgänge verursachen eine Blase in der Pipeline und verschwenden viele wertvolle Zyklen.

    
___ answer1152376 ___

Ein Funktionsaufruf verursacht ziemlich viel Overhead, also würde ich das sowieso entfernen.

Hinzufügen eines Dummy + = i; Das ist kein Problem, solange Sie dasselbe Bit im alternativen Profil behalten. (Also der Code, gegen den Sie es vergleichen).

Last but not least: asm-Code generieren. Auch wenn Sie in asm nicht codieren können, ist der generierte Code in der Regel verständlich, da er hinter Codenamen steht und C-Code kommentiert. So wissen Sie, was passiert und welche Bits behalten werden.

R

ps. habe das auch gefunden:

%Vor%

angeblich auch sehr schnell. Vielleicht möchten Sie dies auch profilieren. (obwohl es kaum portabler Code ist)

    
___ answer1152401 ___

In diesem Fall schlage ich vor, dass Sie die Funktion den ganzzahligen Wert zurückgeben:

%Vor%

Ihr Anrufcode kann sie dann mit einem Printf auswerten, um sicherzustellen, dass sie nicht optimiert wird. Stellen Sie außerdem sicher, dass sich float_to_int in einer separaten Kompilierungseinheit befindet, damit der Compiler keine Tricks spielen kann.

%Vor%

Vergleichen Sie dies jetzt mit einer leeren Funktion wie:

%Vor%

Was auch extern sein sollte.

Der Unterschied in den Zeiten sollte Ihnen eine Vorstellung von den Kosten geben, die Sie zu messen versuchen.

    
___ answer1153576 ___

Geben Sie den Wert zurück?

%Vor%

und dann können Sie auf der Aufrufseite alle Rückgabewerte zusammenfassen und das Ergebnis nach Abschluss des Benchmarks ausdrucken. Der übliche Weg, dies zu tun, ist irgendwie sicherzustellen, dass Sie vom Ergebnis abhängig sind.

Sie könnten stattdessen eine globale Variable verwenden, aber es scheint, als würde das mehr Cache-Misses erzeugen. In der Regel reicht es aus, den Wert einfach an den Aufrufer zurückzugeben (und sicherzustellen, dass der Aufrufer tatsächlich etwas damit macht).

    
___ answer1152387 ___

Ein Mikro-Benchmark um diese Aussage herum ist nicht repräsentativ für die Verwendung dieses Ansatzes in einem echten Szenario; Die umgebenden Anweisungen und ihre Auswirkung auf die Pipeline und den Cache sind im Allgemeinen genauso wichtig wie jede gegebene Anweisung in sich selbst.

    
___ tag123c ___ C ++ ist eine universelle Programmiersprache. Es wurde ursprünglich als Erweiterung von C entworfen und behält eine ähnliche Syntax, ist aber jetzt eine komplett andere Sprache. Verwenden Sie dieses Tag für Fragen zu Code, der mit einem C ++ - Compiler kompiliert werden soll. ___ answer1152517 ___

GCC 4 macht jetzt viele Mikrooptimierungen, die GCC 3.4 noch nie gemacht hat. GCC4 enthält einen Tree Vectorizer, der sich als sehr nützlich erweist, um SSE und MMX zu nutzen. Es verwendet auch die Bibliotheken GMP und MPFR, um bei der Optimierung von Aufrufen wie int dummy; , dummy += i usw. zu helfen, und optimiert solche Aufrufe für ihre FPU, SSE oder 3D Now! Äquivalente.

Ich weiß, dass der Intel-Compiler auch bei diesen Optimierungen sehr gut ist.

Mein Vorschlag ist, sich keine Gedanken über Mikrooptimierungen wie diese zu machen - auf relativ neuer Hardware (alles, was in den letzten 5 oder 6 Jahren gebaut wurde), sind sie fast völlig irrelevant.

Edit: Bei neueren CPUs ist der Befehl i der FPU weit schneller als ein Cast in %code% und Bitmaske, und der Befehl %code% wird im Allgemeinen schneller sein als die Vorberechnung einer Tabelle oder die Extrapolation einer Taylor-Reihe . Viele der Optimierungen, die Sie zum Beispiel in "Tricks of the Game Programming Gurus" finden würden, sind völlig unbegründet und könnten, wie in einer anderen Antwort ausgeführt, möglicherweise langsamer sein als Anweisungen auf der FPU und in SSE.

>

All dies ist auf die Tatsache zurückzuführen, dass neuere CPUs pipelined sind - Befehle werden dekodiert und an schnelle Recheneinheiten gesendet. Befehle laufen nicht mehr in Taktzyklen und sind empfindlicher für Cache-Misses und Inter-Instruction-Abhängigkeiten.

Lesen Sie die AMD- und Intel-Prozessor-Programmierhandbücher für alle wichtigen Details.

    
___ tag123optimierung ___ Optimierung ist der Akt der Verbesserung einer Methode oder eines Designs. In der Programmierung nimmt die Optimierung normalerweise die Form an, die Geschwindigkeit eines Algorithmus zu erhöhen oder die benötigten Ressourcen zu reduzieren. Eine weitere Bedeutung der Optimierung sind numerische Optimierungsalgorithmen. ___ qstnhdr ___ Erzwinge Compiler, um seiteneffektelose Anweisungen nicht zu optimieren ___
GManNickG 20.07.2009, 08:32
quelle

10 Antworten

4
___ answer1152379 ___
  

Ich möchte also sicherstellen, dass wenn ich profiliere, ich keine verzerrten Ergebnisse bekomme. Daher möchte ich sicherstellen, dass der Compiler keine output-Anweisungen

optimiert

Sie sind per Definition schief die Ergebnisse.

So beheben Sie das Problem, dass Sie versuchen, "Dummy" -Code zu schreiben, den Sie nur zum Testen geschrieben haben: Speichern Sie Ihre Ergebnisse für die Profilerstellung in einem globalen / statischen Array und drucken Sie ein Mitglied des Arrays an die Ausgabe am Ende des Programms. Der Compiler ist nicht in der Lage, out irgendwelche der Berechnungen zu optimieren, die Werte in das Array eingetragen haben, aber Sie erhalten immer noch andere Optimierungen, die er einsetzen kann, um den Code schnell zu machen.

    
___ answer1152574 ___

Die Zuweisung zu einer %code% -Variable sollte niemals wegoptimiert werden, damit Sie das gewünschte Ergebnis erhalten:

%Vor%     
___ answer1152717 ___

Was bei allen bisher verwendeten Compilern funktioniert hat:

%Vor%

Beachten Sie, dass dies die Ergebnisse verfälscht, boith-Methoden sollten in %code% schreiben.

%code% sagt dem Compiler "der Wert darf ohne Ihre Nachricht aufgerufen werden", daher kann der Compiler die Berechnung nicht überspringen und das Ergebnis löschen. Um die Propagierung von Eingabekonstanten zu blockieren, müssen Sie sie möglicherweise auch über ein externes volatiles ausführen:

%Vor%

Dennoch können alle Optimierungen zwischen dem Lesen und dem Schreiben "mit voller Kraft" angewendet werden. Das Lesen und Schreiben in die globale Variable sind oft gute "FencePosts" beim Überprüfen der generierten Assembly.

Ohne den %code% kann der Compiler bemerken, dass ein Verweis auf die Variable niemals genommen wird, und somit bestimmen, dass er nicht flüchtig sein kann. Technisch gesehen, mit Link Time Code Generation, ist es vielleicht nicht genug, aber ich habe keinen Compiler gefunden, der aggressiv ist. (Für einen Compiler, der tatsächlich den Zugriff entfernt, müsste der Verweis an eine Funktion in einer zur Laufzeit geladenen DLL übergeben werden)

    
___ answer1152409 ___

Sie müssen nur zu dem Teil springen, in dem Sie etwas lernen und das veröffentlichte Intel CPU Optimierungshandbuch .

Diese stellen ganz klar fest, dass das Gießen zwischen float und int eine sehr schlechte Idee ist, da es einen Speicher vom int-Register zum Speicher benötigt, gefolgt von einem Laden in ein float-Register. Diese Vorgänge verursachen eine Blase in der Pipeline und verschwenden viele wertvolle Zyklen.

    
___ answer1152376 ___

Ein Funktionsaufruf verursacht ziemlich viel Overhead, also würde ich das sowieso entfernen.

Hinzufügen eines Dummy + = i; Das ist kein Problem, solange Sie dasselbe Bit im alternativen Profil behalten. (Also der Code, gegen den Sie es vergleichen).

Last but not least: asm-Code generieren. Auch wenn Sie in asm nicht codieren können, ist der generierte Code in der Regel verständlich, da er hinter Codenamen steht und C-Code kommentiert. So wissen Sie, was passiert und welche Bits behalten werden.

R

ps. habe das auch gefunden:

%Vor%

angeblich auch sehr schnell. Vielleicht möchten Sie dies auch profilieren. (obwohl es kaum portabler Code ist)

    
___ answer1152401 ___

In diesem Fall schlage ich vor, dass Sie die Funktion den ganzzahligen Wert zurückgeben:

%Vor%

Ihr Anrufcode kann sie dann mit einem Printf auswerten, um sicherzustellen, dass sie nicht optimiert wird. Stellen Sie außerdem sicher, dass sich float_to_int in einer separaten Kompilierungseinheit befindet, damit der Compiler keine Tricks spielen kann.

%Vor%

Vergleichen Sie dies jetzt mit einer leeren Funktion wie:

%Vor%

Was auch extern sein sollte.

Der Unterschied in den Zeiten sollte Ihnen eine Vorstellung von den Kosten geben, die Sie zu messen versuchen.

    
___ answer1153576 ___

Geben Sie den Wert zurück?

%Vor%

und dann können Sie auf der Aufrufseite alle Rückgabewerte zusammenfassen und das Ergebnis nach Abschluss des Benchmarks ausdrucken. Der übliche Weg, dies zu tun, ist irgendwie sicherzustellen, dass Sie vom Ergebnis abhängig sind.

Sie könnten stattdessen eine globale Variable verwenden, aber es scheint, als würde das mehr Cache-Misses erzeugen. In der Regel reicht es aus, den Wert einfach an den Aufrufer zurückzugeben (und sicherzustellen, dass der Aufrufer tatsächlich etwas damit macht).

    
___ answer1152387 ___

Ein Mikro-Benchmark um diese Aussage herum ist nicht repräsentativ für die Verwendung dieses Ansatzes in einem echten Szenario; Die umgebenden Anweisungen und ihre Auswirkung auf die Pipeline und den Cache sind im Allgemeinen genauso wichtig wie jede gegebene Anweisung in sich selbst.

    
___ tag123c ___ C ++ ist eine universelle Programmiersprache. Es wurde ursprünglich als Erweiterung von C entworfen und behält eine ähnliche Syntax, ist aber jetzt eine komplett andere Sprache. Verwenden Sie dieses Tag für Fragen zu Code, der mit einem C ++ - Compiler kompiliert werden soll. ___ answer1152517 ___

GCC 4 macht jetzt viele Mikrooptimierungen, die GCC 3.4 noch nie gemacht hat. GCC4 enthält einen Tree Vectorizer, der sich als sehr nützlich erweist, um SSE und MMX zu nutzen. Es verwendet auch die Bibliotheken GMP und MPFR, um bei der Optimierung von Aufrufen wie %code% , %code% usw. zu helfen, und optimiert solche Aufrufe für ihre FPU, SSE oder 3D Now! Äquivalente.

Ich weiß, dass der Intel-Compiler auch bei diesen Optimierungen sehr gut ist.

Mein Vorschlag ist, sich keine Gedanken über Mikrooptimierungen wie diese zu machen - auf relativ neuer Hardware (alles, was in den letzten 5 oder 6 Jahren gebaut wurde), sind sie fast völlig irrelevant.

Edit: Bei neueren CPUs ist der Befehl %code% der FPU weit schneller als ein Cast in %code% und Bitmaske, und der Befehl %code% wird im Allgemeinen schneller sein als die Vorberechnung einer Tabelle oder die Extrapolation einer Taylor-Reihe . Viele der Optimierungen, die Sie zum Beispiel in "Tricks of the Game Programming Gurus" finden würden, sind völlig unbegründet und könnten, wie in einer anderen Antwort ausgeführt, möglicherweise langsamer sein als Anweisungen auf der FPU und in SSE.

>

All dies ist auf die Tatsache zurückzuführen, dass neuere CPUs pipelined sind - Befehle werden dekodiert und an schnelle Recheneinheiten gesendet. Befehle laufen nicht mehr in Taktzyklen und sind empfindlicher für Cache-Misses und Inter-Instruction-Abhängigkeiten.

Lesen Sie die AMD- und Intel-Prozessor-Programmierhandbücher für alle wichtigen Details.

    
___ tag123optimierung ___ Optimierung ist der Akt der Verbesserung einer Methode oder eines Designs. In der Programmierung nimmt die Optimierung normalerweise die Form an, die Geschwindigkeit eines Algorithmus zu erhöhen oder die benötigten Ressourcen zu reduzieren. Eine weitere Bedeutung der Optimierung sind numerische Optimierungsalgorithmen. ___ qstnhdr ___ Erzwinge Compiler, um seiteneffektelose Anweisungen nicht zu optimieren ___
anon 20.07.2009, 08:43
quelle
6

In diesem Fall schlage ich vor, dass Sie die Funktion den ganzzahligen Wert zurückgeben:

%Vor%

Ihr Anrufcode kann sie dann mit einem Printf auswerten, um sicherzustellen, dass sie nicht optimiert wird. Stellen Sie außerdem sicher, dass sich float_to_int in einer separaten Kompilierungseinheit befindet, damit der Compiler keine Tricks spielen kann.

%Vor%

Vergleichen Sie dies jetzt mit einer leeren Funktion wie:

%Vor%

Was auch extern sein sollte.

Der Unterschied in den Zeiten sollte Ihnen eine Vorstellung von den Kosten geben, die Sie zu messen versuchen.

    
George Phillips 20.07.2009 08:43
quelle
6
  

Ich möchte also sicherstellen, dass wenn ich profiliere, ich keine verzerrten Ergebnisse bekomme. Daher möchte ich sicherstellen, dass der Compiler keine output-Anweisungen

optimiert

Sie sind per Definition schief die Ergebnisse.

So beheben Sie das Problem, dass Sie versuchen, "Dummy" -Code zu schreiben, den Sie nur zum Testen geschrieben haben: Speichern Sie Ihre Ergebnisse für die Profilerstellung in einem globalen / statischen Array und drucken Sie ein Mitglied des Arrays an die Ausgabe am Ende des Programms. Der Compiler ist nicht in der Lage, out irgendwelche der Berechnungen zu optimieren, die Werte in das Array eingetragen haben, aber Sie erhalten immer noch andere Optimierungen, die er einsetzen kann, um den Code schnell zu machen.

    
Sam Harwell 20.07.2009 08:39
quelle
6

Die Zuweisung zu einer volatile -Variable sollte niemals wegoptimiert werden, damit Sie das gewünschte Ergebnis erhalten:

%Vor%     
finnw 20.07.2009 09:24
quelle
3

Was bei allen bisher verwendeten Compilern funktioniert hat:

%Vor%

Beachten Sie, dass dies die Ergebnisse verfälscht, boith-Methoden sollten in writeMe schreiben.

volatile sagt dem Compiler "der Wert darf ohne Ihre Nachricht aufgerufen werden", daher kann der Compiler die Berechnung nicht überspringen und das Ergebnis löschen. Um die Propagierung von Eingabekonstanten zu blockieren, müssen Sie sie möglicherweise auch über ein externes volatiles ausführen:

%Vor%

Dennoch können alle Optimierungen zwischen dem Lesen und dem Schreiben "mit voller Kraft" angewendet werden. Das Lesen und Schreiben in die globale Variable sind oft gute "FencePosts" beim Überprüfen der generierten Assembly.

Ohne den extern kann der Compiler bemerken, dass ein Verweis auf die Variable niemals genommen wird, und somit bestimmen, dass er nicht flüchtig sein kann. Technisch gesehen, mit Link Time Code Generation, ist es vielleicht nicht genug, aber ich habe keinen Compiler gefunden, der aggressiv ist. (Für einen Compiler, der tatsächlich den Zugriff entfernt, müsste der Verweis an eine Funktion in einer zur Laufzeit geladenen DLL übergeben werden)

    
peterchen 20.07.2009 10:03
quelle
2

Sie müssen nur zu dem Teil springen, in dem Sie etwas lernen und das veröffentlichte Intel CPU Optimierungshandbuch .

Diese stellen ganz klar fest, dass das Gießen zwischen float und int eine sehr schlechte Idee ist, da es einen Speicher vom int-Register zum Speicher benötigt, gefolgt von einem Laden in ein float-Register. Diese Vorgänge verursachen eine Blase in der Pipeline und verschwenden viele wertvolle Zyklen.

    
Tom Leys 20.07.2009 08:46
quelle
2

Ein Funktionsaufruf verursacht ziemlich viel Overhead, also würde ich das sowieso entfernen.

Hinzufügen eines Dummy + = i; Das ist kein Problem, solange Sie dasselbe Bit im alternativen Profil behalten. (Also der Code, gegen den Sie es vergleichen).

Last but not least: asm-Code generieren. Auch wenn Sie in asm nicht codieren können, ist der generierte Code in der Regel verständlich, da er hinter Codenamen steht und C-Code kommentiert. So wissen Sie, was passiert und welche Bits behalten werden.

R

ps. habe das auch gefunden:

%Vor%

angeblich auch sehr schnell. Vielleicht möchten Sie dies auch profilieren. (obwohl es kaum portabler Code ist)

    
Toad 20.07.2009 08:38
quelle
1

Geben Sie den Wert zurück?

%Vor%

und dann können Sie auf der Aufrufseite alle Rückgabewerte zusammenfassen und das Ergebnis nach Abschluss des Benchmarks ausdrucken. Der übliche Weg, dies zu tun, ist irgendwie sicherzustellen, dass Sie vom Ergebnis abhängig sind.

Sie könnten stattdessen eine globale Variable verwenden, aber es scheint, als würde das mehr Cache-Misses erzeugen. In der Regel reicht es aus, den Wert einfach an den Aufrufer zurückzugeben (und sicherzustellen, dass der Aufrufer tatsächlich etwas damit macht).

    
jalf 20.07.2009 13:27
quelle
0

Ein Mikro-Benchmark um diese Aussage herum ist nicht repräsentativ für die Verwendung dieses Ansatzes in einem echten Szenario; Die umgebenden Anweisungen und ihre Auswirkung auf die Pipeline und den Cache sind im Allgemeinen genauso wichtig wie jede gegebene Anweisung in sich selbst.

    
Will 20.07.2009 08:41
quelle
0

GCC 4 macht jetzt viele Mikrooptimierungen, die GCC 3.4 noch nie gemacht hat. GCC4 enthält einen Tree Vectorizer, der sich als sehr nützlich erweist, um SSE und MMX zu nutzen. Es verwendet auch die Bibliotheken GMP und MPFR, um bei der Optimierung von Aufrufen wie sin() , fabs() usw. zu helfen, und optimiert solche Aufrufe für ihre FPU, SSE oder 3D Now! Äquivalente.

Ich weiß, dass der Intel-Compiler auch bei diesen Optimierungen sehr gut ist.

Mein Vorschlag ist, sich keine Gedanken über Mikrooptimierungen wie diese zu machen - auf relativ neuer Hardware (alles, was in den letzten 5 oder 6 Jahren gebaut wurde), sind sie fast völlig irrelevant.

Edit: Bei neueren CPUs ist der Befehl fabs der FPU weit schneller als ein Cast in int und Bitmaske, und der Befehl fsin wird im Allgemeinen schneller sein als die Vorberechnung einer Tabelle oder die Extrapolation einer Taylor-Reihe . Viele der Optimierungen, die Sie zum Beispiel in "Tricks of the Game Programming Gurus" finden würden, sind völlig unbegründet und könnten, wie in einer anderen Antwort ausgeführt, möglicherweise langsamer sein als Anweisungen auf der FPU und in SSE.

>

All dies ist auf die Tatsache zurückzuführen, dass neuere CPUs pipelined sind - Befehle werden dekodiert und an schnelle Recheneinheiten gesendet. Befehle laufen nicht mehr in Taktzyklen und sind empfindlicher für Cache-Misses und Inter-Instruction-Abhängigkeiten.

Lesen Sie die AMD- und Intel-Prozessor-Programmierhandbücher für alle wichtigen Details.

    
greyfade 20.07.2009 09:12
quelle

Tags und Links