wake-up-neo.net

Beschleunigung der Kompilierzeit von g ++ (bei Verwendung vieler Vorlagen)

Diese Frage ist vielleicht etwas seltsam, aber wie kann ich die g ++ - Kompilierzeit beschleunigen? Mein C++ - Code verwendet stark Boost und Vorlagen. Ich habe bereits so viel wie möglich aus den Header-Dateien herausgezogen und verwende die Option -j, aber das Kompilieren (und Verknüpfen) dauert noch eine Weile.

Gibt es Werkzeuge, die meinen Code analysieren und dem Compiler Engpässe aufzeigen? Oder kann man den Compiler, der auf meinem Code läuft, irgendwie profilieren? Das wäre wirklich schön, denn manchmal habe ich den Eindruck, dass ich zuviel Zeit damit verbracht habe, auf das Compiler-Log zu starren ...

61
Danvil

Was war für mich am nützlichsten:

  • Erstellen Sie ein Dateisystem RAM. Dies ist unter Linux trivial. Möglicherweise möchten Sie eine Kopie allgemeiner Header-Dateien (vorkompilierte oder eigentliche .h-Dateien) auch im Dateisystem RAM aufbewahren.
  • Vorkompilierte Header . Ich habe eine (größere) Bibliothek (z. B. Boost, Qt, Stdlib).
  • Deklarieren statt Klassen einschließen, wenn möglich. Dadurch werden Abhängigkeiten reduziert und somit die Anzahl der Dateien reduziert, die beim Ändern einer Headerdatei erneut kompiliert werden müssen.
  • Parallelisieren von make . Dies hilft normalerweise von Fall zu Fall, aber ich habe -j3 global für make. Stellen Sie jedoch sicher, dass Ihre Abhängigkeitsdiagramme in Ihrem Makefile korrekt sind, oder es können Probleme auftreten.
  • Verwenden Sie -O0, wenn Sie nicht die Ausführungsgeschwindigkeit oder die Codegröße testen (und Ihr Computer ist schnell genug, um sich nicht um den (wahrscheinlich kleinen) Performance-Hit zu kümmern).
  • Kompilieren Sie jedes Mal, wenn Sie speichern. Manche Leute mögen das nicht, aber Sie können Fehler frühzeitig erkennen und können im Hintergrund ausgeführt werden, wodurch sich die Wartezeit verringert, wenn Sie mit dem Schreiben fertig sind und zum Testen bereit sind.
47
strager

Ich gehe davon aus, dass wir über minutes sprechen, um eine Datei zu kompilieren, d. H. Vorkompilierte Header oder Probleme mit der lokalen Festplatte sind nicht das Problem.

Lange Kompilierungszeiten mit tiefem Template-Code (Boost usw.) beruhen häufig auf dem unfreundlichen asymptotischen Verhalten von gcc bei der Template-Instantiierung, insbesondere wenn variadische Templates mit Template-Standardargumenten emuliert werden. 

Hier ist ein Dokument, das die reduzierte Kompilierzeit als Motivation für variadische Vorlagen bezeichnet:

cpptruths hatte einen Artikel darüber, wie gcc-4.5 in dieser Hinsicht viel besser ist und wie es mit seinen variadischen Templates brillant funktioniert:

IIRC und BOOST bieten eine Möglichkeit, die Generierung von Template-Standardparametern für die Pseudo-Variadics zu beschränken. Ich denke, 'g ++ -DBOOST_MPL_LIMIT_LIST_SIZE = 10' sollte funktionieren (der Standard ist 20).

UPDATE: Es gibt auch einen Nice-Thread mit allgemeinen Techniken, um das Kompilieren hier auf SO zu beschleunigen, was nützlich sein könnte: 

UPDATE: Hier geht es um die Leistungsprobleme beim Erstellen von Vorlagen. Die akzeptierte Antwort empfiehlt auch gcc-4.5. Auch Clang wird als positives Beispiel erwähnt:

17

Folgendes habe ich getan, um Builds in einem sehr ähnlichen Szenario, das Sie beschreiben, zu beschleunigen (Boost, Vorlagen, gcc)

  • erstellung auf lokaler Festplatte anstelle eines Netzwerkdateisystems wie NFS
  • upgrade auf eine neuere Version von gcc
  • untersuchen distcc
  • schnellere Build-Systeme, insbesondere mehr RAM
17
Sam Miller

Wenn Sie viel rekompilieren, kann ccache helfen. Die Kompilierung wird zwar nicht beschleunigt, aber Sie erhalten ein zwischengespeichertes Ergebnis, wenn Sie aus irgendeinem Grund eine sinnlose Neukompilierung durchführen. Es könnte den Eindruck erwecken, das falsche Problem anzugehen, aber manchmal sind die Neuerstellungsregeln so kompliziert, dass Sie tatsächlich während eines neuen Builds denselben Kompilierungsschritt erhalten.

Zusätzliche Idee: Wenn Ihr Code mit clang kompiliert wird, verwenden Sie ihn stattdessen. Es ist normalerweise schneller als GCC.

9
viraptor

