269 votes

Clang vs GCC - lequel produit des binaires plus rapides ?

J'utilise actuellement GCC, mais j'ai découvert Clang récemment et j'envisage de le changer. Il y a cependant un facteur décisif : la qualité (vitesse, empreinte mémoire, fiabilité) des binaires produits. gcc -O3 peut produire un binaire qui s'exécute 1% plus vite, ou que les binaires Clang prennent plus de mémoire ou échouent simplement à cause de bogues du compilateur, c'est un cas de rupture.

Clang peut se vanter d'avoir une meilleure vitesse de compilation et une empreinte mémoire plus faible que GCC, mais je suis vraiment intéressé par les benchmarks/comparaisons des logiciels compilés qui en résultent. Pourriez-vous m'indiquer des ressources préexistantes ou vos propres benchmarks ?

8 votes

Il semble que la question et les réponses soient tout de même intéressantes, et beaucoup sont intéressés.

13 votes

@YasserAsmi : Et les deux métriques - empreinte mémoire et vitesse d'exécution - sont loin d'être arbitraires ou sujettes à "opinion". Mais il semble que la maladie de Physics.SE se propage ici et les gens ont commencé à voter pour fermer sans lire les détails du texte de la question ici aussi.

19 votes

La question demande des repères et des comparaisons, la réponse donne les deux ... pourquoi est-ce une opinion au lieu d'une comparaison factuelle ?

286voto

Mike Kinghan Points 4567

Voici quelques-unes de mes découvertes récentes, bien que limitées, avec GCC 4.7.2 et Clang 3.2 pour C++.

MISE À JOUR : comparaison entre GCC 4.8.1 et clang 3.3 jointe ci-dessous.

MISE À JOUR : la comparaison entre GCC 4.8.2 et clang 3.4 est ajoutée à cela.

Je maintiens un outil OSS qui est construit pour Linux avec GCC et Clang, et avec le compilateur de Microsoft pour Windows. L'outil, coan est un préprocesseur et un analyseur de fichiers sources C/C++ et de leurs lignes de code : son profil de calcul est axé sur l'analyse syntaxique par descente récursive et le traitement des fichiers. La branche de développement (à laquelle ces résultats se rapportent) comprend actuellement environ 11K LOC dans environ 90 fichiers. Elle est codée, maintenant, en C++ qui est riche en polymorphisme et en templates mais qui est encore mais est encore embourbé dans de nombreux correctifs par son passé pas si lointain en C bricolé. La sémantique des déplacements n'est pas expressément exploitée. Le programme est monofilaire. I n'ai pas consacré d'effort sérieux à son optimisation, alors que l'"architecture" reste reste si largement à faire.

J'ai utilisé Clang avant la version 3.2 uniquement comme compilateur expérimental. car, en dépit de sa vitesse de compilation et de ses diagnostics supérieurs, son support de la norme C++11 était en retard sur la version contemporaine de GCC dans le dans les domaines exercés par coan. Avec la version 3.2, cet écart a été comblé.

Mon harnais de test Linux pour les processus de développement actuels de coan, en gros 70K fichiers sources dans un mélange de cas de tests d'analyseurs de fichiers, de tests de des tests de stress consommant des milliers de fichiers et des tests de scénario consommant moins de 1 000 fichiers.

En plus de rapporter les résultats des tests, le harnais accumule et et affiche les totaux de fichiers consommés et le temps d'exécution consommé dans coan (il passe simplement chaque ligne de commande coan à l'ordinateur Linux). time le commandement et les captures et additionne les chiffres rapportés). Les chronologies sont flattées par le fait que n'importe quel nombre de tests qui prennent 0 temps mesurable s'additionneront tous à 0, mais la contribution de tels tests est négligeable. Les statistiques de temps sont affichées à la fin de la commande make check comme ça :

coan_test_timer: info: coan processed 70844 input_files.
coan_test_timer: info: run time in coan: 16.4 secs.
coan_test_timer: info: Average processing time per input file: 0.000231 secs.

