GNU Compiler | Einfluss d. Parameter auf Performance (-ox -march=xxx etc. )

Piktogramm

Fleet Admiral
Registriert
Okt. 2008
Beiträge
10.093
Servus,

ich suche Literaturhinweise bzw. direkte Antworten/Erfahrungen, wie sich die div. Parameter auf den GNU Compiler (und auch Andere) in der Praxis auswirken. Daher, die Dokumentation d. GNU Compiler kann ich selber lesen und auch mal 1-2 Programme selber mit div. Parameter compilieren.

Bisher habe ich das beispielsweise mit dem ursprünglichem Linpack probiert, wo zwischen einem Lauf der ohne jede Optimierung kompiliert wurde und einem Versuch mit -03 und -march=native. Das optimierte Kompilat schafft da mal eben das 7,5x an OP/s*. Nun ist Linpack mit seinen bekannten Schwächen nicht unbedingt absolut zuverlässig, aber das Ergebnis zeigt, in welche Richtung es geht.
Nun frage ich mich, wieso kompiliert man beispielsweise nicht gleich alle Programme mit -ox bzw. wenn es nicht um Portabilität geht gleich mit -march=native bzw. wann nutzt man diese Optionen? Bis auf die etwas längere Zeit zum kompilieren ist das ja verschenkte Performance/Energieeffzienz etc. pp.


PS: Ich habe schon etwas selber gesucht, aber meist sind das dann Erfahrungsberichte der Ecke Benchmarkkiddie, die man freiwillig an kein Produktivsystem heran lässt. Also doch arg unbrauchbar ;)

*Faktor 7,5 bei einem Thread und 200x200er Array. Faktor 4 bei 10.000². Daher mit größerem Problem und auch größerem Einfluss der Anbindung zum Arbeitsspeicher wird der Unterschied kleiner, aber das ist dennoch ne ordentliche Hausnummer.
Prozessor ist ein Intel Haswell, aber auch die kleinen AMD Kabini für AM1 Sockel skalieren ähnlich ebenso der RasperryPi
 
Zuletzt bearbeitet:
Release Versionen werden in der Regel mit mindestens -O2 kompiliert.

Dass das nicht standartmäßig der Fall ist hat mindestens zwei Gründe:

1. Das kompilieren großer Programme dauert wesentlich länger, da der Compiler die Optimierungen anwenden muss.
2. Debugging ist nicht möglich, falls nicht mit -O0 und weiteren debuggingparametern kompiliert wurde.

march=native ist noch einmal ein anderes Thema. March sagt dem Compiler, welche CPU-Features genutzt werden sollen. Es können nicht alle Programme mit -march=native compiliert werden, da sie dann auf älterer Hardware nicht lauffähig wären - Schließlich kompiliert man in den wenigten Fällen Programme für sich selbst, sondern um sie zu verkaufen.
 
Hi togepi,

das sind die Einflüsse der Parameter ja, die kenne ich :) Die Dokumentation ist mir ja bekannt:
http://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/i386-and-x86-64-Options.html#i386-and-x86-64-Options

Nun frage ich mich jedoch, unter welchen Bedingungen die volle Optimierung wirklich im Alltag genutzt werden sollte, und unter welchen Gesichtspunkten es sich verbietet.
Also solang es um Debugging geht bringt die Optimierung nix, mit dem ganzen Debugkram im Binärcode wird das Programm schlicht immer unnötig langsam (und unsicher) laufen.

Beispiel1: Webserver, würde es hier nicht sinnvoll sein OpenSSL, Apache Server, PHP-Interpreter, SQL-Server mit der vollen Optimierung zu fahren? Daher mindestens -03 und optional -march=native. Die Nachteile von -o3 mit der längeren Zeit zum Kompilieren fällt, wenn es nicht direkt auf dem Server geschieht nicht ins Gewicht. Die Inportabilität ist evtl. nachteilig. Nimmt man für stärker belastete Server also die Nachteile der Optimierung in Kauf und ja wann/wieso/unter welchen Rahmenbedingungen?


Beispiel2: FE-Simulation, hier kann ein Vielfaches der zusätlichen Zeit beim Kompilieren durch verkürzte Berechnungen kompensiert werden. Für mich wäre es daher nur sinnvoll -03 zu nutzen. Spätestens auf größeren Clustern würde ich gar behaupten, dass -march=native Pflicht ist, da die Rechenzeit schlicht richtig teuer ist und die benötigte CPU-Zeit zum Kompilieren in aller Regel um Größenordnungen übertroffen wird.


