Comment accélérer la compilation de g ++ (en utilisant beaucoup de templates)

Cette question est peut-être quelque peu étrange, mais comment puis-je accélérer la compilation de g ++? Mon code C ++ utilise fortement le boost et les templates. J’ai déjà déplacé le plus possible les fichiers d’en-tête et utilisé l’option -j, mais la compilation (et le lien) prend un certain temps.

Existe-t-il des outils d’parsing de mon code et des goulots d’étranglement pour le compilateur? Ou peut-on en quelque sorte profiler le compilateur exécuté sur mon code? Ce serait vraiment bien, car parfois j’ai l’impression que j’ai passé trop de temps à regarder le journal de la console du compilateur …

Ce qui m’a été le plus utile:

  • Construire sur un système de fichiers RAM. C’est sortingvial sur Linux. Vous souhaiterez peut-être également conserver une copie des fichiers d’en-tête communs (fichiers précompilés ou fichiers .h réels) sur le système de fichiers RAM.
  • En-têtes précompilés . J’ai une par bibliothèque (majeure) (ex: Boost, Qt, stdlib).
  • Déclarez au lieu d’inclure des classes si possible. Cela réduit les dépendances et réduit donc le nombre de fichiers à recomstackr lorsque vous modifiez un fichier d’en-tête.
  • Paralléliser faire . Cela aide généralement au cas par cas, mais j’ai -j3 globalement pour make. Assurez-vous que vos graphiques de dépendance sont corrects dans votre fichier Makefile, mais vous pouvez avoir des problèmes.
  • Utilisez -O0 si vous ne testez pas la vitesse d’exécution ou la taille du code (et que votre ordinateur est suffisamment rapide pour ne pas trop vous soucier de l’ -O0 (probablement faible) sur les performances).
  • Comstackz chaque fois que vous enregistrez. Certaines personnes n’aiment pas cela, mais cela vous permet de voir les erreurs plus tôt et peut être fait en arrière-plan, ce qui réduit le temps d’attente avant d’écrire et d’être prêt à tester.

Voici ce que j’ai fait pour accélérer les builds dans un scénario très similaire que vous décrivez (boost, templates, gcc)

  • construire sur le disque local au lieu d’un système de fichiers réseau comme NFS
  • mise à niveau vers une version plus récente de gcc
  • enquêter sur distcc
  • systèmes de construction plus rapides, en particulier plus de RAM

Je suppose que nous parlons de minutes pour comstackr un fichier, c’est-à-dire que les en-têtes précompilés ou les problèmes de disque local ne sont pas un problème.

Des temps de compilation longs avec un code de modèle profond (boost, etc.) sont souvent liés au comportement asymptotique peu accueillant de gcc en ce qui concerne l’instanciation des modèles, en particulier lorsque les modèles variadiques sont émulés avec des arguments par défaut.

Voici un document qui nomme le temps de compilation réduit comme motivation pour les modèles variadiques:

cpptruths avait un article sur la façon dont gcc-4.5 est bien meilleur dans ce domaine et comment il fonctionne brillamment avec ses modèles variadic:

IIRC, alors BOOST a un moyen de limiter la génération des parameters par défaut des modèles pour les pseudo-variadiques, je pense que ‘g ++ -DBOOST_MPL_LIMIT_LIST_SIZE = 10’ devrait fonctionner (la valeur par défaut est 20)

MISE À JOUR: Il existe également un bon fil avec des techniques générales pour accélérer la compilation ici sur SO, ce qui pourrait être utile:

  • Quelles techniques peuvent être utilisées pour accélérer les temps de compilation C ++?

MISE À JOUR: Celle-ci concerne les problèmes de performance lors de la compilation des modèles, la réponse acceptée recommande également gcc-4.5, le clang est également cité comme exemple positif:

  • Existe-t-il des compilateurs c ++ optimisés pour l’utilisation de modèles?

Si vous faites beaucoup de recompilation, ccache pourrait vous aider. Cela n’accélère pas réellement la compilation, mais cela vous donnera un résultat en cache si vous faites une recompilation inutile pour une raison quelconque. Cela peut donner l’impression de s’attaquer au mauvais problème, mais parfois les règles de reconstruction sont tellement compliquées que vous vous retrouvez avec la même étape de compilation lors d’une nouvelle construction.

