Introducing GNU Compiler Collection (GCC) and Clang/Low Level Virtual Machine (LLVM); comparing the performance of both C/C++ compilers
Visual C++, GNU Compiler Collection (GCC), and Clang/Low Level Virtual Machine (LLVM) are three mainstream C/C++ compilers in the industry. Visual C ++ bietet grafische Benutzeroberflächen (GUIs) und ist einfach zu debuggen, aber nicht für Linux-Plattformen geeignet. Daher vergleicht dieses Dokument hauptsächlich GCC mit Clang / LLVM.
GCC ist ein von GNU entwickelter Programmsprachen-Compiler. Es ist eine Reihe freier Software, die unter der GNU General Public License (GPL) und der GNU Lesser General Public License (LGPL) veröffentlicht wird. Es ist ein offizieller Compiler für die GNU- und Linux-Systeme und ein Hauptcompiler zum Kompilieren und Erstellen anderer UNIX-Betriebssysteme.
LLVM enthält eine Reihe von modularisierten Compilerkomponenten und Werkzeugketten. Es kann Programmsprachen und Links während der Kompilierung, Laufzeit und Leerlaufzeit optimieren und Code generieren. LLVM kann als Hintergrund für Compiler in mehreren Sprachen dienen. Clang ist ein C-, C ++ -, Objective-C- oder Objective-C ++ – Compiler, der in C ++ basierend auf LLVM kompiliert und unter der Apache 2.0-Lizenz veröffentlicht wird. Clang wird hauptsächlich verwendet, um eine Leistung zu erzielen, die der von GCC überlegen ist.
Durch langfristige Entwicklung und Iteration sind GCC, Clang und LLVM zu ausgereiften Compilern in der Branche geworden. Welcher Compiler ist dann besser? Welches sollten wir verwenden, um Programme und Systeme zu kompilieren und zu erstellen?
Bedeutung eines guten Compilers
Moderne Prozessoren haben alle superskalare und lange Pipelines sowie komplexe interne Strukturen und unterstützen Vektorerweiterungseinheiten in der Complex Instruction Set Computer (CISC) – oder Reduced Instruction Set Computer (RISC) -Architektur. Für viele Programme, die allgemeine rechenintensive Kernel enthalten, können Programmierer Vektorerweiterungsbefehle verwenden, um die Programmausführungsleistung erheblich zu verbessern. Beispielsweise werden bei Matrix- und Vektoroperationen die kombinierten Multiplikations- und Additionsbefehle verwendet, um die Leistung und Genauigkeit zu verbessern. Bitmaskenbefehle werden für die Verzweigungsverarbeitung in Vektoroperationen verwendet. Um jedoch die höchste Leistung zu erzielen, müssen Programmierer und Compiler immer noch viel Aufwand betreiben, um Aufgaben mit komplexen Speicherzugriffsmodi und nicht standardmäßigen Kerneln zu bewältigen.Darüber hinaus abstrahieren Standards moderner fortgeschrittener Sprachen ständig die Details der zugrunde liegenden Hardware und Datenstrukturen, um allgemeinen Code zu generieren, der logischer und mathematischer ist, anstatt spezifische Betriebsanweisungen und Speicherzugriffspfade. C ++ – Standards werden immer expressiver und abstrakter. Python ist beliebt, weil es lesbarer und ausdrucksvoller ist, selbst auf Kosten einer niedrigeren Laufgeschwindigkeit. Eine höhere Ausdruckskraft erhöht die Belastung des Compilers, guten Assemblercode aus den komplexen Strukturen zu generieren, die von Programmierern kompiliert wurden. Der Compiler muss intelligenter sein und härter arbeiten, um die Leistung mithilfe des Codes zu maximieren. Nicht alle Compiler können das. Bei der Auswahl eines Compilers müssen wir zunächst prüfen, ob dasselbe Codesegment effizientere Assemblerbefehle generieren kann.
Moderne Compiler müssen nicht nur leistungsstarke ausführbare Programme erzeugen, sondern auch selbst über eine hohe Leistung verfügen. Ein großes Softwareprojekt in C ++ kann Hunderte bis Tausende einzelner Übersetzungseinheiten enthalten. Jede Übersetzungseinheit kann Tausende von Codezeilen enthalten. C ++ – Code kann auch eine große Anzahl von vorlagenbasierten Programmiertechnologien verwenden. Diese Technologien erfordern, dass der Compiler relevante Informationen mehrmals überträgt, um eine Zieldatei zu generieren. Die Kompilierung großer C ++ – Projekte kann mehrere Stunden dauern, und während der Entwicklung müssen mehrere voneinander abhängige Änderungen gleichzeitig eingereicht werden. Für jede Einreichung müssen Entwickler die meisten Codebibliotheken neu kompilieren. Daher sind schnellere Compiler (Build-Tools) entscheidend, um eine hohe Produktivität für große Teams zu erreichen.In Bezug auf die Spracherweiterung bieten moderne Computersysteme mit mehreren Kerneln, Vektorverarbeitungsfunktionen und Beschleunigern Funktionen, die den natürlichen Fähigkeiten gängiger Programmiersprachen überlegen sind. Daher können spezielle HPC-Frameworks (High Performance Computing) wie OpenMP und OpenACC diese Lücke schließen. Diese Frameworks bieten Anwendungsprogrammschnittstellen (APIs), mit denen Programmierer Parallelität im Code ausdrücken können. Der Compiler und die entsprechende Laufzeitbibliothek müssen den parallelen Code der Prozessorarchitektur zuordnen. Viele HPC-Projekte hängen von OpenMP- und OpenACC-Standards ab, die von Entwicklern und Hardwareherstellern erweitert werden. Daher müssen die Compiler mit der Entwicklung von Spracherweiterungsstandards Schritt halten.
Abschließend erlaubt uns ein guter Compiler, uns auf den Prozess der Programmierung zu konzentrieren, anstatt gegen seine Mängel zu kämpfen. Es kann die neuesten Sprachstandards unterstützen, optimierte Befehle aus dem abstraktesten Code generieren und den Quellcode in kürzerer Zeit kompilieren.
Entwicklungsgeschichte von GCC
Bevor Sie GCC lernen, müssen Sie zuerst das GNU-Projekt verstehen. Richard Stallman startete 1984 das GNU-Projekt, um ein UNIX-ähnliches Open-Source-Softwaresystem zu entwickeln. Das GNU-Betriebssystem hat sich im Laufe der Zeit nicht umfassend weiterentwickelt. Es hat jedoch viele hervorragende und nützliche Open-Source-Software-Tools wie Make, Sed, Emacs, Glibc, GDB und GCC entwickelt. Diese GNU Open Source Software und Linux Kernel bilden zusammen das GNU/Linux System. Am Anfang stellte GCC stabile und zuverlässige Compiler zur Verfügung, die auf der Programmiersprache C für das GNU-System basierten. Ihr voller Name lautet GNU C Compiler. Später wurden weitere Sprachen (wie Fortran, Obj-C und Ada) unterstützt, und der vollständige Name von GCC wurde in GNU Compiler Collection geändert.
GCC-1.0 wurde 1987 von Richard Stallman veröffentlicht, vor mehr als dreißig Jahren. Aus der Software-Perspektive ist es sehr alt. Jemand sammelte die GCC-Entwicklungsaufzeichnungen zwischen 1989 und 2012 und produzierte ein dreißigminütiges animiertes Video (GNU Compiler Collection dev History 1989-2012), das den Entwicklungsprozess von GCC intuitiv demonstrierte. Wir können etwas über die Entwicklungsgeschichte von GCC aus seinen Versionen lernen:
- GCC-1.0: veröffentlicht von Richard Stallman im Jahr 1987.
- GCC-2.0: veröffentlicht 1992 und unterstützt C++. Später wurde die GCC-Gemeinschaft gespalten, weil Richard Stallman GCC als zuverlässigen C-Compiler des GNU-Systems definierte und dachte, dass GCC zu dieser Zeit für das GNU-System ausreichend war und der Entwicklungsfokus von GCC auf das GNU-System selbst verlagert werden sollte. Andere große Entwickler hofften, GCC weiter zu verbessern und radikalere Entwicklungen und Verbesserungen in verschiedenen Aspekten vorzunehmen. Diese aktiven Entwickler verließen 1997 die GCC-Community und entwickelten die EGCS-Gabel.
- GCC-3.0: Offensichtlich hatten Entwickler im Allgemeinen einen starken Wunsch nach guten Compilern. Die EGCS-Gabel entwickelte sich reibungslos und wurde von immer mehr Entwicklern anerkannt. Schließlich wurde EGCS als neues GCC-Backbone verwendet und GCC-3.0 wurde 2001 veröffentlicht. Die gespaltene Gemeinschaft wurde wieder zusammengeführt, aber Richard Stallmans Einfluss war bis zu einem gewissen Grad geschwächt worden. Darüber hinaus hatte das GCC Industrial Committee begonnen, die Entwicklungsrichtung von GCC zu bestimmen.
- GCC-4.0: veröffentlicht im Jahr 2005. Diese Version wurde in die Serial Storage Architecture (SSA) integriert, und GCC entwickelte sich zu einem modernen Compiler.
- GCC-5.0: veröffentlicht im Jahr 2015. Später wurde die GCC-Versionsrichtlinie angepasst und jedes Jahr eine Hauptversion veröffentlicht. Ein unerwarteter Vorteil ist, dass die Versionsnummer dem Jahr entspricht. Beispielsweise wurde GCC-7 2017 und GCC-9 2019 veröffentlicht.
Jetzt ist die GCC-Entwicklung in die „moderne Chronik“ eingetreten. Angesichts des Wettbewerbsdrucks von LLVM hat die GCC-Community aktiv viele Anpassungen vorgenommen, z. B. die Beschleunigung der Kompilierung und die Verbesserung der Kompilierungswarnungsinformationen. In den letzten 30 Jahren hat sich GCC von einem Herausforderer in der Compiler-Branche zu einem Mainstream-Compiler für Linux-Systeme entwickelt und steht nun vor der Herausforderung von LLVM. Glücklicherweise nimmt die GCC-Community Anpassungen vor, um die Entwicklung von GCC zu beschleunigen. Wir können erwarten, dass der Wettbewerb zwischen den beiden Kompilierungstechnologien Softwareentwicklern weiterhin bessere Compiler zur Verfügung stellen wird.
Entwicklungsgeschichte von Clang und LLVM
LLVM entstand aus der Forschung von Chris Lattner über UUIC im Jahr 2000. Chris Lattner wollte eine dynamische Kompilierungstechnologie für alle statischen und dynamischen Sprachen erstellen. LLVM ist eine Art Open-Source-Software, die unter der BSD-Lizenz entwickelt wurde. Die erste Version 1.0 wurde 2003 veröffentlicht. Im Jahr 2005 wurde Apple Inc. stellte Chris Lattner und sein Team ein, um Programmiersprachen und Compiler für Apple-Computer zu entwickeln, woraufhin die Entwicklung von LLVM auf die Überholspur ging. Ab LLVM 2.5 wurden jedes Jahr zwei kleinere LLVM-Versionen veröffentlicht (in der Regel im März und September). Im November 2011 wurde LLVM 3.0 als Standard-XCode-Compiler veröffentlicht. XCode 5 begann standardmäßig mit Clang und LLVM 5.0. Die Versionsrichtlinie wurde für LLVM 5.0 und spätere Versionen angepasst, und jedes Jahr werden zwei Hauptversionen veröffentlicht. Die aktuelle stabile Version ist 8.0.
Der Name LLVM wurde zuerst von Low Level Virtual Machine abgekürzt. Da dieses Projekt nicht auf die Erstellung einer virtuellen Maschine beschränkt ist, wird die Abkürzung LLVM häufig in Frage gestellt. Nach der Entwicklung von LLVM wurde es zu einem Sammelbegriff für viele Kompilierungstools und Low-Level-Tool-Technologien, wodurch der Name weniger angemessen wurde. Die Entwickler beschlossen, die Bedeutung dieser Abkürzung aufzugeben. Jetzt ist LLVM der offizielle Markenname, der für alle Projekte unter LLVM gilt, einschließlich LLVM Intermediate Representation (LLVM IR), LLVM Debugging Tools und LLVM C ++ Standardbibliotheken. LLVM kann als traditioneller Compiler, JIT-Compiler, Assembler, Debugger, statisches Analysetool und für andere Funktionen im Zusammenhang mit Programmiersprachen verwendet werden.Im Jahr 2012 gewann LLVM den Software System Award der Association for Computing Machinery (ACM), zusammen mit traditionellen Systemen wie UNIX, WWW, TCP / IP, TeX und Java. LLVM vereinfacht die Implementierung neuer Programmiersprachen-Toolketten erheblich. In den letzten Jahren haben viele neue Programmiersprachen wie Swift, Rust und Julia LLVM als Kompilierungsframework verwendet. Darüber hinaus ist LLVM zum Standard-Compiler für Mac OS X-, iOS-, FreeBSD- und Android-Systeme geworden.
Clang
Clang wurde entwickelt, um einen Frontend-Compiler bereitzustellen, der GCC ersetzen kann. Apple Inc. (einschließlich NeXT later) hat GCC als offiziellen Compiler verwendet. GCC hat sich als Standard-Compiler in der Open-Source-Community immer gut bewährt. Apple Inc. hat seine eigenen Anforderungen an Kompilierungstools. Auf der einen Seite Apple Inc. es wurden viele neue Funktionen für die Objective-C-Sprache (oder später sogar für die C-Sprache) hinzugefügt. Die GCC-Entwickler akzeptierten diese Funktionen jedoch nicht und wiesen der Unterstützung dieser Funktionen eine niedrige Priorität zu. Später wurden sie einfach in zwei Zweige für die separate Entwicklung unterteilt, und folglich die von Apple Inc. veröffentlichte GCC-Version. ist viel früher als die offizielle Version. Auf der anderen Seite ist der GCC-Code stark gekoppelt und schwer separat zu entwickeln. Darüber hinaus nimmt die Codequalität in späteren Versionen weiter ab. Allerdings sind viele Funktionen von Apple Inc. (wie verbesserte integrierte Entwicklungsumgebung (IDE) Unterstützung) muss GCC als Modul aufrufen, aber GCC bietet nie eine solche Unterstützung. Darüber hinaus schränkt die Befreiung der GCC-Laufzeitbibliothek die Entwicklung von LLVM GCC grundlegend ein. Auch durch die Lizenz beschränkt, Apple Inc. LLVM kann nicht verwendet werden, um die Codegenerierungsqualität basierend auf GCC weiter zu verbessern. Daher hat Apple Inc. beschlossen, das Frontend-Klirren von C, C ++ und Objective-C-Sprachen von Grund auf neu zu schreiben, um GCC vollständig zu ersetzen.
Wie der Name schon sagt, unterstützt Clang nur C, C ++ und Objective-C. Die Entwicklung begann 2007 und der C-Compiler wurde erstmals fertiggestellt. Clang für Objective-C wird 2009 vollständig für die Produktionsumgebung verwendet. Die Unterstützung für C ++ ging ebenfalls schnell voran. Clang 3.3 unterstützte C ++ 11 vollständig, Clang 3.4 unterstützte C ++ 14 vollständig und Clang 5 unterstützte C ++ 17 vollständig und alle waren zu diesem Zeitpunkt GCC deutlich voraus.
Clang/LLVM und GCC-Community
Wie andere Open-Source-Software-Communities wird die GCC-Community von Enthusiasten freier Software und Hackern dominiert. Im Entwicklungsprozess werden die GCC-Community-Management- und Partizipationsmechanismen heute schrittweise gebildet. Derzeit ist die GCC-Community eine relativ stabile und klar definierte Wissensgesellschaft, in der jede Person klare Rollen und Pflichten hat:Richard Stallman und Free Software Foundation (FSF): Obwohl Richard Stallman und die FSF selten in das GCC-Community-Management involviert sind, sind sie in Lizenz- und Rechtsangelegenheiten immer noch getrennt.
Wie andere Open-Source-Communities wird die ausgereifte GCC-Community nicht mehr von Hackern dominiert. Kommerzielle Unternehmen spielten eine wichtige Rolle in der Community, z. B. bei der Rekrutierung von Entwicklern und beim Sponsoring von Entwicklungstreffen. Derzeit wird die GCC-Community von den folgenden Arten von kommerziellen Unternehmen dominiert:
- Systemanbieter, hauptsächlich RedHat und SUSE.
- Chiphersteller, hauptsächlich Intel, ARM, AMD und IBM (PowerPC).
- Spezialisierte Anbieter wie CodeSourcery und Tool Chain Service Provider wie AdaCore auf Basis der Ada-Sprache. CodeSourcery hatte eine brillante Geschichte und rekrutierte viele berühmte Entwickler, lehnte jedoch nach der Übernahme durch Mentor ab.
In der aktuellen GCC-Community dominieren Chiphersteller die Backend-Entwicklung, während Systemanbieter andere Entwicklungsbereiche leiten. In Bezug auf die Community-Entwicklung wird der GCC-Code derzeit auf einem eigenen SVN-Server gehostet. Eine Git-API wird bereitgestellt, um die Entwicklung und Einreichung zu erleichtern. Die Patch-Überprüfung ähnelt der in der Linux-Kernel-Community und verwendet das Mailinglistenformular. Wie oben erwähnt, ist die GCC-Community eine relativ stabile (oder geschlossene) bekannte Gesellschaft. Die Community hat im Grunde genommen jedes Jahr 150 bis 200 aktive Mitwirkende und veranstaltet jedes Jahr im September eine Entwicklerkonferenz. Im September 2019 findet die Entwicklerkonferenz in Montreal, Kanada, statt.
LLVM-Community
Die LLVM-Community ist eine noob-freundliche Compiler-Community. Es reagiert schnell auf die Fragen neuer Benutzer und Patch-Reviews. Dies ist auch die Grundlage und Quelle für nachfolgende Diskussionen der LLVM Foundation und die Verabschiedung des LLVM Community Code of Conduct und führt zu einer Reihe politisch korrekter Diskussionen.
Alle LLVM-Projekte und -Probleme werden über die DevExpress-E-Mail-Liste besprochen, und die Codeeinreichung wird über die Commits-E-Mail-Liste benachrichtigt. Alle Fehler und Funktionsänderungen werden über die Fehlerliste verfolgt. Die eingereichten Patches werden für die Master-Branches empfohlen. Der Stil entspricht den LLVM-Codierungsstandards und die Codeüberprüfung wird über Phabricator durchgeführt. Derzeit wurde das LLVM-Code-Repository nach GitHub migriert.
Im Gegensatz zur GCC-Community hat die LLVM-Community nur die LLVM Foundation. Die LLVM-Stiftung hat acht Mitglieder. Neben der Verwaltung von LLVM-Community-Angelegenheiten muss jedes Mitglied der LLVM-Stiftung LLVM-Entwicklungsfragen im Zusammenhang mit Technologie leiten. Derzeit ist der Präsident Tanya Lattner, die Frau von Chris Lattner. Chris Lattner selbst ist ebenfalls Mitglied der Stiftung und hat eine starke Kontrolle über die LLVM-Community und die Entwicklungsrichtung von LLVM.
Die Richtlinien zur Codeüberprüfung in der LLVM-Community sind im Grunde die gleichen wie in der GCC-Community. Der Unterschied besteht darin, dass aufgrund der schnellen Entwicklung von LLVM viele Mitwirkende keine Commit-Zugriffsberechtigung haben und ihren Code über die Betreuer einreichen müssen. Derzeit haben die Clang- und LLVM-Communities jedes Jahr mehr als 1.000 Mitwirkende. Im Allgemeinen finden Entwicklerkonferenzen jährlich im April und Oktober statt. Die Entwicklerkonferenz im Oktober 2019 findet in San Jose, USA, statt.
Die LLVM-Lizenz wird von der UIUC-Lizenz zur Apache 2.0-Lizenz mit LLVM-Ausnahmen geändert. Es wird hauptsächlich verwendet, um das Problem zu lösen, dass die LLVM-Laufzeitbibliothek auf einer MIT-Lizenz basiert und die für das Projekt erforderliche Patentgenehmigung zu umfangreich ist. Unter dieser Lizenz erlaubt LLVM jedem, kommerzielle Produkte ohne Einschränkungen von LLVM abzuleiten, und erfordert nicht, dass Derivate Open-Source-Code bereitstellen, wodurch die umfassende Verwendung von LLVM gefördert wird, einschließlich:Das Herunterladen oder die Verwendung von LLVM ganz oder teilweise für persönliche, interne oder kommerzielle Zwecke. Die Möglichkeit, LLVM-Code zu ändern, ohne ihn wieder zum Projekt beizutragen.
Leistung Vergleich zwischen GCC und LLVM
Architektur: x86_64
Prozessor: Intel (R) Xeon (R) Platin 8163 CPU @ 2,50 GHz
L1 daten cache: 32 KB
L2 cache: 1,024 KB
L3 cache: 33,792 KB
Speicher: 800 GB
Betriebs system: Alibaba Group Enterprise Linux Server release 7,2 Paladin)
Kernel: 4.9.151–015.ali3000.alios7.x86_64
Compiler: Clang/LLVM 8.0 GCC8.3.1
Benchmark
SPEC CPU 2017 ist eine Reihe von CPU-Subsystem-Test-Tools zum Testen der CPU, Cache, Speicher und Compiler. Es enthält 43 Tests von vier Kategorien, einschließlich SPECspeed 2017 INT und FP, die die Integer-Geschwindigkeit und Gleitkomma-Betriebsgeschwindigkeit und SPECrate 2017 INT und FP testen, die die Integer-Parallelitätsrate und die Gleitkomma-Parallelitätsrate testen. Clang unterstützt die Fortran-Sprache nicht. Daher werden in diesem Beispiel die C / C ++ – Programme im SPEC Speed Test Set verwendet, um den Single-Core-Leistungsunterschied zwischen den von Clang und GCC generierten Binärprogrammen zu testen. Die folgende Tabelle listet die SPEZIFIKATION CPU2017 C und C ++ Sets:
CINT2017 SpeedCFP2017 Speed600.perlbench_s619.lbm_s602.gcc_s644.nab_s605.mcf_s620.omnetpp_s623.in: xalancbmk_s625.x264_s631.deepsjeng_s641.leela_s657.xz_s
Testmethoden
Das LLVM-lnt-Automatisierungsframework wird verwendet, um den Test durchzuführen und die Leistung zu vergleichen. Es läuft auf die gleiche Weise wie runcpu der SPEC CPU. Bevor LLVM-lnt ausgeführt wird, wird der Cache (echo 3 > /proc/sys/vm/drop_caches) gelöscht und dann der Testdatensatz ausgeführt. Als nächstes wird der Reflex dreimal ausgeführt. Als Endergebnis wird der Mittelwert der drei ref-Testlaufergebnisse verwendet. Um Leistungsschwankungen durch CPU-Migration oder Kontextwechsel zu reduzieren, werden Prozesse, die auf dem Test-Dataset und dem Ref-Dataset ausgeführt werden, mithilfe des CPU-Affinitäts-Tools an einen CPU-Kern gebunden. Für den Kompilierzeittest verwendet diese Methode Thread 1, um das Testprogramm zu erstellen und die Testelemente zu vergleichen, die für eine lange Zeit kompiliert wurden. Die Kompilierungszeit enthält nicht die Ausführungszeit des Linkers. Es enthält nur die Zeit, zu der alle Quelldateien in allen Testprogrammen generiert werden.
Vergleich der Kompilierungsleistung
Der GCC-Kompilierungsprozess ist wie folgt: lesen Sie die Quelldatei, verarbeiten Sie die Quelldatei vor, konvertieren Sie sie in eine IR, optimieren Sie und generieren Sie eine Assemblydatei. Dann generiert der Assembler eine Objektdatei. Clang und LLVM sind nicht auf unabhängige Compiler angewiesen, sondern integrieren selbst implementierte Compiler im Backend. Das Generieren von Assemblydateien entfällt beim Generieren von Objektdateien. Die Objektdatei wird direkt aus dem IR generiert. Außerdem ist die Datenstruktur von LLVM IR im Vergleich zum GCC IR übersichtlicher. Es belegt weniger Speicher während der Kompilierung und unterstützt eine schnellere Durchquerung. Daher sind Clang und LLVM in Bezug auf die Kompilierungszeit vorteilhaft, was durch die aus der Spezifikationszusammenstellung erhaltenen Daten belegt wird, wie in der folgenden Abbildung gezeigt. Clang reduziert die Single-Thread-Kompilierungszeit im Vergleich zu GCC um 5% bis 10%. Daher bietet Clang mehr Vorteile für den Bau von Großprojekten.