Daher, es geht wirklich um die große weite, produktive Welt, wann setzt man was wie und weshalb ein?
Allgemein -o2 für Release ist ein guter Anfang ;)
 
Mir ist nicht ganz klar was deine eigentliche Frage ist.

Wenn man die Programme nur für den Eigengebrauch auf festgelegter Hardware compiliert, sollte man selbstverständlich mit -O3 -march=native compilieren.

Wenn man allerdings selbst Programme entwirft und testet, dann kompiliert man natürlich nicht so. Genauso wenig wenn man vorkompilierte Programme veröffentlicht.
 
Die letzten beiden Absätze treffen es doch schon halbwegs ;) Um solche Sachen geht es mit, also unter welchen Praxisbedingungen nutzt man was und wieso, bzw. was sollte man sich dabei überlegen.

Deswegen auch die Beispiele, würde es sich zum Beispiel bei einem Webserver lohnen die Performance mitzunehmen und gleichzeitig Inportabilität in Kauf zu nehmen (wenn der Server erstzt wird/ausfällt im Zweifelsfall von Nachteil) oder kompensiert man an der Stelle mangelnde Leistung lieber durch stärkerer (teurere) Hardware weil die Inportabilität einfach zu unabsehbaren Langfolgen führen kann.

Daher, es geht mit um Praxisfälle. Dein "Releases meist mit -o2" war da ein guter Anfang. Daher gegen -o2 spricht nichts, es wird gar in aller Regel mitgenommen solang die Zeit zum Kompilieren nicht total ausufert.
 
Piktogramm schrieb:
Beispiel1: Webserver, würde es hier nicht sinnvoll sein OpenSSL, Apache Server, PHP-Interpreter, SQL-Server mit der vollen Optimierung zu fahren? Daher mindestens -03 und optional -march=native. Die Nachteile von -o3 mit der längeren Zeit zum Kompilieren fällt, wenn es nicht direkt auf dem Server geschieht nicht ins Gewicht.
Schau dir doch erstmal an, was bei deinen Beispielen tatsächlich in der Praxis passiert! Du gehst offenbar davon aus, daß alle Softwarentwickler doof sind, noch nie was von optimiertem Code gehört haben und alle Arbeit dem Installateur überlassen. Damit liegst du falsch.

Beispiel Openssl:
Das config-Skript sorgt ganz allein für -O3 -march=was_ganz_gut_passendes falls gcc und bekannte Plattform. Auf 32bit-x86ern wirst du bei openssl vermutlich auch -fomit-frame-pointer sehen. Außerdem enthält openssl für nichtobskure Plattformen für die meisten zeitfressenden Kryptoalgos Assemblerversionen, womit der Optimierungszirkus des C-Compilers an diesen Stellen sowieso nichts bewirken kann - es sei denn, du schießt dir selbst ins Knie und verhinderst beim Bauen die Nutzung der Assemblerversionen.

Bei anderen weitverbreiteten, echten Anwendungsprogrammen (im Unterschied zu Benchmark-Geraffel ala linpack) ist es ähnlich: Performancekritische Abschnitte sind sowieso bereits handoptimiert und/oder die Buildskripte sorgen für passende Optimierung an den wichtigen Stellen.

Der mMn beste Ratschlag zur vernünftigen Optimierung bei der Installation von Programmen anderer Leute ist das Lesen der Installationsanleitung. Wenn das Verhalten des Programms durch Compileroptimierung stark beeinflusst werden kann, wirst du in der Install-Anleitung in der Regel dazu Hinweise finden.
 
Zuletzt bearbeitet:
Gerade bei OpenSSL wundert es mich eben,

wenn ich da die Werte vergleiche, die Phoronix.com für

Code:
$ openssl speed

bei einem AMD Athlon 5150 angibt sind um Faktor 4 höher als bei OpenSSL welches bei Ubuntu über die Paketquellen kommt. Wobei das Testsystem an kritischen Stellen (CPU, RAM) iidentisch ist. Ebenso erreicht OpenSSL in der VM mit entsprechenden Parametern kompiliert 2,x fach bessere Leistung (nach /etc/cpuinfo der VM meint, dass maximal SSE3 durchgereicht wird, + der Performancenachteil der durchs Virtualisieren eh hinzu kommt).
Eben da frage ich micht, wieso anscheinend das was die Ubuntu Pakete ausliefern nicht alles an Performance mitnehmen was möglich ist. Für OpenSSL aus den Ubuntu Repos wahrscheinlich zwecks Kompatibilität, OK.

