Profilerstellung des C ++ - Kompilierungsprozesses


79

Ich neige dazu, ziemlich große C ++ - Bibliotheken nur mit Headern zu schreiben, und meine Benutzer beschweren sich häufig über Kompilierungszeiten. Nachdem ich über die Sache nachgedacht hatte, kam mir der Gedanke , dass ich keine Ahnung habe, wohin die Zeit geht . Gibt es eine einfache Möglichkeit, den C ++ - Kompilierungsprozess mit gängigen Compilern wie g ++, icc und xlC zu profilieren? Ist es beispielsweise möglich, eine Vorstellung davon zu bekommen, wie viel Zeit in jeder der Phasen der C ++ - Kompilierung verbracht wird ?



2
@KarthikT Ich schätze den Vorschlag, aber ich interessiere mich für viel feinkörnigere Informationen als diese (und für eine größere Anzahl von Compilern). Wenn ich beispielsweise eine Objektdatei aus einer Nur-Header-Bibliothek erstelle, wie kann ich dann sehen, wo die Zeit vergangen ist?
Jack Poulson

Ich verstehe, ich kann nichts Feinkörnigeres finden, sorry.
Karthik T

Antworten:


66

Für GCC gibt es Debugging-Optionen zu findenhow much time is spent within each of the phases of C++ compilation?

-Q Lässt den Compiler jeden Funktionsnamen beim Kompilieren ausdrucken und nach Abschluss einige Statistiken zu jedem Durchgang drucken.

-ftime-report Lässt den Compiler einige Statistiken über die Zeit drucken, die jeder Durchgang nach Abschluss benötigt.

Passes werden in GCCINT 9: Passes und Dateien des Compilers beschrieben .

Sie können die Ausgabe der g ++ - Kompilierung einer einzelnen Quelldatei -v -ftime-reporthier veröffentlichen, um dies zu diskutieren . Es könnte Hilfe auf der GCC- Mailingliste geben .


Für andere Compiler als GCC (oder GCC älter als 3.3.6 ) siehe die anderen Optionen in diesem Thread.


2
PS: Die -QAusgabe kann von einem awk- oder perl-Skript erfasst, analysiert und analysiert werden. oder Sie können einfach beim Drucken von Funktionsnamen auf der Konsole zusehen, welche nach langer Pause gedruckt wurde, war schwer zu kompilieren.
Osgx

Irgendeine Idee, wie man Timing an die Funktionsnamen anfügt (kurz vor dem Hacken von g ++)? Ich habe eine 200-MB-Datei mit einem Spaghetti-Durcheinander von Funktionen und keine Ahnung, welche Funktion lange zum Kompilieren benötigt hat. Sie werden meistens schnell kompiliert, es gibt nur viele von ihnen (es ist auch ein vorlagenlastiger Code). Ich dachte an eine Pipe und ein Skript, aber Pipes haben einen Puffer und die Funktionen mit Kurznamen werden möglicherweise erst dann angezeigt, wenn mehr gedruckt werden.
das Schwein

1
Versuchen Sie, 'quiet_flag' in gcc / cgraphunit.c zu erfassen und gcc/toplev.c( announce_function - "Wenn der Start einer Funktionsdefinition analysiert wird, druckt diese Funktion auf stderr den Namen der Funktion"). Dies announce_functionkann der Punkt sein, an dem der Zeitstempel (gettimeofday) gedruckt oder die Ausgabe ungepuffert neu geschrieben werden soll. Oder die andere Möglichkeit besteht darin, Debug-Dumps ( -fdump-rtl-all-all -fdump-tree-all-all -fdump-ipa-all-all) zu aktivieren, die jedoch 1 Datei pro Durchgang ausgeben. Sie müssen sie konvertieren, um 1 Datei pro Durchgang und pro Funktion auszugeben (viele Dateien mit Erstellungszeit erhalten).
Osgx

14

Es gibt ein Tool aus dem Boost-Projekt, das für so ziemlich jeden Compiler und jedes Build-System nützlich sein kann.

Das Tool erfordert eine Quellcode-Instrumentierung mit TEMPLATE_PROFILE_ENTER()und TEMPLATE_PROFILE_EXIT()Makroaufrufen. Diese Makros generieren dann zur Kompilierungszeit spezifische Diagnosen (Warnungen), die zeitgesteuert und zusammen mit Instanziierungs-Callstacks (die folglich das Erstellen und Visualisieren von Callgraphs ermöglichen) durch ein Skript erfasst werden. Nicht schlecht, IMO.

Ich habe es aber noch nicht benutzt.