Idée supplémentaire: si votre code comstack avec clang , utilisez-le à la place. C’est généralement plus rapide que gcc.

Outre ce que tout le monde a ajouté et ce que vous faites déjà (construction parallélisée, options du compilateur, etc.), envisagez de masquer les modèles dans les classes d’implémentation, accessibles via les interfaces. Cela signifie qu’au lieu d’avoir une classe comme:

 // ClsWithNoTemplates.h file, included everywhere class ClsWithTemplates { ComplicatedTemplate member; // ... public: void FunctionUsingYourMember(); }; 

tu aurais dû:

 // ClsWithNoTemplates.h file: class ClsWithTemplatesImplementation; // forward declaration // definition included in the ClsWithNoTemplates.cpp file // this class will have a ComplicatedTemplate 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 }; 

Cela modifie un peu la conception de votre POO, mais c’est pour le bien: inclure la définition de ‘ClsWithNoTemplates’ est maintenant rapide et vous ne comstackz que la définition de ‘ClsWithNoTemplates’ une fois.

De plus, si vous modifiez le code d’implémentation, tout code incluant ClsWithNoTemplates.h n’aura probablement pas besoin d’être redéfini.

Cette modification devrait considérablement augmenter votre temps de compilation partiel, et cela vous aidera également dans le cas où votre ClsWithNoTemplates est une interface publique exscope à partir d’un fichier de bibliothèque: puisque le fichier n’est pas modifié lorsque vous modifiez uniquement l’implémentation, votre code client dépendant nen ‘ t besoin d’être recompilé du tout.

Essayez la technique PIMPL, cette question: Quelles techniques peuvent être utilisées pour accélérer les temps de compilation C ++?

Cela empêchera le compilateur de suivre la chaîne des fichiers d’en-tête et des implémentations chaque fois que vous devez faire quelque chose.

S’il y a beaucoup de fichiers, vous pouvez accélérer la compilation en ayant juste un fichier .cpp qui inclut tous les autres fichiers .cpp. Cela exige bien sûr que vous soyez plus prudent avec les macros que vous avez déjà définies par fichier car elles seront désormais visibles par les autres fichiers cpp.

S’il y a beaucoup de fichiers, cela peut réduire considérablement le temps de compilation.

Instanciez moins de modèles et de fonctions en ligne. Précomstackr autant que vous le pouvez et lier le tout plutôt que de tout comstackr à partir de zéro. Assurez-vous d’utiliser la dernière version de GCC.

Toutefois, C ++ est un langage incroyablement complexe et sa compilation prend un certain temps.

Cet article décrit une méthode pour comstackr du code de modèle de la même manière que les fichiers object non traditionnels “classiques”. Enregistre la compilation et le temps de liaison, avec une seule ligne de code supplémentaire par instanciation de modèle.

Habituellement, les parties les plus coûteuses de la compilation sont (a) la lecture des fichiers source ( tous ) et (b) le chargement du compilateur en mémoire pour chaque fichier source.

Si vous avez 52 fichiers source (.cc), dont chacun comprend 47 fichiers #include (.h), vous allez charger le compilateur 52 fois, et vous allez parcourir 2496 fichiers. Selon la densité des commentaires dans les fichiers, vous passerez peut-être une bonne partie de votre temps à manger des personnages inutiles. (Dans une organisation que j’ai vue, les fichiers d’en-tête variaient entre 66% et 90% de commentaires, et seulement 10% à 33% du fichier étaient «significatifs». La meilleure chose à faire pour améliorer la lisibilité de ces fichiers était out tous les derniers commentaires, ne laissant que le code.)

Regardez attentivement comment votre programme est organisé physiquement. Vérifiez si vous pouvez combiner des fichiers source et simplifier votre hiérarchie de fichiers #include.

Il y a des décennies, des sociétés comme IBM comprenaient cela et écrivaient leurs compilateurs pour que le compilateur puisse recevoir une liste de fichiers à comstackr, pas seulement un fichier, et le compilateur ne serait chargé qu’une seule fois.

Comstackr avec g ++ en utilisant plusieurs cœurs

Comstackr avec g ++ en utilisant plusieurs cœurs