Zusätzlich zu dem, was alle anderen hinzugefügt haben und was Sie bereits tun (parallelisiertes Build, Compileroptionen usw.), sollten Sie Vorlagen in Implementierungsklassen ausblenden, auf die über Schnittstellen zugegriffen wird. Das heißt, anstatt eine Klasse wie:

// ClsWithNoTemplates.h file, included everywhere

class ClsWithTemplates
{
    ComplicatedTemplate<abc> member;
    // ...

public:
    void FunctionUsingYourMember();
};

du solltest haben:

// ClsWithNoTemplates.h file:

class ClsWithTemplatesImplementation; // forward declaration
  // definition included in the ClsWithNoTemplates.cpp file
  // this class will have a ComplicatedTemplate<abc> member, but it is only 
  // included in your ClsWithNoTemplates definition file (that is only included once)


class ClsWithNoTemplates
{
     ClsWithTemplatesImplementation * impl; // no templates mentioned anywhere here
public:
    void FunctionUsingYourMember(); // call impl->FunctionUsingYourMember() internally
};

Dies ändert Ihr OOP - Design ein wenig, aber es ist zum Wohle: Die Definition von 'ClsWithNoTemplates' ist jetzt fast und Sie kompilieren die Definition von 'ClsWithNoTemplates' nur einmal (vor).

Wenn Sie außerdem den Implementierungscode ändern, muss der Code, der ClsWithNoTemplates.h enthielt, möglicherweise nicht neu definiert werden.

Diese Änderung sollte die teilweise Kompilierungszeit drastisch verlängern. Dies ist auch hilfreich, wenn es sich bei ClsWithNoTemplates um eine öffentliche Schnittstelle handelt, die aus einer Bibliotheksdatei exportiert wird: Es muss überhaupt neu kompiliert werden.

3
utnapistim

Versuchen Sie die PIMPL-Technik, diese Frage: Welche Techniken können verwendet werden, um die C++ - Kompilierungszeiten zu beschleunigen?

Dadurch wird verhindert, dass der Compiler der Kette von Header-Dateien und Implementierungen jedes Mal folgt, wenn Sie etwas tun müssen.

3
gtrak

Wenn viele Dateien vorhanden sind, können Sie die Kompilierung erheblich beschleunigen, indem Sie nur eine .cpp-Datei haben, die alle anderen .cpp-Dateien enthält. Dies setzt natürlich voraus, dass Sie mit Makros vorsichtiger sind und die Sie bereits pro Datei definiert haben, da sie jetzt für andere CPP-Dateien sichtbar sind.

Wenn viele Dateien vorhanden sind, kann dies die Kompilierzeit erheblich reduzieren.

2
Zitrax

Instantiieren Sie weniger Vorlagen und Inline-Funktionen. Kompilieren Sie so viel wie möglich und verknüpfen Sie es, anstatt alles von Grund auf neu zu kompilieren. Stellen Sie sicher, dass Sie die neueste Version von GCC verwenden.

Es ist jedoch eine einfache Tatsache, dass C++ eine unglaublich komplexe Sprache ist und das Kompilieren viel Zeit in Anspruch nimmt.

1
Puppy

Dieses Dokument beschreibt eine Methode zum Kompilieren von Vorlagencode, ähnlich wie bei "herkömmlichen" Objektdateien, die keine Vorlagen sind. Spart die Kompilier- und Verknüpfungszeit mit nur einer Zeile Code-Overhead pro Template-Instantiierung.

1
Chris Tonkinson

Kompilieren mit g ++ unter Verwendung mehrerer Kerne 

Kompilieren mit g ++ mit mehreren Kernen

0
karlphillip

Normalerweise sind die teuersten Teile der Kompilierung (a) das Lesen der Quelldateien (ALLvon ihnen) und (b) das Laden des Compilers für jede Quelldatei in den Speicher.

Wenn Sie 52 Quelldateien (.cc-Dateien) haben, von denen jede # #clus-Dateien (.h) enthält, laden Sie den Compiler 52-mal, und Sie werden 2496-Dateien durchgehen. Abhängig von der Dichte der Kommentare in den Dateien verbringen Sie möglicherweise ziemlich viel Zeit damit, unnötige Zeichen zu essen. (In einer Organisation, die ich gesehen habe, schwankten die Header-Dateien zwischen 66% und 90% der Kommentare, wobei nur 10% -33% der Datei "bedeutungsvoll" waren.) Die einzige beste Möglichkeit, die Lesbarkeit dieser Dateien zu verbessern, war Strip jeden letzten Kommentar heraus, nur Code übrig.)

Sehen Sie sich ausführlich an, wie Ihr Programm physisch organisiert ist. Prüfen Sie, ob Sie Quelldateien kombinieren können, und vereinfachen Sie Ihre Hierarchie von # include-Dateien.

Unternehmen wie IBM haben dies vor Jahrzehnten verstanden und schreiben ihre Compiler so, dass dem Compiler eine Liste der zu kompilierenden Dateien übergeben werden kann, nicht nur eine Datei, und der Compiler würde nur einmal geladen.

0
John R. Strohm