Die Frage die sich mir zusätzlich stellt, gibt es einen Grund, wieso man auf kritisches Systemen entsprechend OpenSSL selber mit allen Optimierungen kompilieren sollte oder nicht? Denn auch wenn nicht besagter Faktor 4 im Realbetrieb herauskommt, scheint man das System an der Stelle dennoch gescheit beschleunigen zu können. Wie es sich dann bei der Geschwindigkeit von Datenbanken und beispielsweise Webservern verhält wäre auch nett zu wissen bzw. das dagegenspräche bei Produktivsystemen gnadenlos Optimierungen zu fahren.


Ansonsten soweit wie ich mich bisher informiert habe sind bei den meisten OpenSource Dingen die mir bisher aufgefallen sind keine (gescheiten) Abschnitte in der Dokumentation zu finden, die sich über die Performanceoptimierung seitens des Kompilierens auslassen. Da wird wohl eher davon ausgegangen, dass der Nutzer das zu wissen hat und dieses Wissen will ich mir mir euerer Hilfe aneignen ;).

Was ich jedoch gefunden habe, wie es auch du schreibst sind Aussagen wie "wenn es um Performance geht, dann hat da eh jemand schon was in Assembler geschrieben bzw. vorassimbiliert". Wobei ich diese Behauptung sich zwar oft findet, aber nachvollziehbar ist sie nicht. Das schreiben von eigenem Assembler klappt an sich nur wenn man den Befehlssatz der Zielmaschine genau kennt, bei Maschinen mit potenteren Befehlserweiterungen wird da aber wieder allerhand Performance verschenkt. Denn wenn aus Kompatibilitätsgründen eine in Assembler geschriebene und optimierte Floatingpointberechnung nur SSE2 nutzt die CPU aber bis AVX2 bietet, dann nutzt der beste von Hand optimierte Assemblercode nix.
Was sich jedoch findet (in Unterzahl) sind Quellen, die behaupten, dass das Schreiben von eigenem Assembler nur selten sinnvoll ist, da die Compiler mittlerweile großteils sehr guten Assembler -> Binärcode erzeugen, der auch gleich für potente Befehlserweiterungen angepasst werden kann. Wobei auch wenn diese Aussage seltener auftritt sie für mich weit besser nachvollziehbar ist.
Genauso finden sich vorassimibilierte Teile der Programme die entsprechend auf div. Platformen optimiert wurden bisher nicht. Zumindest OpenSSL aus den Ubuntu Quellen bringt sie allem Anschein nicht mit.


Ansonsten, ich gehe nicht davon aus, dass alle Softwareentwickler doof sind, sondern das mein Verstänndnis noch nicht reicht um die Entscheidungen guter Softwareentwickler nachzuvollziehen bzw. die Üblichen Geflogenheiten zu verstehen/zu kennen :). Ich gehe aber auch davon aus, dass wie überall eine ganze Menge zwar Softwareentwickler sind, aber dennoch sehr wenig von der Materie verstehen (war bisher in jedem Wirtschaftsbereich in dem ich Gearbeitet so. Es gab immer eine erschreckend große Menge an erfolgreichen Personen, die von dem was sie da machen sollten eigentlich nichts verstanden). Dabei ist mein Ziel mein Wissen auszubauen, zu verstehen wieso etwas warum gemacht wird, was möglich ist und wann es sinnvoll ist diese Möglichkeiten zu nutzen.
 
Piktogramm schrieb:
Eben da frage ich micht, wieso anscheinend das was die Ubuntu Pakete ausliefern nicht alles an Performance mitnehmen was möglich ist. Für OpenSSL aus den Ubuntu Repos wahrscheinlich zwecks Kompatibilität, OK.
Du kennst also die Antwort. Wenn du auf einer Plattform arbeitest, die weit mehr kann also die von der Distri vorausgesetzte, wird halt öfters was verschenkt.

