Ce week-end, alors qu'il m'était impossible de réactualiser frénétiquement la page d'accueil de Linuxfr pour voir s'il n'y avait rien d'intéressant, je suis allé sur le site de LLVM.
Tout d'abord, la page d'accueil de ce site est un peu plus peuplée, et liste tous les projets intéressantes de LLVM :
- LLVM lui-même, architecture modulaire permettant de créer des compilateurs pour plein de langages, mais aussi des interpréteurs, etc
- Clang, le compilateur C, C++, Objective-C et Objective-C++ se basant sur LLVM pour la génération de code.
- llvm-gcc et DragonEgg, deux projets visant à intégrer LLVM dans GCC, donc de se servir des front-ends de GCC et de LLVM pour générer le code. llvm-gcc est un fork de GCC 4.2, DragonEgg est un plugin pour GCC 4.5.
- libc++, projet jeune et très intéressant, conciste à une réécriture de la libstdc++, sous licence LLVM. Le projet est complet à 80% (en comptant les nouveautés du C++0x). Cette réécriture est en particulier demandée par l'arrivée de cette nouvelle version du C++, qui oblige des changements de fond dans les bibliothèques C++. Au lieu de hacker la libstdc++ de GCC, les développeurs de LLVM préfèrent en recréer une nouvelle, tirant parti des découvertes et inventions faites dans le domaine depuis les dernières années.
- compiler-rt, équivalent LLVM de la libgcc. Cette petite bibliothèque contient des fonctions souvent appelées dans le code, permettant d'émuler des opérations qu'un certain target ne supporte pas. Par exemple, il est difficile pour certains processeurs de convertir un nombre flottant sur 32 bits (float) en un double (64 bits).
- vmkit, essai visant à émuler une machine virtuelle Java ou .NET au-dessus de LLVM. La machine virtuelle Java fonctionne déjà plus ou moins et sait lancer Eclipse, Tomcat, etc.
- Klee est un genre d'analyseur de code. On compile son code, on le lance dans Klee, et il nous dit toutes les valeurs que peuvent prendre les variables. Ça permet de voir s'il n'y a pas de pointeurs NULL qui se baladent, pas de code inutilisé, combien de fois une boucle est utilisée, etc.
Mais ce qui m'intéresse ici est Clang, le compilateur pour les langages de la famille du C.
Comme je l'avais dit dans mes précédant journaux, Clang essaie de supporter le C++, ce qui est difficile étant donné la complexité atroce de ce langage pour le compilateur.
Hier, je me balade donc sur le site de Clang. Je clique sur la page Statut du C++, et voit qu'elle est quasiment vide.
Auparavant, elle contenait une centaine (voire plus) de lignes dans un tableau, une pour chaque test du standard C++ 2003. Au fur et à mesure que le temps passait, des tests passaient en vert, ou du rouge vers l'orange quand ils étaient implémentés.
Ce tableau n'existe plus pour le C++ standard, il n'en reste qu'un petit morceau pour le futur C++-0x. Je lis donc attentivement l'introduction de cette page et découvre ceci :
Clang currently implements all of the ISO C++ 1998 standard (including the defects addressed in the ISO C++ 2003 standard) except for 'export' (which has been removed from the C++'0x draft). However, the implementation of Clang C++ is still somewhat immature, with remaining bugs that may cause compiler crashes, erroneous errors and warnings, or miscompiled code. The LLVM bug tracker contains a Clang C++ component that tracks known Clang C++ bugs.
Ou pour les anglophobes :
Clang implémente pour le moment tout le standard ISO C++ 1998 (incluant les défauts corrigés dans le standard ISO C++ 2003), sauf 'export' (qui a été retiré du brouillon du C++-0x). Cependant, l'implémentation du C++ de Clang est encore un peu immature, avec des bugs qui peuvent causer des crashs du compilateur, de fausses erreurs et warnings, ou un code mal compilé. Le bug tracker de LLVM contient un composant Clang C++ permettant de traquer les bugs connus du C++ de Clang
(désolé pour la traduction pourrie, c'est du fait-main et je ne traduis pas souvent).
Il s'avère donc que Clang supporte tout le C++, sauf quelques extensions (listées sur une page spéciale).
Je m'arme donc d'un programme de test en C++, j'ai nommé Setup, le gestionnaire de paquets que je développe. Il est composé de 15k SLOC C++, utilisant Qt, des templates, toute forme d'héritage, le préprocesseur, les bindings C (extern "C"), la surcharge des opérateurs, etc. Une bonne partie du C++ (mais pas les exceptions).
Je lance donc Clang dessus, avec un simple «cmake -DCMAKE_CXX_COMPILER="clang++"». Je lance make, ça marche.
Out-of-the-box en plus ! Rien à faire ! C'est un succès total. Clang me génère même des warnings que GCC ne me trouvait pas. Je les ai corrigés.
Setup se lance, fait tout ce que je lui demande, et bien. Clang a vaincu un programme complexe, architecture bibliothèque-clients, utilisant Qt.
Je regarde un peu le blog de LLVM et vois que Clang compile impeccablement la bibliothèque C++ Boost, réputée pour sa complexité. Son support du C++ est donc devenu excellent.
Benchmarks
Maintenant, place aux benchs. Tout d'abord, j'ai consulté cette page, une page pour les hardcore hackers (oui oui), qui décrit comment créer un plugin pour LLVMC.
LLVMC est comme GCC, c'est à dire un directeur de compilation (compiler driver). C'est lui qui parse les options qu'on lui donne, et décide quels programmes appeler. Par exemple, on peut générer des fichiers objets à partir de fichiers en C, mais on peut aussi lier les fichiers objets en un exécutable.
LLVMC fonctionnait déjà avant mon intervention, mais pas comme je voulais. Il se comportait trop comme GCC, compilant le code en dur, le liant en utilisant LD, etc.
Pour mes tests, je l'ai modifié pour utiliser 100% LLVM. Les fichiers C sont compilés en fichiers bitcode LLVM, sortis sous forme de .o (mais qui ne sont pas des .o normaux). Le lieur n'est pas LD, mais llvm-link.
Le but du machin est du tirer au maximum parti de LLVM et de Clang. Voici théoriquement comment se déroule la compilation :
* Clang compile les fichiers .c, .cpp, .m et .mxx en fichiers .o, contenant du bitcode LLVM non-optimisé. Les options -Ox sont ignorées ici.
* llvm-link lie ces fichiers .o en un gros fichier .o, toujours non-optimisé.
* Si on a précisé une option -Ox, alors opt (l'optimiseur de LLVM) est appelé sur ce fichier .o, et génère un fichier .o optimisé. Le but de la manoeuvre est d'optimiser une seule fois (plus rapide), et surtout sur un seul fichier. On a ainsi gratuitement une Link Time Optimization, beaucoup plus efficace et agressive qu'une optimisation après chaque compilation.
* La sortie de opt, ou de llvm-link si on n'optimise pas, est fournie à llvm-ld. Ce programme sort un script shell, lançant l'interpréteur LLVM sur un fichier .bc, contenant le bitcode complet du programme. Il est également possible de passer l'option "-native" à LLVMC, qui la passera à llvm-ld, qui sortira alors un beau fichier ELF comme on a l'habitude.
Chaîne de compilation relativement classique, et plus simple que celle de GCC (qui appelle tout un tas de lieurs, assembleurs, collect2, etc).
Les chiffres maintenant. Comme toujours, je me sers de Cream, un navigateur web léger développé par une connaissance (oui je fais de la pub, mais j'aime bien ce navigateur).
C'est du C, pas du C++, mais il utilise GTK et Webkit. Il est donc intéressant. Les tests sont faits sur un Packard Bell DOT/MA.FR-30, c'est à dire un Netbook avec un disque dur 5200tpm de 160Gio, 1Gio de RAM DDR2 660Mhz, un processeur AMD Athlon 64 L110 à ... 1,2Ghz, 512Kio de cache, carte graphique ATI Radeon X1270 (RS690G). Bref, une bouze niveau rapidité, mais il a un magnifique écran 1366x768 (troll: et KDE 4.4 tourne comme un charme dessus, et se lance en quelques secondes) [/mavie].
- Compilé avec gcc, en -g -O2 (options standard des autotools), la compilation prend 16,715 secondes.
- Compilé avec gcc -flto, toujours en -O2, sans le -g (incompatible avec -flto), la compilation crashe après 17,670 secondes.
- Compilé avec llvmc (Clang donc, relisez ce que je met plus haut pour comprendre), toujours en -g -O2, la compilation prend 10,295 secondes. Simplement, j'ai alors un fichier bitcode, pas un exécutable.
- Compilé avec llvmc -native, en -g -O2, la compilation prend 12,166 secondes, et j'ai un fichier ELF fonctionnant parfaitement.
Niveau vitesse de compilation, il n'y a pas photo. GCC prend près de 17 secondes, Clang en prend 12, alors qu'il utilise des optimisations plus agressives, faites au moment de la liaison finale.
Dans les deux cas, Cream est parfaitement fluide et affiche sans problème n'importe quel site web.
Je referai bientôt des tests plus poussés du C++, en compilant Blender par exemple, pour voir ce que ça donne. Je dois d'abord corriger quelques problèmes, en particulier le fait que les outils que j'utilise (CMake, les autotools) ne sont pas habitués à avoir du bitcode LLVM à la place du ELF. Il y a plein de strip partout, les fichiers compilés sont lancés, etc.
Voilà. Journal un peu long, mais j'ai dit tout ce que j'avais à dire.
# un modo dans les parages?
Posté par Albert_ . Évalué à 10.
[^] # Re: un modo dans les parages?
Posté par steckdenis (site web personnel) . Évalué à 4.
Mais la partie «dépêche» est peut-être un peu courte (juste le début, présentation de LLVM, et l'annonce que Clang supporte le C++).
Sinon, pour ceux qui voudraient reproduire mes benchmarks, il faut suivre la documentation que j'ai donné près du lien «pour les hardcore hackers». Dans ce lien, ils vous parleront d'un fichier «tablegen». Au lieu de vous arracher les cheveux à retrouver comment j'ai fait, voici le mien : http://logram-project.org/pastebin-3-n49c4d9a46717.html .
D'ailleurs, j'ai réussi à compiler Neverball avec :) . Ça marche très bien et il est jouable en 640x480 toutes options désactivées (on sent la carte ATI intégrée avec pilotes libres et le L110 ici, gcc faisant la même chose).
[^] # Re: un modo dans les parages?
Posté par Thrillseeker . Évalué à 4.
# Bench entre GCC et LLVM
Posté par patrick_g (site web personnel) . Évalué à 9.
Je voulais faire une news en testant les deux dernières versions des compilateurs mais, accablé par mon incompétence, j'avais abandonné l'idée...et hop ! Une vraie comparaison a été effectuée par Vladimir Makarov et les résultats postées sur la mailing list de GCC => http://gcc.gnu.org/ml/gcc/2010-04/msg00948.html
Les résultats détaillées sont ici => http://vmakarov.fedorapeople.org/spec/
Comparaison des différentes versions de GCC => http://vmakarov.fedorapeople.org/spec/comparison64.html
Comparaison entre GCC 4.5 et LLVM 2.7 => http://vmakarov.fedorapeople.org/spec/llvmgcc64.html
Attention a prendre le temps de bien lire les benchs puisque les tableaux visualisent trois choses différentes successivement :
1) Compilation Speed
2) Code Size
3) Generated Code Performance
Pour les décideurs pressés :
1) GCC 4.5 est plus lent que LLVM 2.7 pour compiler (entre 10 et 15%)
1) GCC 4.5 génère du code plus rapide que LLVM 2.7 (environ 7% sur les benchs des entiers et environ 15% sur les benchs des flottants)
[^] # Re: Bench entre GCC et LLVM
Posté par Ludo . Évalué à 1.
C'est néanmoins bien parti pour qu'ils "explosent" les performances de GCC.
[^] # Re: Bench entre GCC et LLVM
Posté par patrick_g (site web personnel) . Évalué à 6.
mmm...qu'est-ce qui te fait dire ça ?
[^] # Re: Bench entre GCC et LLVM
Posté par Ludo . Évalué à 0.
[^] # Re: Bench entre GCC et LLVM
Posté par claudex . Évalué à 10.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: Bench entre GCC et LLVM
Posté par claudex . Évalué à 6.
On pourrait imaginer utiliser LLVM pendant le développement pour pouvoir tester le programme plus vite et le compiler avec GCC quand c'est fini.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: Bench entre GCC et LLVM
Posté par steckdenis (site web personnel) . Évalué à 3.
C'est effectivement intéressant, mais il me semble (ce n'est pas clairement marqué, je me base sur un «LLVM GCC frontend») qu'ils utilisent llvm-gcc pour leurs tests, pas Clang.
Et la vitesse gagnée vient justement de Clang, car c'est la partie «font-end» de GCC qui est lente. Il faut également voir si Clang ne produit pas du code que LLVM sait mieux optimiser.
J'avais une fois fait un test sur un programme moyen (400 lignes de C, mais un truc tordu qui construit un suffix-tree puis fait plein d'opérations dessus), et ce programme compilé avec Clang s'exécutait en un peu moins de 0,9 secondes, et un peu plus de 1,1 seconds avec GCC.
Je devrai aussi tester tout ça, avec mon support des optimisations à la liaison, sur un programme qui mouline bien (genre Lame, et ceux que Phoronix utilise pour ses tests de compilateurs). J'ai déjà essayé avec Yafaray, mais il ne veut pas se compiler, même avec GCC. Je donnerai des nouvelles.
[^] # Re: Bench entre GCC et LLVM
Posté par gasche . Évalué à 2.
[^] # Re: Bench entre GCC et LLVM
Posté par gasche . Évalué à 3.
http://www.phoronix.com/scan.php?page=article&item=gcc_l(...)
[^] # Re: Bench entre GCC et LLVM
Posté par steckdenis (site web personnel) . Évalué à 3.
Le fait que l'optimisation soit faite sur le bytecode final permet de mieux optimiser, d'inliner des fonctions, de propager des constantes, etc. Le LTO, ça marche vraiment, même si on se dit que ça ne sert que dans peu de cas.
Exemple, j'ai dans Setup une fonction nommée matchVersion, qui vérifie qu'une version correspond à une autre comme on veut (en clair, si on lui passe "1.3.4", >=, "1.3.0", elle retourne true). Le truc que j'envoie au milieu est un simple INT, représentant l'opération.
Une partie de mon écriveur de base de donnée s'occupe de rechercher une version exacte. Il envoie donc toujours DEPEND_OP_EQ (le ==). Problème, sans LTO, matchVersion est dans un autre fichier.
Avec LTO, LLVM me détecte que j'envoie une valeur immédiate. Il va alors m'inliner cette fonction, me retirer les ifs qu'il y a dedans, retirer la fonction que je n'appelle donc pas, supprimer une variable inutilisée, inliner une autre fonction dedans, en appliquant le même traitement.
Finalement, un «setup update» passe de 1,2 secondes à 0,8. Pas mal non ?
Alors oui, Clang supporte l'option -O4 qui fait aussi du LTO .. uniquement sur Darwin. En effet, le toolchain Clang sous Linux est encore minimal (en gros : passer le plus vite possible en ELF et appeler les outils de GCC), le gain est donc minimal. Mon LLVMC reste le plus longtemps en bitcode LLVM, et compare donc bien mieux les différences entre GCC et LLVM.
[^] # Re: Bench entre GCC et LLVM
Posté par yellowiscool . Évalué à 1.
Les .hxx étaient inclus dans les .h, et donc le code des fonctions simples était inclus dans tout les fichiers, permettant au compilateur de faire les inline qui font bien.
Envoyé depuis mon lapin.
[^] # Re: Bench entre GCC et LLVM
Posté par __o . Évalué à 1.
# Coupures volontaires
Posté par Kerro . Évalué à 10.
Cela me fait penser qu'il serait peut-être bien que linuxfr soit indisponible 24 heures aléatoirement tous les x jours.
'n'est pas une bonnidée ça ? Hum ?
Non, vraiment pas ?
[^] # Re: Coupures volontaires
Posté par Gniarf . Évalué à 2.
# optimisation globale
Posté par Antoine . Évalué à 8.
Tu as oublié un truc quand même... Si tu recompiles seulement un fichier C (suite à petite modif par exemple), l'optimisation devra être refaite sur l'intégralité du programme, et là ce n'est pas plus rapide, mais a priori beaucoup plus lent que si l'optimisation était faite sur chaque fichier séparé.
[^] # Re: optimisation globale
Posté par Gniarf . Évalué à 3.
[^] # Re: optimisation globale
Posté par Antoine . Évalué à 4.
# ...
Posté par M . Évalué à 2.
libc++ n'implémente que la lib standard c++, libstdc++ implémente aussi la stl ?
le choix de réécrire ces libs, c'est aussi une question de licence : bsd vs (l)gpl.
Mais oui le projet llvm à une bonne dynamique et est en train de rattraper gcc (au moins pour le platforme classique X86 mac osx/linux).
[^] # Re: ...
Posté par Matthieu Moy (site web personnel) . Évalué à 5.
En fait, plus précisément BSD Vs GPLv3 : les employés Apple n'ont pas le droit de bosser sur du code GPLv3 :
http://thread.gmane.org/gmane.comp.compilers.llvm.devel/3174(...)
« It doesn't really matter. It is widely known that Apple employees are generally not allowed to touch GPL3
code. The reasons and decision was not an engineering choice. »
Les détails sur le choix de démarrer libc++ :
http://thread.gmane.org/gmane.comp.compilers.llvm.devel/3174(...)
[^] # Re: ...
Posté par Matthieu Moy (site web personnel) . Évalué à 5.
Vu que STL signifie « Standard Template Library », ce n'est pas une surprise que la STL fasse partie de la lib standard C++. J'ai pas regardé en détails, mais dans les sources de la libc++, il y a des fichiers include/vector, include/algorithm et autres qui semblent confirmer que la libc++ implémente la STL (enfin, modulo le fait que libc++ n'est pas terminée).
[^] # Re: ...
Posté par ecyrbe . Évalué à 2.
libc++ is still under development. It has about 85% of N3092 implemented/tested. C++'98 support is fully featured, and most of C++'0x support is as well. The only major missing pieces of C++'0x support are and , and parts of .
Donc il ne manque vraiment pas grand chose. Actuellement peu des fonctionnalités de C++0X sont employées car pas encore standardisées. Je vois qu'il y a quand même pas mal de fonctionnalités de TR1 qui sont déjà implémentées.
Bref, ils avancent très vite.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.