J'ai comparé les performances du harnais de test entre GCC 4.7.2 et Clang 3.2. Clang 3.2, toutes choses étant égales sauf les compilateurs. A partir de Clang 3.2, je n'ai plus besoin de différencier les préprocesseurs entre le code de code que GCC compile et les alternatives de Clang. J'ai construit à partir de la même bibliothèque C++ (celle de GCC) dans chaque cas et j'ai effectué toutes les comparaisons consécutivement dans la même session de terminal.

Le niveau d'optimisation par défaut de ma version est -O2. J'ai également testé avec succès les builds à -O3. J'ai testé chaque configuration 3 configuration 3 fois de suite et j'ai calculé la moyenne des 3 résultats, avec les résultats suivants. Le nombre dans une cellule de données est le nombre moyen de de microsecondes consommées par l'exécutable coan pour traiter chacun des chacun des ~70K fichiers d'entrée (lecture, analyse et écriture de la sortie et des diagnostics).

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.7.2 | 231 | 237 |0.97 |
----------|-----|-----|-----|
Clang-3.2 | 234 | 186 |1.25 |
----------|-----|-----|------
GCC/Clang |0.99 | 1.27|

Toute application particulière a de fortes chances de présenter des caractéristiques qui jouent un rôle important dans le processus de développement. les forces ou les faiblesses d'un compilateur. Un benchmarking rigoureux fait appel à diverses applications. Avec ce bien à l'esprit, le remarquable caractéristiques de ces données sont :

  1. -L'optimisation de l'O3 a été marginalement préjudiciable au CCG.
  2. -L'optimisation de O3 a été très bénéfique pour Clang.
  3. Avec l'optimisation -O2, GCC était plus rapide que Clang d'un rien.
  4. Avec l'optimisation -O3, Clang était nettement plus rapide que GCC.

Une autre comparaison intéressante entre les deux compilateurs est apparue par hasard. peu de temps après ces découvertes. Coan utilise généreusement des pointeurs intelligents et l'un d'entre eux est fortement utilisé dans la gestion des fichiers. Ce type particulier de Ce type particulier de smart-pointer avait été typographié dans les versions précédentes dans un souci de de la différenciation du compilateur, pour être un pointeur intelligent. std::unique_ptr<X> si le compilateur configuré avait un support suffisamment mature pour son utilisation comme que, et sinon un std::shared_ptr<X> . Le parti pris de std::unique_ptr était stupide, puisque ces pointeurs étaient en fait transférés, mais std::unique_ptr semble être l'option la plus appropriée pour remplacer std::auto_ptr à un moment où les variantes de C++11 étaient nouvelles pour moi.

Au cours des constructions expérimentales visant à évaluer le besoin continu de Clang 3.2 pour cette différenciation et d'autres similaires, j'ai construit par inadvertance std::shared_ptr<X> alors que j'avais l'intention de construire std::unique_ptr<X> , et j'ai été surpris d'observer que l'exécutable résultant, avec l'optimisation par défaut -O2 par défaut, était le plus rapide que j'avais vu, atteignant parfois 184 msec. par fichier d'entrée. Avec cette seule modification du code source, les résultats correspondants étaient les suivants ;

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.7.2 | 234 | 234 |1.00 |
----------|-----|-----|-----|
Clang-3.2 | 188 | 187 |1.00 |
----------|-----|-----|------
GCC/Clang |1.24 |1.25 |

Les points à noter ici sont les suivants :

  1. Aucun des deux compilateurs ne bénéficie désormais de l'optimisation -O3.
  2. Clang bat GCC de manière tout aussi importante à chaque niveau d'optimisation.
  3. Les performances de GCC ne sont que marginalement affectées par le type smart-pointer changement.
  4. Les performances de Clang en -O2 sont fortement affectées par le changement de type de smart-pointer changement.

Avant et après le changement de type de smart-pointer, Clang est capable de construire un fichier exécutable coan sensiblement plus rapide avec une optimisation -O3, et il peut construire un exécutable tout aussi rapide à -O2 et -O3 lorsque le type de type de pointeur est le meilleur - std::shared_ptr<X> - pour le poste.

