63 votes

Comment accélérer le temps de compilation de g++ (quand on utilise beaucoup de templates)

Cette question est peut-être un peu bizarre, mais comment puis-je accélérer le temps de compilation de g++ ? Mon code C++ utilise beaucoup boost et les templates. J'ai déjà déplacé autant que possible les fichiers d'en-tête et utilisé l'option -j, mais la compilation (et l'édition de liens) prend encore beaucoup de temps.

Existe-t-il des outils qui analysent mon code et signalent les goulots d'étranglement au compilateur ? Ou peut-on en quelque sorte profiler le compilateur qui fonctionne sur mon code ? Ce serait vraiment bien, parce que parfois j'ai l'impression d'avoir passé trop de temps à regarder le journal de la console du compilateur...

49voto

strager Points 41713

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

  • Construit sur un système de fichiers RAM. C'est trivial sous Linux. Vous voudrez peut-être garder une copie des fichiers d'en-tête communs (précompilés ou les fichiers .h réels) sur le système de fichiers RAM également.
  • En-têtes précompilés . J'en ai un par bibliothèque (majeure) (par exemple Boost, Qt, stdlib).
  • Déclarez les classes au lieu de les inclure lorsque cela est possible. Cela réduit les dépendances, et donc le nombre de fichiers qui doivent être recompilés lorsque vous modifiez un fichier d'en-tête.
  • Paralléliser la fabrication . Cela permet généralement d'aider au cas par cas, mais j'ai -j3 globalement pour la marque. Assurez-vous que vos graphes de dépendances sont corrects dans votre Makefile, cependant, ou vous pourriez 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 que vous ne vous souciiez pas trop de l'impact (probablement faible) sur les performances).
  • Compilez à chaque fois que vous enregistrez. Certaines personnes n'aiment pas cela, mais cela vous permet de voir les erreurs rapidement et peut être fait en arrière-plan, ce qui réduit le temps d'attente lorsque vous avez fini d'écrire et que vous êtes prêt à tester.

17voto

Sam Miller Points 14976

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

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

17voto

Nordic Mainframe Points 13717

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

Les longs temps de compilation avec du code de template profond (boost etc.) sont souvent dus au comportement asymptotique peu amical de gcc lorsqu'il s'agit de l'instanciation de template, en particulier lorsque des templates variadiques sont émulés avec des arguments par défaut de template.

Voici un document qui cite la réduction du temps de compilation comme motivation pour les modèles variadiques :

cpptruths a publié un article expliquant que gcc-4.5 est bien meilleur dans ce domaine et qu'il est très performant avec ses modèles variadiques :

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

UPDATE : Il y a aussi un bon fil de discussion avec des techniques générales pour accélérer la compilation ici sur SO qui pourrait être utile :

UPDATE : Cette question concerne les problèmes de performances lors de la compilation de modèles, la réponse acceptée recommande également gcc-4.5, et clang est également mentionné comme un exemple positif :

10voto

viraptor Points 12779

Si vous faites beaucoup de recompilation, ccache pourrait aider. Cela n'accélère pas vraiment 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 si compliquées que l'on se retrouve avec la même étape de compilation lors d'une nouvelle construction.

Idée supplémentaire : si votre code se compile avec clang Il faut l'utiliser à la place. Il est généralement plus rapide que le gcc.

3voto

utnapistim Points 12060

En plus de ce que tout le monde a ajouté et de ce que vous faites déjà (construction parallélisée, options de compilation, etc.), envisagez de cacher les modèles dans les classes d'implémentation, auxquelles on accède par des interfaces. Cela signifie qu'au lieu d'avoir une classe comme :

// ClsWithNoTemplates.h file, included everywhere

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

public:
    void FunctionUsingYourMember();
};

vous devriez avoir :

// 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
};

Cela modifie un peu votre conception de la POO, mais c'est pour le mieux : l'inclusion de la définition de "ClsWithNoTemplates" est maintenant rapide et vous ne (pré)compilez la définition de "ClsWithNoTemplates" qu'une seule fois.

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

Ce changement devrait augmenter considérablement votre temps de compilation partielle, et il sera également utile dans le cas où votre ClsWithNoTemplates est une interface publique exportée à partir d'un fichier de bibliothèque : puisque le fichier n'est pas modifié lorsque vous ne changez que l'implémentation, votre code client dépendant n'a pas besoin d'être recompilé du tout.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X