Ich verwende derzeit GCC, habe aber kürzlich Clang entdeckt und denke über einen Wechsel nach. Es gibt jedoch einen entscheidenden Faktor - die Qualität (Geschwindigkeit, Speicherbedarf, Zuverlässigkeit) der von ihm erzeugten Binärdateien - wenn gcc -O3
eine Binärdatei erzeugt werden kann, die 1% schneller läuft oder 1% weniger Speicher benötigt, ist dies ein Deal-Breaker.
Clang bietet bessere Kompilierungsgeschwindigkeiten und einen geringeren Speicherbedarf zur Kompilierungszeit als GCC, aber ich bin wirklich an Benchmarks / Vergleichen der resultierenden kompilierten Software interessiert - können Sie mich auf einige hinweisen oder Ihre Erfahrungen beschreiben?
Antworten:
Hier sind einige aktuelle, wenn auch enge Ergebnisse von mir mit GCC 4.7.2 und Clang 3.2 für C ++.
UPDATE: GCC 4.8.1 v Clang 3.3 Vergleich unten angefügt.
UPDATE: GCC 4.8.2 v Clang 3.4 Vergleich ist dem beigefügt.
Ich verwalte ein OSS-Tool, das für Linux sowohl mit GCC als auch mit Clang und mit dem Microsoft-Compiler für Windows erstellt wurde. Das Tool coan ist ein Präprozessor und Analysator für C / C ++ - Quelldateien und Codelines für solche: seine Hauptprofile für das rechnerische Abstiegs-Parsing und die Dateiverwaltung. Der Entwicklungszweig (auf den sich diese Ergebnisse beziehen) umfasst derzeit etwa 11.000 LOC in etwa 90 Dateien. Es ist jetzt in C ++ codiert, das reich an Polymorphismus und Vorlagen ist und dennoch in vielen Patches durch seine nicht allzu ferne Vergangenheit in zusammengehacktem C verstrickt ist. Die Bewegungssemantik wird nicht ausdrücklich ausgenutzt. Es ist Single-Threaded. Ich habe keine ernsthaften Anstrengungen unternommen, um es zu optimieren, während die "Architektur" so weitgehend ToDo bleibt.
Ich habe Clang vor 3.2 nur als experimentellen Compiler eingesetzt, da seine C ++ 11-Standardunterstützung trotz seiner überlegenen Kompilierungsgeschwindigkeit und Diagnose der aktuellen GCC-Version in der von coan ausgeübten Hinsicht hinterherhinkt. Mit 3.2 wurde diese Lücke geschlossen.
Mein Linux-Testkabel für aktuelle Coan-Entwicklungsprozesse verarbeitet ungefähr 70.000 Quelldateien in einer Mischung aus Parser-Testfällen mit einer Datei, Stresstests, die Tausende von Dateien verbrauchen, und Szenariotests, die weniger als 1 KB Dateien verbrauchen. Das Harness meldet nicht nur die Testergebnisse, sondern sammelt auch die Gesamtzahl der verbrauchten Dateien und die in coan verbrauchte Laufzeit (es übergibt einfach jede coan-Befehlszeile an den Linux-
time
Befehl und erfasst und addiert die gemeldeten Zahlen). Das Timing wird durch die Tatsache geschmeichelt, dass eine beliebige Anzahl von Tests, die 0 messbare Zeit benötigen, alle 0 ergeben, aber der Beitrag solcher Tests ist vernachlässigbar. Die Timing-Statistiken werden am Ende folgendermaßen angezeigtmake check
:Ich habe die Leistung des Testkabels zwischen GCC 4.7.2 und Clang 3.2 verglichen, wobei alle Dinge außer den Compilern gleich waren. Ab Clang 3.2 benötige ich keine Präprozessor-Differenzierung mehr zwischen Code-Traktaten, die GCC kompiliert, und Clang-Alternativen. Ich habe jeweils dieselbe C ++ - Bibliothek (GCC) erstellt und alle Vergleiche nacheinander in derselben Terminalsitzung ausgeführt.
Die Standardoptimierungsstufe für meinen Release-Build ist -O2. Ich habe auch Builds bei -O3 erfolgreich getestet. Ich habe jede Konfiguration dreimal hintereinander getestet und die drei Ergebnisse mit den folgenden Ergebnissen gemittelt. Die Zahl in einer Datenzelle ist die durchschnittliche Anzahl von Mikrosekunden, die von der ausführbaren Coan-Datei benötigt werden, um jede der ~ 70K-Eingabedateien zu verarbeiten (Lese-, Analyse- und Schreibausgabe und Diagnose).
Es ist sehr wahrscheinlich, dass eine bestimmte Anwendung Eigenschaften aufweist, die den Stärken oder Schwächen eines Compilers nicht gerecht werden. Rigoroses Benchmarking verwendet verschiedene Anwendungen. Vor diesem Hintergrund sind die bemerkenswerten Merkmale dieser Daten:
Ein weiterer interessanter Vergleich der beiden Compiler ergab sich zufällig kurz nach diesen Erkenntnissen. Coan verwendet großzügig intelligente Zeiger, und einer davon wird in der Dateiverwaltung stark ausgeübt. Dieser spezielle Smart-Pointer-Typ wurde in früheren Releases aus Gründen der Compiler-Differenzierung typisiert, um zu sein,
std::unique_ptr<X>
ob der konfigurierte Compiler eine ausreichend ausgereifte Unterstützung für seine Verwendung als solche hatte, und ansonsten einestd::shared_ptr<X>
. Die Tendenz zustd::unique_ptr
war dumm, da diese Zeiger tatsächlich herum übertragen wurden, aberstd::unique_ptr
wie die passende Option zum Ersetzenstd::auto_ptr
zu einem Zeitpunkt aussahen, als die C ++ 11-Varianten für mich neu waren.Während experimenteller Builds, um das anhaltende Bedürfnis von Clang 3.2 nach dieser und einer ähnlichen Differenzierung zu messen, habe ich versehentlich gebaut,
std::shared_ptr<X>
als ich beabsichtigt hatte zu bauenstd::unique_ptr<X>
, und war überrascht zu beobachten, dass die resultierende ausführbare Datei mit der Standard-O2-Optimierung die schnellste I war hatte gesehen, manchmal 184 ms zu erreichen. pro Eingabedatei. Bei dieser einen Änderung des Quellcodes waren dies die entsprechenden Ergebnisse.Die wichtigsten Punkte hier sind:
Vor und nach der Änderung des Smart-Pointer-Typs kann Clang bei -O3-Optimierung eine wesentlich schnellere ausführbare Coan-Datei erstellen und bei -O2 und -O3 eine ebenso schnellere ausführbare Datei erstellen, wenn dieser Zeigertyp der beste ist -
std::shared_ptr<X>
- für die Arbeit.Eine offensichtliche Frage, die ich nicht kommentieren kann, ist, warum Clang in meiner Anwendung eine Beschleunigung von 25% -O2 finden sollte, wenn ein häufig verwendeter Smart-Pointer-Typ von eindeutig zu gemeinsam geändert wird, während GCC gleichgültig ist zur gleichen Änderung. Ich weiß auch nicht, ob ich die Entdeckung, dass Clangs -O2-Optimierung eine so große Sensibilität für die Weisheit meiner Smart-Pointer-Entscheidungen birgt, bejubeln oder aushöhlen sollte.
UPDATE: GCC 4.8.1 v clang 3.3
Die entsprechenden Ergebnisse sind jetzt:
Die Tatsache, dass alle vier ausführbaren Dateien jetzt eine viel längere durchschnittliche Zeit als zuvor benötigen, um eine Datei zu verarbeiten, spiegelt nicht die Leistung der neuesten Compiler wider. Dies liegt an der Tatsache, dass der spätere Entwicklungszweig der Testanwendung in der Zwischenzeit viel Analyse-Raffinesse angenommen hat und sich schnell bezahlt macht. Nur die Verhältnisse sind signifikant.
Die Punkte der Bemerkung sind jetzt nicht auffallend neu:
Vergleicht man diese Ergebnisse mit denen für GCC 4.7.2 und Clang 3.2, so fällt auf, dass GCC auf jeder Optimierungsstufe etwa ein Viertel des Clang-Vorsprungs zurückgefordert hat. Da die Testanwendung inzwischen stark entwickelt wurde, kann man dies nicht sicher auf einen Aufholprozess bei der Codegenerierung von GCC zurückführen. (Dieses Mal habe ich den Anwendungsschnappschuss notiert, aus dem die Timings abgerufen wurden, und kann ihn wieder verwenden.)
UPDATE: GCC 4.8.2 v clang 3.4
Ich habe das Update für GCC 4.8.1 v Clang 3.3 abgeschlossen und gesagt, dass ich mich für weitere Updates an dasselbe Coan-Snaphot halten würde. Aber ich habe mich stattdessen entschlossen, diesen Snapshot (Rev. 301) und den neuesten Entwicklungs-Snapshot zu testen, der die Testsuite (Rev. 619) besteht. Dies gibt den Ergebnissen ein wenig Länge, und ich hatte ein anderes Motiv:
In meinem ursprünglichen Beitrag wurde festgestellt, dass ich keine Anstrengungen unternommen hatte, um den Coan auf Geschwindigkeit zu optimieren. Dies war ab rev. 301. Nachdem ich jedoch den Zeitmessapparat in den Coan-Testgurt eingebaut hatte, starrten mich die Auswirkungen der letzten Änderungen auf die Leistung jedes Mal an, wenn ich die Testsuite durchführte. Ich sah, dass es oft überraschend groß war und dass der Trend stärker negativ war, als ich es von Funktionsgewinnen verdient hatte.
Durch rev. 308 Die durchschnittliche Verarbeitungszeit pro Eingabedatei in der Testsuite hatte sich seit der ersten Veröffentlichung hier mehr als verdoppelt. Zu diesem Zeitpunkt drehte ich meine 10-jährige Politik um, mich nicht um die Leistung zu kümmern. In der intensiven Flut von Revisionen war die Leistung von bis zu 619 immer eine Überlegung, und eine große Anzahl von ihnen ging lediglich dazu über, wichtige Lastträger auf grundlegend schnelleren Zeilen neu zu schreiben (allerdings ohne die Verwendung von nicht standardmäßigen Compilerfunktionen). Es wäre interessant zu sehen, wie jeder Compiler auf diese Kehrtwende reagiert.
Hier ist die jetzt bekannte Zeitmatrix für die letzten beiden Compiler-Builds von Rev. 301:
coan - rev.301 Ergebnisse
Die Geschichte hier ist von GCC-4.8.1 und Clang-3.3 nur unwesentlich geändert. GCCs Auftritt ist eine Kleinigkeit besser. Clang's ist eine Kleinigkeit schlimmer. Lärm könnte das gut erklären. Clang hat immer noch einen Vorsprung
-O2
und-O3
Margen, die in den meisten Anwendungen keine Rolle spielen würden, aber für einige von Bedeutung wären.Und hier ist die Matrix für rev. 619.
coan - rev.619 Ergebnisse
Wenn man die Figuren 301 und 619 nebeneinander betrachtet, sprechen mehrere Punkte aus.
Ich wollte schnelleren Code schreiben, und beide Compiler bestätigen nachdrücklich meine Bemühungen. Aber:
GCC zahlt diese Bemühungen weitaus großzügiger zurück als Clang. Bei der
-O2
Optimierung ist Clangs 619-Build 46% schneller als sein 301-Build: Bei-O3
Clangs Verbesserung 31%. Gut, aber auf jeder Optimierungsstufe ist der 619-Build von GCC mehr als doppelt so schnell wie der 301.GCC kehrt Clangs frühere Überlegenheit mehr als um. Und auf jeder Optimierungsstufe schlägt GCC Clang jetzt um 17%.
Clangs Fähigkeit im 301-Build, durch
-O3
Optimierung mehr Hebelkraft als GCC zu erzielen, ist im 619-Build nicht mehr vorhanden. Keiner der Compiler profitiert sinnvoll von-O3
.Ich war von dieser Umkehrung des Glücks ausreichend überrascht, dass ich vermutete, dass ich versehentlich einen trägen Build von Clang 3.4 selbst erstellt habe (da ich ihn aus dem Quellcode erstellt habe). Also habe ich den 619-Test mit Clang 3.3 meiner Distribution wiederholt. Die Ergebnisse waren praktisch die gleichen wie für 3.4.
Was die Reaktion auf die Kehrtwende betrifft: Bei den Zahlen hier hat Clang viel besser als GCC abgeschnitten, als ich ihm keine Hilfe gegeben habe. Als ich mich entschied zu helfen, hat GCC einen viel besseren Job gemacht als Clang.
Ich erhebe diese Beobachtung nicht zu einem Prinzip, aber ich nehme die Lektion: "Welcher Compiler erzeugt die besseren Binärdateien?" ist eine Frage, bei der es, selbst wenn Sie die Testsuite angeben, zu der die Antwort relativ sein soll, nicht eindeutig darum geht, nur die Binärdateien zeitlich zu steuern.
Ist Ihre bessere Binärdatei die schnellste Binärdatei oder diejenige, die billig gestalteten Code am besten kompensiert? Oder kompensieren Sie am besten teuer gestalteten Code, bei dem Wartbarkeit und Wiederverwendung Vorrang vor Geschwindigkeit haben? Dies hängt von der Art und dem relativen Gewicht Ihrer Motive für die Erstellung der Binärdatei sowie von den Einschränkungen ab, unter denen Sie dies tun.
Wenn Sie sich auf jeden Fall für das Erstellen der "besten" Binärdateien interessieren, sollten Sie immer wieder überprüfen, wie aufeinanderfolgende Iterationen von Compilern Ihre Vorstellung von "den besten" über aufeinanderfolgende Iterationen Ihres Codes hinweg liefern.
quelle
kcachegrind
, die Funktionen zu bestimmen, bei denen sich die generierten ausführbaren Dateien in der Leistung unterscheiden.Phoronix hat einige Benchmarks durchgeführt , aber es handelt sich um eine Snapshot-Version von Clang / LLVM von vor einigen Monaten. Das Ergebnis war, dass die Dinge mehr oder weniger ein Schub waren; Weder GCC noch Clang sind in allen Fällen definitiv besser.
Da Sie den neuesten Clang verwenden würden, ist er möglicherweise etwas weniger relevant. Andererseits wird GCC 4.6 anscheinend einige wichtige Optimierungen für Core 2 und i7 haben.
Ich denke, Clangs schnellere Kompilierungsgeschwindigkeit wird für Originalentwickler besser sein, und wenn Sie den Code in die Welt hinausschieben, Linux-Distribution / BSD / etc. Endbenutzer verwenden GCC für die schnelleren Binärdateien.
quelle
Die Tatsache, dass Clang Code schneller kompiliert, ist möglicherweise nicht so wichtig wie die Geschwindigkeit der resultierenden Binärdatei. Hier finden Sie jedoch eine Reihe von Benchmarks .
quelle
Es gibt insgesamt nur einen sehr geringen Unterschied zwischen GCC 4.8 und Clang 3.3 in Bezug auf die Geschwindigkeit der resultierenden Binärdatei. In den meisten Fällen funktioniert der von beiden Compilern generierte Code ähnlich. Keiner dieser beiden Compiler dominiert den anderen.
Benchmarks, die darauf hinweisen, dass zwischen GCC und Clang eine erhebliche Leistungslücke besteht, sind zufällig.
Die Programmleistung wird durch die Wahl des Compilers beeinflusst. Wenn ein Entwickler oder eine Gruppe von Entwicklern ausschließlich GCC verwendet, ist zu erwarten, dass das Programm mit GCC etwas schneller ausgeführt wird als mit clang und umgekehrt.
Aus Entwicklersicht besteht ein bemerkenswerter Unterschied zwischen GCC 4.8+ und Clang 3.3 darin, dass GCC über die
-Og
Befehlszeilenoption verfügt . Diese Option ermöglicht Optimierungen, die das Debuggen nicht beeinträchtigen, sodass beispielsweise immer genaue Stapelspuren abgerufen werden können. Das Fehlen dieser Option in clang macht es für einige Entwickler schwieriger, clang als optimierenden Compiler zu verwenden.quelle
Die einzige Möglichkeit, dies festzustellen, besteht darin, es zu versuchen. FWIW Ich habe einige wirklich gute Verbesserungen mit Apples LLVM gcc 4.2 im Vergleich zum regulären gcc 4.2 (für x86-64-Code mit ziemlich viel SSE) gesehen, aber YMMV für verschiedene Codebasen. Angenommen, Sie arbeiten mit x86 / x86-64 und kümmern sich wirklich um die letzten paar Prozent, dann sollten Sie auch Intels ICC ausprobieren, da dies häufig gcc schlagen kann - Sie können eine 30-Tage-Evaluierungslizenz von intel.com erhalten und versuche es.
quelle
Ein besonderer Unterschied, den ich bei gcc 5.2.1 und clang 3.6.2 festgestellt habe, ist, dass Sie eine kritische Schleife haben wie:
Dann wird gcc beim Kompilieren mit
-O3
oder-O2
die Schleife achtmal spekulativ abrollen. Clang wird es überhaupt nicht abrollen. Durch Versuch und Irrtum stellte ich fest, dass in meinem speziellen Fall mit meinen Programmdaten die richtige Menge an Abrollen fünf beträgt, also gcc overshot und clang undershot. Das Überschießen war jedoch nachteiliger für die Leistung, so dass gcc hier viel schlechter abschnitt.Ich habe keine Ahnung, ob der Unterschied beim Abrollen ein allgemeiner Trend ist oder nur etwas, das für mein Szenario spezifisch war.
Vor einiger Zeit habe ich ein paar Garbage Collectors geschrieben , um mir mehr über die Leistungsoptimierung in C beizubringen. Zumal es bei der Speicherbereinigung hauptsächlich um das Verfolgen und Kopieren von Speicher durch Zeiger geht.
Die Ergebnisse sind (Zahlen in Sekunden):
Dies ist alles reiner C-Code und ich erhebe keinen Anspruch auf die Leistung eines Compilers beim Kompilieren von C ++ - Code.
Unter Ubuntu 15.10, x86.64 und einem AMD Phenom (tm) II X6 1090T-Prozessor.
quelle
Grundsätzlich lautet die Antwort: Es kommt darauf an. Es gibt viele, viele Benchmarks, die sich auf verschiedene Arten von Anwendungen konzentrieren.
Mein Benchmark für meine App lautet: gcc> icc> clang.
Es gibt seltene E / A-Vorgänge, aber viele CPU-Float- und Datenstrukturoperationen.
Kompilierungsflags sind -Wall -g -DNDEBUG -O3.
https://github.com/zhangyafeikimi/ml-pack/blob/master/gbdt/profile/benchmark
quelle