Une question évidente sur laquelle je ne suis pas compétent pour me prononcer est la suivante pourquoi Clang devrait être capable de trouver une accélération de 25% -O2 dans mon application lorsque un type de pointeur intelligent très utilisé est changé d'unique à partagé, alors que GCC est indifférent à ce même changement. Je ne sais pas non plus si je dois me réjouir ou me lamenter de la découverte que l'optimisation -O2 de Clang abrite une telle sensibilité à la sagesse de mes choix de smart-pointer.

MISE À JOUR : GCC 4.8.1 v clang 3.3

Les résultats correspondants sont maintenant :

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.1 | 442 | 443 |1.00 |
----------|-----|-----|-----|
Clang-3.3 | 374 | 370 |1.01 |
----------|-----|-----|------
GCC/Clang |1.18 |1.20 |

Le fait que les quatre exécutables prennent maintenant un temps moyen beaucoup plus important que précédemment pour être traités 1 fichier ne no reflètent les performances des derniers compilateurs. Elle est due au fait que la branche de développement ultérieure de l'application de test a pris beaucoup de sophistication de l'analyse syntaxique entre-temps et qu'elle le paie en vitesse. Seuls les ratios sont significatifs.

Les points à noter maintenant ne sont pas d'une nouveauté étonnante :

  • GCC est indifférent à l'optimisation de -O3
  • clang bénéficie très marginalement de l'optimisation -O3
  • clang bat GCC par une marge tout aussi importante à chaque niveau d'optimisation.

En comparant ces résultats avec ceux de GCC 4.7.2 et clang 3.2, on constate que GCC a récupéré environ un quart de l'avance de clang à chaque niveau d'optimisation. Mais Mais comme l'application de test a été fortement développée entre temps, on ne peut pas On ne peut pas attribuer cela avec certitude à un rattrapage dans la génération de code de GCC. (Cette fois, j'ai noté le snapshot de l'application à partir duquel les timings ont été obtenus et je peux à nouveau l'utiliser).

MISE À JOUR : GCC 4.8.2 v clang 3.4

J'ai terminé la mise à jour pour GCC 4.8.1 v Clang 3.3 en disant que je m'en tiendrais au même snaphot coan pour les mises à jour ultérieures. m'en tenir au même snaphot coan pour les futures mises à jour. Mais j'ai décidé plutôt de tester sur ce snapshot (rev. 301) y sur les derniers développements que j'ai et qui passe sa suite de tests (rev. 619). Cela donne aux résultats un un peu de longitude, et j'avais un autre motif :

Mon message initial indiquait que je n'avais pas fait d'efforts pour optimiser la vitesse de coan. vitesse. C'était toujours le cas à la rev. 301. Cependant, après avoir intégré l'appareil de chronométrage dans le harnais de test de coan, chaque fois que j'exécutais la suite de tests l'impact sur les performances des derniers changements me regardait en face. J'ai vu que J'ai vu qu'il était souvent étonnamment grand et que la tendance était plus fortement négative que ce que je pensais être mérité par les gains de performance. que ce que je pensais être mérité par les gains de fonctionnalité.

Par rev. 308, le temps de traitement moyen par fichier d'entrée dans la suite de tests avait plus que doublé depuis la première publication ici. À ce moment-là, j'ai fait un j'ai fait volte-face sur ma politique de 10 ans de ne pas me soucier des performances. Dans l'intense de révisions jusqu'à la 619, les performances ont toujours été prises en compte et un grand nombre d'entre elles étaient purement destinées à réactualiser le système. et un grand nombre d'entre elles ont été purement consacrées à la réécriture de porteurs de charge clés sur des supports fondamentalement plus rapides (sans toutefois utiliser de fonctionnalités de compilation non standard pour ce faire). Il serait intéressant de voir la réaction de chaque compilateur à cette volte-face,

Voici la désormais familière matrice des timings pour les deux derniers compilateurs de la rev.301 :

coan - résultats rev.301

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.2 | 428 | 428 |1.00 |
----------|-----|-----|-----|
Clang-3.4 | 390 | 365 |1.07 |
----------|-----|-----|------
GCC/Clang | 1.1 | 1.17|

