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 :
- -L'optimisation de l'O3 a été marginalement préjudiciable au CCG.
- -L'optimisation de O3 a été très bénéfique pour Clang.
- Avec l'optimisation -O2, GCC était plus rapide que Clang d'un rien.
- 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 :
- Aucun des deux compilateurs ne bénéficie désormais de l'optimisation -O3.
- Clang bat GCC de manière tout aussi importante à chaque niveau d'optimisation.
- Les performances de GCC ne sont que marginalement affectées par le type smart-pointer changement.
- 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.
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 ?
3 votes
Il n'y a rien de fondé sur une opinion à demander quel compilateur produit les meilleurs binaires !
2 votes
@BjörnLindqvist Vraiment, vraiment ? Vous pensez que l'ensemble des binaires produits pour le même code source par différents compilateurs est un ensemble totalement ordonné, alors ? Nous pouvons les classer ? Et tout le monde serait d'accord sur le classement ? Et le classement serait le même pour la plupart des sources ? Il y aurait donc un compilateur clairement meilleur, un autre clairement second, etc ? Parce que tous il faudrait que ce soit vrai, pour que cette question no de se fonder sur des opinions.
0 votes
Oui, vraiment. Vous pouvez commander des compilateurs en exactement de la même manière que vous pouvez commander les coureurs les plus rapides du monde. Puisque les coureurs sont couramment commandés par des concours (benchmarks), les compilateurs peuvent évidemment être commandés aussi.
0 votes
@BjörnLindqvist Si la vitesse d'exécution est la seule chose qui compte, alors c'est un peu vrai, même si cela peut varier d'un projet à l'autre. Mais qu'en est-il de la correction ? De la stabilité ? De la vitesse de compilation ? Et la réputation d'un projet de corriger rapidement les bogues ? Du prix ? Les problèmes de licence ? Je me suis mis à Linux il y a 20 ans à cause des mises à jour constantes de Microsoft.
0 votes
@TomZych La question portait sur la production de meilleurs binaires. La vitesse de compilation, le prix et les autres attributs ne sont pas pertinents. Pour les programmeurs C/C++ modernes, la seule métrique pertinente pour comparer des binaires issus du même code source est la vitesse d'exécution. Dans la limite du raisonnable, bien sûr, et en supposant que les compilateurs fonctionnent, les fichiers exécutables de 1 Go ne sont évidemment pas souhaitables.
4 votes
Je ne vois pas pourquoi cette question a été fermée. Qu'il s'agisse d'une opinion ou d'un fait, nous voulons connaître la réponse, et le fait de la marquer comme fermée lui donne une teinte négative, alors qu'il ne devrait pas y en avoir.
7 votes
@TomZych : Si vous voulez connaître ces facteurs, posez des questions différentes. Celle-ci est très spécifique et sans ambiguïté - elle demande la vitesse d'exécution et l'empreinte mémoire. Vous pouvez être intéressé par d'autres facteurs, tant mieux pour vous, cela ne signifie pas que cette question est invalide, elle ne répond simplement pas à vos intérêts personnels. C'est comme si vous étiez un programmeur Java et que vous vouliez fermer toutes les questions sur le C# parce qu'elles ne parlent pas de Java.