2015-04-20 5 views
6

Ich habe ein Projekt, das ziemlich viel C++ - Vorlage Meta-Programmierung verwendet. Dies macht die Kompilierungszeiten lang. Ich verstehe, dass ich den Kuchen nicht haben und es auch essen kann, aber ich würde gerne einige Tipps und Tricks wissen, wie man kompilierte Zeiten reduziert. Ich habe bereits explizite Instanziierungen versucht, und obwohl dies in manchen Fällen hilfreich sein kann, sind die Instanzen oft für eine bestimmte Kompilierungseinheit einzigartig, in welchem ​​Fall explizite Instanziierung nichts hilft. Und jetzt reden wir nur über Clang, der einen ziemlich guten Job macht. Wenn ich dies auf G ++ versuche, explodiert die Kompilierzeit. Für eine Datei habe ich es aufgegeben, nach 45 Minuten darauf zu warten, dass sie kompiliert wird.Was sind Übeltäter für TMP-Langsamkeit

  • Gibt es irgendwelche Übeltäter, wenn es um Template-Metaprogrammierung geht, Dinge, von denen bekannt ist, dass sie oft problematisch sind? Welche Techniken sollte ich vermeiden und was sollte ich stattdessen tun?
  • Gibt es Bereiche, in denen GCC bekanntermaßen schlechter abschneidet als Clang und gibt es eine Möglichkeit, dies zu umgehen?
  • Ich benutze meist einfache C++ 11 Techniken, ich benutze keine Boost MPL oder ähnliche Bibliotheken.

    Antwort

    0

    In unseren Projekten haben wir nur gedacht und getestet. I.e. Zuerst denken wir "was sind die komplexen Vorlagen hier" und dann haben wir versucht, diese Vorlagen zu isolieren oder sie zu entfernen oder zu refaktorieren, um zu sehen, ob sich die Kompilierzeit ändert. Oft wird die Zeit für die Kompilierung von Templates von einer erhöhten Speicherauslastung begleitet. Ich habe sogar einmal einen gcc-Bug gemeldet (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54056).

    Es gibt einen weiteren Trick, der mehrmals geholfen hat, indem Sie den Befehlszeilenschalter -Q verwenden (Funktionen anzeigen, die gcc gerade kompiliert). Z.B. Für den oben verlinkten Fehler war klar, dass gcc bei diesen fehlerhaften Vorlagen langsamer wurde.

    2

    Hier sind einige in Bezug auf metaprogramming mit C++ 11 berät und darüber hinaus:

    • variadische Expansion Bevorzugen basierte Algorithmen. Variadische Vorlagen werden in der Regel schnell vom Compiler gehandhabt, verglichen mit der O (n) -Kette von Template-Instanziierungen, die normalerweise für Typlisten benötigt werden und sich auf altes C++ 98/03 beziehen. Ich bin gespannt auf C++ 1z Falten Ausdrücke, als eine Möglichkeit, fold Familie Metafuntcitons mit Pack-Erweiterung zu implementieren.

    • Vermeiden Sie Vererbungsketten: Algorithmen, die auf rekursiver Vererbung basieren, funktionieren normalerweise schlecht, da der Compiler die Vererbungsbaum-Metadaten verfolgen sollte. Bevorzugen Sie rohe Anrufe zum nächsten ::type, anstatt direkt vom nächsten "Anruf" als Kurzschrift zu erben, um das type Mitglied zu erhalten.

    • Bevorzugen Vererbung Expansion Pack auf rekursive Vererbung: Das heißt, wenn Sie ein Tupel wie Sache implementieren, bevorzugen

      template<typename... Ts> 
      struct tuple : Ts... 
      

      zu

      template<typename Head, typename... Tail> 
      struct tuple : Head, tuple<Tail...> 
      

      da der Compiler sollte N-Subtypen intantiate zu letzterem plus den oben beschriebenen Vererbungsaufwand.

    • Bevorzugter Namen Lookup-basierte Algorithmen: Name Suche führt in der Regel schneller als rekursive Vorlage Instanziierung.Überlegen Sie sich also, ob Sie etwas wie decltype(declval<T>().f()) ausführen, um einen Typ zu berechnen, bei dem das Ergebnis in der richtigen f-Überladung ist.

    +0

    Leider sind das Dinge, die ich schon mache. Einige Dinge, die ich wirklich kompilierte Zeiten fand, war meine Verwendung von 'std :: make_shared' und' std :: shared_ptr'. Ich ersetzte diese durch meine eigene Referenzzählung mit 'std :: atomic', da ich sowieso eine Art Löschung vornahm. –

    +0

    @EmilEriksson Es ist möglich, 'std :: shared_ptr' zu verwenden und nicht zu viel zusätzlichen Overhead zu bekommen http://blog2.emptycrate.com/content/template-code-bloat-revisited-smaller-makeshared – lefticus

    +0

    In diesem Fall sogar Wenn ich die Anzahl der 'std :: shared_ptr'-Instanziierungen reduzieren würde, hätte ich immer noch zu viele von ihnen und 'std :: shared_ptr' ist teurer zu instanziieren als meine eigene Implementierung. Natürlich ist es aus einem guten Grund teuer, dass Flexibilität für eine Standardbibliotheksklasse erforderlich ist, die überall verwendet wird. Aber ich habe einen sehr spezifischen Anwendungsfall und konnte daher die Kompilierzeiten durch eine andere Lösung reduzieren. –