Ich erinnere mich gut an openssl auf Debian auf 32bit-Sparcs, wo sparc v7-Kompatibilität Pflicht war. Das führte dazu, daß ein ssh-login auf einer Sun4m-Kiste (ist sparc v8) statt 3 Sekunden 20s (Zahlen aus dem Kopf) brauchte, weil das in v8 vorhandene Hardware-Multiply nicht genutzt wurde. Das war richtig unbenutzbar und fiel sofort auf, wenn man vorher Solaris auf dem Rechner hatte. Auf Debian bekam der gcc bei Übersetzen wegen v7-Kompatibilität nicht das Flag -mv8 mit, was im originalen openssl-build natürlich drin war. Also hat man in seinem Debian-Quellpakete eine Zeile geändert, das ganze neu übersetzt und installiert. Später gabs einen Mechanismus, um v7 und v8 Code parallel zu installieren und zur Laufzeit den jeweils passenden zu nutzen.

Deshalb gab ich oben den Rat "Installaltionsanleitung lesen" und nicht den Rat "Binärdistri nehmen", wenn man optimierte Software für seinen Rechner haben möchte.

Piktogramm schrieb:
Was ich jedoch gefunden habe, wie es auch du schreibst sind Aussagen wie "wenn es um Performance geht, dann hat da eh jemand schon was in Assembler geschrieben bzw. vorassimbiliert". Wobei ich diese Behauptung sich zwar oft findet, aber nachvollziehbar ist sie nicht.
Was ist daran nicht nachvollziehbar? Schau dir den Quellcode der Bibliotheken mit den großen CPU-Fressern an. Cryptokram, VideoEn-/Decoding, Numerik. Oder schau dir Systemsoftware, die ständig unten drunter rödelt: glibc, OS-Kernel. Da steckt überall viel optimiertes Zeug drin, weil es eben so oft genutzt wird und was bringt.


Piktogramm schrieb:
Das schreiben von eigenem Assembler klappt an sich nur wenn man den Befehlssatz der Zielmaschine genau kennt, bei Maschinen mit potenteren Befehlserweiterungen wird da aber wieder allerhand Performance verschenkt. Denn wenn aus Kompatibilitätsgründen eine in Assembler geschriebene und optimierte Floatingpointberechnung nur SSE2 nutzt die CPU aber bis AVX2 bietet, dann nutzt der beste von Hand optimierte Assemblercode nix.
Überraschung: Solange niemand passenden Code beisteuert, fehlt er.

Abgesehen von wenigen datenintensiven Algoritmen bringt dir AVX nichts. Diese wenigen Algorithmen stecken sowieso in speziellen Bibliotheken. Für 0815-Code ists vollkommen ausreichend, ihn nur für SSE2 zu optimieren, womit er auf allen x86_64-CPUs läuft.

Dort, wo es wirklich was bringt, findet sich der optimierte Code tatsächlich oft. AVX nutzender Assemblercode in freier Wildbahn, den praktisch jeder nutzt, sind die Zeichenkettenoperationen der glibc, Cryptoalgorithmen im Linuxkernel (arch/x86/crypto/*). Openssl hat für AES Versionen an Bord, die Intels AES-NI nutzen. Mehr geht nicht. Da haben sich schon Leute Gedanken gemacht - nicht selten Leute aus dem Haus des CPU-Herstellers, der seine neuesten Chips gut verkaufen will.

Piktogramm schrieb:
Genauso finden sich vorassimibilierte Teile der Programme die entsprechend auf div. Platformen optimiert wurden bisher nicht. Zumindest OpenSSL aus den Ubuntu Quellen bringt sie allem Anschein nicht mit.
Bezweifele ich stark. In openssl liegen z.B. Assemblervarianten von AES unter crypto/aes/asm/. Für andere Algorithmen analog. Extrem unwahrscheinlich, daß Ubuntu die nicht nutzt - wobei - bei Ubuntu muß man mit allem rechnen.

Man kann Programme auch so schreiben, daß kritischer Code in verschieden optimierten Varianten gleichzeitig im Binary landet und man zur Laufzeit auswählen kann, welcher Pfad genutzt wird. Der Aufwand lohnt selten, insbesondere bei quelloffener Software. Linux macht davon z.B. Gebrauch.
 
Zuletzt bearbeitet:
Ersteinmal danke, habe mittlerweile mal bisserl das Makefile und Configure von openssl "angeschaut". Ist recht interessant, vor allem da configure verschiedene Flags für verschiedene Platformen setzt.

Wobei sich openssl dann auch weigert per make install installlieren zu lassen. Werde da noch etwas herumprobieren. Dank deiner Hilfe und etwas eigener darauf aufbauendem Probieren fühle ich mich jetzt ersteinmal nicht mehr so blööd :D
 
Zurück
Oben