L'histoire ici n'a que peu changé depuis GCC-4.8.1 et Clang-3.3. Les résultats de GCC est un peu meilleure. Celle de Clang est un peu moins bonne. Le bruit pourrait bien expliquer ce phénomène. Clang est toujours en avance de -O2 y -O3 des marges qui n'auraient pas d'importance dans la plupart applications, mais qui auraient de l'importance pour certaines d'entre elles.

Et voici la matrice pour la révision 619.

coan - rev.619 résultats

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.2 | 210 | 208 |1.01 |
----------|-----|-----|-----|
Clang-3.4 | 252 | 250 |1.01 |
----------|-----|-----|------
GCC/Clang |0.83 | 0.83|

Si l'on prend côte à côte les chiffres de la 301 et de la 619, plusieurs points ressortent.

  • Je cherchais à écrire du code plus rapide, et les deux compilateurs confirment catégoriquement mes efforts. Mais :

  • GCC rembourse ces efforts bien plus généreusement que Clang. Sur -O2 optimisation La version 619 de Clang est 46% plus rapide que la version 301 : à -O3 L'outil de Clang est de 31%. Bon, mais à chaque niveau d'optimisation, la compilation 619 de GCC est plus de deux fois plus rapide que sa 301.

  • GCC fait plus que renverser l'ancienne supériorité de Clang. Et à chaque niveau d'optimisation d'optimisation, GCC bat maintenant Clang de 17%.

  • La capacité de Clang, dans la build 301, à obtenir plus d'effet de levier que GCC à partir de -O3 optimisation a disparu dans la version 619. Aucun des deux compilateurs ne bénéficie de manière significative de -O3 .