Auf der Dokumentationsseite sehe ich keine Notwendigkeit für eine Quellcode-Instrumentierung. Wo hast du das gelesen?
Lrineau

@Irineau, in der Quelle. Das Tool bietet auch einige Skripte, die die Instrumentierung scheinbar automatisch ausführen (allerdings mit unbekanntem Grad an Granularität).
Ulidtko

1
Der Link ist tot.
Rustyx

Nun, @rustyx, das ist kein Wunder, wenn man svn .boost.org in der URL und im 21. Jahrhundert auf der Uhr sieht ... Hat jemand eine Gabel / einen Spiegel / ein Umschreiben hochgeladen ? aber vielleicht hilft das.
ulidtko

8

Clang 9 (und neuer) verfügt über ein -ftime-traceFlag, mit dem ein Profilbericht als JSON (zusätzlich zu einer Objektdatei) ausgegeben wird.

Sie können diese Datei in einen mit Chrome ( chrome://tracing) gelieferten Profiler importieren , um eine schöne Visualisierung zu erhalten:

Bild

Die Balken entsprechen Headern, die analysiert werden mussten, und für jeden Header bestimmten Klassen (und wahrscheinlich anderen Konstrukten), die analysiert werden mussten. Außerdem wird die Zeit angegeben, die für die Instanziierung bestimmter Vorlagen aufgewendet wurde.



5

Sie können sie bis zu einem gewissen Grad trennen (ich nehme an make)

  • Fügen Sie eine Build-Regel hinzu, die nur Dateien vorverarbeitet (mithilfe des -ESchalters), und ein .PHONYZiel, das von den Präprozessor-Ausgabedateien abhängt, hängt genau wie das normale binäre Ziel von .oDateien ab. Messen Sie, wie lange es dauert, dieses Ziel zu erstellen
  • Fügen Sie ein 'PHONYZiel hinzu, das von allen .oDateien abhängt , diese jedoch nicht verknüpft. Messen Sie, wie lange es dauert, dieses Ziel zu erstellen (von sauber)
  • Messen Sie, wie lange es dauert, einen sauberen Build der üblichen Binärdatei zu erstellen

Jetzt haben Sie eine Vorstellung davon, wie lange das Vorverarbeiten, Kompilieren und Verknüpfen dauert. Sie können auch optimierte und nicht optimierte ( -O0) Versionen des zweiten und dritten Ziels vergleichen, um festzustellen, wie lange im Optimierer verbracht wird.


Danke für die Antwort. Ich denke, dass dies für C-Programme mehr als ausreichend wäre, aber für C ++ nur für Header, das nicht mehr als eine .o-Datei erstellt, wird fast die gesamte Zeit für die Erstellung der einzelnen .o-Datei aufgewendet. Ich stimme zu, drücke aber die Daumen, dass jemand einen feinkörnigeren Ansatz vorschlägt.
Jack Poulson

Ah, Sie interessieren sich also nicht so sehr für die Übersetzungsphasen, als für welches Codebit die meiste Zeit benötigt wird.
Useless

2
Wenn Sie clang / llvm verwenden, können Sie eine ähnliche Technik verwenden, um das Frontend (clang) vom Backend (llvm-opt) zu trennen. Im Backend können Sie sogar das Optimierungsdiagramm sichern und separat ausführen. In gcc können Sie die Erstellungszeit zwischen -O0 und -O3 vergleichen und den Unterschied zwischen der für die Optimierung aufgewendeten Zeit und der an anderer Stelle aufgewendeten Zeit feststellen. Sie können dann Optimierer selektiv aktivieren, um festzustellen, welcher der schlimmste Täter ist (falls vorhanden).
Ze Blob

2

Möglicherweise können Sie mit einer bestimmten Variante eine gewisse Traktion erzielen strace -e trace=process -f -r -ttt -T, zumindest für Compiler wie g ++, die in viele Prozesse unterteilt sind.


0

Andere haben bereits das -ftime-reportBefehlszeilenflag für GCC vorgeschlagen, wodurch der Compiler einige Statistiken über die von jeder Kompilierungsphase benötigte Zeit druckt. Der Nachteil ist, dass nur eine Zusammenfassung für eine Einheit angezeigt wird.

Ich habe ein Python- Skript geschrieben , mit dem die Gesamtzusammenfassung für jede Einheit in jeder Kompilierungsphase unter Berücksichtigung der Projekterstellungsprotokolldatei gedruckt werden kann. Es ermöglicht auch das Sortieren nach verschiedenen Phasen. Außerdem können zwei Protokolldateien verglichen werden (z. B. wenn Sie versuchen, die Auswirkungen Ihrer Änderungen zu verstehen).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.