J'ai été suffisamment surpris par ce retournement de situation pour me douter que je que j'avais peut-être accidentellement fait une construction lente de clang 3.4 lui-même (puisque je l'ai construit source). J'ai donc refait le test 619 avec la version 3.3 de Clang de ma distribution. Les résultats de résultats étaient pratiquement les mêmes que pour la version 3.4.

En ce qui concerne la réaction à la volte-face : Sur les chiffres ici, Clang a fait bien mieux mieux que GCC pour tirer de la vitesse de mon code C++ alors que je ne lui donnais aucune aide. d'aide. Lorsque je me suis appliqué à l'aider, GCC a fait un bien meilleur travail que Clang.

Je n'élève pas cette observation au rang de principe, mais je prends mais je retiens que "Quel compilateur produit les meilleurs binaires ? qui, même si vous spécifiez la suite de test à laquelle la réponse doit être relative, n'est toujours pas une question claire et nette de chronométrage des binaires.

Votre meilleur binaire est-il le binaire le plus rapide, ou est-ce celui qui est le plus rapide ? qui compense le mieux un code fabriqué à bas prix ? Ou qui compense le mieux coûteux un code élaboré qui privilégie la maintenabilité et la réutilisation à la vitesse ? Cela dépend de la nature et du poids relatif de vos motivations pour produire le binaire, ainsi que des les contraintes sous lesquelles vous le faites.

Et dans tous les cas, si vous vous souciez de construire les "meilleurs" binaires, alors vous devriez vous feriez mieux de continuer à vérifier comment les itérations successives de compilateurs délivrent idée de "meilleur" sur des itérations successives de votre code.

50voto

Nietzche-jou Points 7711

Phoronix a fait quelques benchmarks à ce sujet, mais il s'agit d'une version snapshot de Clang/LLVM datant de quelques mois. Les résultats étant que les choses étaient plus ou moins poussées ; ni GCC ni Clang n'est définitivement meilleur dans tous les cas.

Puisque vous utilisez la dernière version de Clang, c'est peut-être un peu moins pertinent. Mais encore une fois, GCC 4.6 est prévu pour avoir quelques optimisations majeures para Core 2 y Core i7 apparemment.

Je me dis que la vitesse de compilation plus rapide de Clang sera plus agréable pour les développeurs originaux, et ensuite, lorsque vous pousserez le code dans le monde, la distribution Linux, BSD Les utilisateurs finaux utiliseront GCC pour les binaires les plus rapides.

2 votes

Aujourd'hui, j'ai effectué quelques benchmarks sur la vitesse de compilation de Clang et c'est très décevant pour du C pur. En compilant 35 fichiers C avec 270 KLOC, Clang était seulement 25% plus rapide. Quand je vois la vitesse de tinycc sur linux, c'est un mauvais résultat pour un compilateur nouvellement écrit. Il s'améliore en utilisant les optimisations -O2/-O3 mais comme elles sont utilisées pour la version finale, les performances du compilateur n'ont pas d'importance dans ce cas.

7 votes

@mcandre Peut-être que Nietzche-jou a été compilé avec Clang, alors que vous avez été compilé avec GCC.

20voto

mcandre Points 6965

Le fait que Clang compile le code plus rapidement peut ne pas être aussi important que la vitesse du binaire résultant. Cependant, voici un série de points de référence .

14 votes

En fait, c'est le cas. Pendant le développement, le temps de compilation (et la consommation de ressources due à la compilation) est un goulot d'étranglement bien plus important que les performances binaires. Après tout, nous compilons en mode Debug à ce stade. Ce n'est que lorsque vient l'étape du test et de l'expédition que l'on passe en mode Release et que l'on essaie d'obtenir un binaire aussi rapide que possible.

4 votes

Matthieu M : Je jure que cette réponse disait "peut ", comme s'il soulevait un problème potentiel. Je suppose que cela valait peut-être la peine d'être mentionné parce que c'était, vous savez, lié à l'OP.

0 votes

D'accord, bien que tous les points soient bons ici. Je préférerais ajouter un deuxième ou un troisième disque RAID 0, un SSD ou une mémoire vive plus importante et plus rapide pour obtenir les meilleures performances .exe, à condition que ces mesures vous permettent d'atteindre la parité ou une valeur proche. Il est aussi parfois utile de développer avec plus d'un compilateur. Il peut vous faire prendre conscience de fonctionnalités non portables, ET attraper des erreurs qui, autrement, ne seraient pas détectées ou entraîneraient des jours de perte de temps à essayer de déboguer du code sur lequel un meilleur compilateur vous aurait averti/erré.

12voto

Atom Points 8739

Il y a très peu de différence globale entre GCC 4.8 et Clang 3.3 en termes de vitesse du binaire résultant. Dans la plupart des cas, le code généré par les deux compilateurs se comporte de manière similaire. Aucun de ces deux compilateurs ne domine l'autre.

Les benchmarks indiquant qu'il existe un écart de performance significatif entre GCC et Clang sont une coïncidence.

Les performances des programmes sont affectées par le choix du compilateur. Si un développeur ou un groupe de développeurs utilise exclusivement GCC, on peut s'attendre à ce que le programme s'exécute légèrement plus vite avec GCC qu'avec Clang, et vice versa.

Du point de vue des développeurs, une différence notable entre GCC 4.8+ et Clang 3.3 est que GCC dispose de l'option -Og option de ligne de commande. Cette option permet d'activer des optimisations qui n'interfèrent pas avec le débogage, de sorte que, par exemple, il est toujours possible d'obtenir des traces de pile précises. L'absence de cette option dans Clang rend l'utilisation de Clang comme compilateur optimisant plus difficile pour certains développeurs.

0 votes

Ces derniers temps (3.3 et 4.8), je ne vois même pas une grande différence entre les temps de compilation. (dans "mes" programmes avec des temps de compilation entre 10 secondes et 30 secondes).

10voto

Paul R Points 104036

La seule façon de le déterminer est de l'essayer. Pour information, j'ai constaté de très bonnes améliorations en utilisant le logiciel Apple's LLVM GCC 4.2 comparé au GCC 4.2 normal (pour le code x86-64 avec beaucoup de SSE), mais YMMV pour différentes bases de code.

En supposant que vous travaillez avec x86/x86-64 et que vous vous souciez vraiment des derniers pourcentages, vous devez essayer la solution d'Intel. ICC Vous pouvez obtenir une licence d'évaluation de 30 jours sur intel.com et l'essayer.

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