Aujourd'hui, comme je n'avais pas grand-chose à faire, j'ai testé llvm. Mon but n'est pas de voir s'il peut me compiler KDE, ffmpeg, GNOME ou autre, non, il y a de fortes chance qu'il n'y arrive pas.
En fait, j'ai une idée derrière la tête, idée qui va vous plaire, une bonne idée.
Le principe est simple : créer un gestionnaire de paquets, sauf que cette fois-ci, j'ai trouvé ce qui sera révolutionnaire dedans. En effet, les paquets seront petits, très petits. Ils seront rapides, très rapide également.
Comment y arriver ? C'est simple :
- Prendre un bon gros programme
- Le compiler avec clang, et sortir un fichier .ll
- Petite chaîne de compilation llvm (assembleur, optimisations, bytecode)
- Empaqueter ça, c'est à dire une représentation compacte (le bytecode), et surtout indépendante de l'architecture du processeur
- Du côté client, on récupère le paquet. Il contient les instructions pour la suite de la compilation (donc juste les libs à passer en paramètre -l à ld)
- Compiler le bytecode en code natif, adapté à la machine
Ça paraît trop beau pour être vrai, j'en pleure presque. Snif, fini les problèmes, on va être a des millions de kilomètres de ce que le proprio fait, de Windows, de Mac, etc. Voici la liste des avantages :
- Des mirroirs légers, très légers : tout n'est qu'en une seule architecture, et le bytecode est largement plus petit que le code compilé !
- Une éxécution super rapide chez le poste client, car optimisé aux petits oignons pour son CPU, quel qu'il soit (dernier Core i7, AMD Phenom, un PPC, un Cell, un ARM, etc)
- Sans boulot supplémentaire, on supporte toutes les architectures que LLVM supporte. De plus, les paramètres -march et -mcpu de lli (le programme qui transforme le source llvm en bytecode) sont très simples à utiliser, et j'ai avec succès généré une application pour PPC sur mon x86_64. Ainsi, les LiveCD qui doivent être précompilés sont générés très facilement et rapidement
Et voici les inconvénients qu'on pourrait penser que ce système a, mais qu'il n'a pas :
- Transformer le bytecode en assembleur est très rapide, l'assemblage aussi, et le linkage également. Le temps éventuellement perdu est de toute façon gagné en temps de téléchargement (mon fichier bytecode pour un tout petit fichier C est près de 10 fois plus petit que le binaire non-strippé, et 5x plus petit que quand il est strippé !)
- Le statut expérimental de llvm et clang : ils marchent bien, surtout llvm. Au pire, on utilise le front-end llvm-gcc, ce qui nous apporte également le C++
- Pas besoin de build-dependecies, tous les fichiers .h ont été parsés, et le code se trouve directement dans le fichier bytecode.
Côté inconvénients, je ne vois rien, pour le moment.
Les tests
Et oui, j'ai testé. Je suis partit d'un tout petit fichier C, le TP Plus ou Moins qu'on peut trouver ici (je n'avais pas envie de trouver un fichier C moi-même, et celui là est plus "réel" qu'un Hello Word).
Ensuite, la compilation :
$ clang-cc test.c -emit-llvm -o - | llvm-as | opt -std-compile-opts > bytecode.bc
$ clang -o binaire_llvm test.c
$ ./binaire_llvm
Quel est le nombre ? 4
C'est moins !
[ ... donc ça marche ;-) ... ]
$ gcc -o binaire_gcc test.c
$ ./binaire_gcc
Quel est le nombre ? 3
C'est plus !
[ ... Lui aussi marche ... ]
$ strip --strip-all binaire_gcc # Soyons honnête sur la comparaison
$ strip --strip-all binaire_llvm
$ llc -o bytecode_asm.s bytecode_llvm.bc # Maintenant, compileation du bytecode
$ clang -o bytecode_bin bytecode_asm.s
$ ./bytecode_bin
Quel est le nombre ?
[ ... c'est bon aussi ... ]
$ ls -l
5104 sep 1 12:50 binaire_gcc
5112 sep 1 12:50 binaire_llvm
5128 sep 1 13:12 bytecode_bin
1116 sep 1 12:48 bytecode_llvm.bc
On voit donc que le bytecode est 5 fois plus petit que le résultat compilé et strippé.
Intéressant non ? Plus qu'à tester sur de gros programmes (ce que je vais faire).
PS: J'ai refait le même test avec un code C plus gros (le TP du pendu :P ), et le bytecode fait 3472 octets, alors que le fichier binaire le plus petit (celui de llvm) fait 5536 octets. Je vais tester avec encore plus gros.
PS 2: (décidément, linuxfr down me permet de bien tester) son TP du sokoban est remarquable : je compile chaque fichier .c en byte code, puis utilise llvm-ld pour générer tout.bc, puis lie le tout en un fichier sokoban. Tout.bc pèse à peine 5264 octets, alors que sokoban, strippé, pèse 11416 octets ! La version sokoban de gcc pèse 12904 octets. LLVM est le grand gagnant !
Encore un PS (j'ai eu le temps): marche à la perfection avec Cream, un navigateur web en GTK 2. Super et rapide : Cream. 63k pour le fichier bytecode, et 77k pour le binaire. Ca me paraît petit comme gain, peut-être que GTK met beaucoup de données qui ne sont pas des binaires dans son code.
# opt de taille
Posté par Marc (site web personnel) . Évalué à 4.
Je parle de tests que j'ai fais il y a bien 1année...
(PS: je reste dubitatif sur ton hypothèse qui dit "les build-deps == ensemble de .h". Tu zappes un paquet de chose là, ne serait-ce que les bibliothèques liées statiquement)
[^] # Re: opt de taille
Posté par steckdenis (site web personnel) . Évalué à 3.
Pour les bibliothèques liées statiquement, hors le fait que je n'aime pas, il devrait être possible de les fournir dans le paquet, puis d'utiliser "clang -o binaire fichiers.s -L. -llib_statique", ou quelque-chose comme ça. C'est un domaine jamais exploré, je vais voir ce que je peux trouver.
[^] # Re: opt de taille
Posté par Gof (site web personnel) . Évalué à 3.
Sinon c'est inutile.
(Les comparaisons peuvent s'inverser au final)
# petit ordi et grosse connexion
Posté par manatlan (site web personnel) . Évalué à 3.
> façon gagné en temps de téléchargement
Moi j'ai pas un ordi véloce, mais j'ai une grosse connexion adsl (à 300m du dslam)
La compile de firefox est extrêmement plus longue que le téléchargement/installe de ce dernier ...
cependant, c'est super interessant ton concept
# Pas très écolo
Posté par ribwund . Évalué à 2.
Sinon le bitcode llvm n'est pas toujours portable d'une architecture à l'autre.
Par contre les blocks/libdispatch de Apple 10.6 seraient intéressants à porter sous linux, des volontaires ?
http://arstechnica.com/apple/reviews/2009/08/mac-os-x-10-6.a(...)
[^] # Re: Pas très écolo
Posté par steckdenis (site web personnel) . Évalué à 1.
À mon avis, le problème se situera plutôt du côté des applis "mal codées" (ce qui est relatif) qui ne sont déjà que difficilement portables comme ça (donc celles qui n'utilisent pas des sizeof(void *), ou qui ne font pas attention à l'endianess, etc).
À la limite, on pourra proposer des paquets spéciaux dépendants d'une architecture qui pose problème pour ces paquets (si foobar marche sur tout sauf sur ARM, on propose le paquet précompilé pour ARM).
Ensuite, la compilation est faite : le plus difficile et le plus lourd est la transformation des sources vers le bytecode (parsage des fichiers d'en-tête, optimisations, etc). Du côté client, il ne faut que générer le fichier assembleur, l'assembleur et le lier.
Pour le test de Cream, la phase "compilation sur le serveur" prend environ 20 secondes (peut-être plus, je ne m'en souviens plus), et compiler le bytecode en code natif prend moins d'une seconde. À mon avis, compiler une vingtaine de gros paquets devrait prendre moins de 30 secondes, en tous cas moins d'une minute.
Compiler KDE depuis les sources, ça prend combien de temps ? 3h chez moi. On y gagne donc si le bytecode s'assemble en moins de 3h (bon, ce n'est pas instantané, mais on installe bien moins souvent un programme qu'on ne l'utilise).
[^] # Re: Pas très écolo
Posté par ribwund . Évalué à 5.
C'est faux, il reste bien évidemment toutes les optimisations archi-dépendantes (code selection, coalescing, spilling et regalloc, scheduling, etc.) et/ou les optimisations inter-procédurales. Sinon ton système n'apporterait aucun gain (pas de spécialisation).
Sinon à mon avis quitte à se taper du bitcode, autant faire de la compil dynamique et faire de l'optimisation "runtime".
[^] # Re: Pas très écolo
Posté par Matthieu Moy (site web personnel) . Évalué à 2.
Non, ce n'est pas le cas. Enfin, le bitcode est plus ou moins indépendant de l'architecture, mais c'est la chaine de compilation en partant du C qui ne l'est pas. Pour prendre un exemple caricatural, comment représenterait-t-on
printf("%d\n", sizeof(int));
en bitcode indépendant de l'architecture ?
Pour les détails, cf. par exemple http://markmail.org/message/chucijjh6ki4jz5c
[^] # Re: Pas très écolo
Posté par Matthieu Moy (site web personnel) . Évalué à 4.
[^] # Re: Pas très écolo
Posté par ribwund . Évalué à 2.
[^] # Re: Pas très écolo
Posté par Naha (site web personnel) . Évalué à 2.
Il y avait un article (peut-être légèrement orienté, mais intéressant tout de même) à ce sujet dans le n°58 de La Décroissance (avril 2009) : http://www.ladecroissance.net/?chemin=journal&numero=58 (non lisible en ligne).
# Sympa ce journal
Posté par FX Pasquier . Évalué à 4.
http://llvm.org/
et j'ai découvert Cream en bonus :)
Sinon le but général du journal, ce nouveau gestionnaire de paquet, a l'air très prometteur, comme tu dis c'est trop beau pour être vrai !
Surtout tiens nous au courant des tests !!!!
Je plussoie \o/
[^] # Re: Sympa ce journal
Posté par steckdenis (site web personnel) . Évalué à 2.
La gestion des architectures sera toujours gardées, car il y aura bien des paquets (ne fusse que le kernel) qui ne passeront pas avec LLVM, et qui auront besoin de GCC, ou de fichiers non-binaires mais dépendants de l'architecture (il me semble que ça existe, genre des dumps mémoire dépendants de la taille des pages).
Et oui, j'ai oublié de présenter LLVM. Toutes mes excuses à ceux qui se sont sentis perdus.
[^] # Re: Sympa ce journal
Posté par patrick_g (site web personnel) . Évalué à 4.
En même temps il y avait déjà eu plusieurs news :
LLVM 2.2 : https://linuxfr.org//2008/02/18/23723.html
LLVM 2.4 : https://linuxfr.org//2008/11/12/24671.html
LLVM 2.5 : https://linuxfr.org//2009/03/04/25108.html
Mais c'est vrai que c'est mieux de faire un petit rappel au début.
[^] # Re: Sympa ce journal
Posté par bubar🦥 (Mastodon) . Évalué à 2.
Mais n'ayant pas les connaissances pour évaluer lvvm vs gcc, te surtout pas l'envie de rentrer dans un début philosophique me dépassant (et sachant que des argumentaires techniques peuvent y être mûs par la seule volonté de valoriser une vision philosophique). Ayant encore moins les notions permettant de jauger la qualité, les résultats, les tenants et aboutissants du bytecode vs compilé, je nepeux que me contenter de dire :
La solution "architecture" me semble belle. Et ça me plait :) Donc pas la vision purement technique sur les moyens d'y arriver mais la finalité du projet : disposer de 'binaires' initiaux très 'légers', très 'portables', et très 'indépendant'. La phase finale étant assurée par la machine cliente. Je trouve cela beau et formidable.
Un seul bémol, sur l' argumentaire :
Une éxécution super rapide chez le poste client, car optimisé aux petits oignons pour son CPU, quel qu'il soit (dernier Core i7, AMD Phenom, un PPC, un Cell, un ARM, etc)
Là j' ai des doutes. D' une part parceque les bibliothèques sont toujours ce qu' elles sont : des binaires classiquement installés. Ce qui, je présumé, grève significativement l' argument, pour une partie des fonctions d' une bonne partie des binaires logiciels fait de cette nouvelle manière.
Il faudrait peut être que cela soit, plutôt que de suite vouloir faire un gestionnaire de paquet, une distribution faite sur ce mode. Proposer un "stage 1" à-la-Gentoo, qui permet d' installer une distribution avec ce mode de fonctionnement d'installation. Le but n'étant pas de faire une nouvelle distro, mais de valider totalement ce -futur- gestionnaire de paquet, en validant son fonctionnement de manière quasi-globale.
Si j'ai pas trop faux, et de toutes façons dans tout les cas, je suppose que tu as besoin d'aide ? Perso je peux pas apporter grand chose, peut être une cotisation supplémentaire chez tuxfamily.org pour que tu ai une super archi d'une part, et peut être d'autre part une machine ?
mes deux cents.
cordialement.
[^] # Re: Sympa ce journal
Posté par steckdenis (site web personnel) . Évalué à 2.
Je suis content que l'idée te plaise. En effet, avoir des optimisations spécifique au processeur est un gros plus. Ce qui fait que le amd64 est plus rapide que le i386 n'est pas spécialement le passage en 64bit, mais simplement le fait que amd64 est plus récent, et que pour être compatible amd64, un processeur doit supporter plus d'instructions, qu'un i386 ne supporte pas. Ainsi, on peut utiliser l'argument -mtune de GCC.
Les bibliothèques utiliseront également LLVM, ce sera appliqué à tous les paquets (si ça marche). Ainsi, si je teste sur un Core i7, les bibliothèques multimédia par exemple pourront utiliser les instructions dernier cri SSE4, alors que le paquet Debian, amd64 générique, ne dépasse pas SSE2.
Il y a aussi de subtiles différences entre les processeurs AMD et Intel. Une certaine instruction sera plus rapide sur un proc AMD qu'une autre, alors que ça peut être l'inverse sur du Intel. LLVM, dans sa phase de compilation en binaire, va générer le code optimal pour le processeur.
J'ai également comme idée un support d'un genre de "USE flags" : du côté serveur, on compile le programme avec toutes les combinaisons de USE. Dans le paquet, on place les fichiers bytecode en deux parties :
* Un gros fichier bytecode (créé avec llvm-link) pour ce qui ne change pas en fonction des USE
* De petits bytecode pour ce qui est dépendant des USE/architectures (au cas où des #ifdef traineraient)
À l'installation, en fonction des choix de l'utilisateur, on peut choisir les fichiers bytecode à lier, puis à compiler.
Tout ceci n'est qu'une idée. Il me semble que personne encore n'a pensé à utiliser LLVM pour ça, c'est un sujet très intéressant. Tout ce que je peux demander à ceux qui veulent voir ceci réalisé est de contribuer à LLVM et Clang (le code est simple et beau, on s'y retrouve vite), en particulier pour le C++ (j'ai envie d'avoir KDE compilé avec Clang :-° ).
[^] # Re: Sympa ce journal
Posté par Alexandre . Évalué à 1.
# Bytecode vraiment portable ?
Posté par Olivier Serve (site web personnel) . Évalué à 4.
[^] # Re: Bytecode vraiment portable ?
Posté par steckdenis (site web personnel) . Évalué à 1.
Logram étant une distrib GNU/Linux, les #ifdef sont bons :) .
Pour les paquets qui sont vraiment dépendants d'une architecture, soit on cherche un hack, soit on utilise la bonne vieille méthode.
[^] # Re: Bytecode vraiment portable ?
Posté par Buf (Mastodon) . Évalué à 8.
Ça, c'est faux.
Il y a plusieurs cas où ça arrive qu'on teste sur l'architecture :
- code assembleur inline
- test d'endianness (c'est pas un test d'architecture au sens strict, mais ça revient au même)
- 32 ou 64 bits (idem qu'au dessus)
# Dépendances?
Posté par Larry Cow . Évalué à 4.
Donc tu risques d'avoir des redondances fâcheuses (et lourdes). Si je télécharge des programmes KDE - par exemple - via un gestionnaire de paquets lambda, il ne téléchargera que le paquet (éventuellement les trucs nécessaires au runtime, mais seulement la première fois). Si je fais de même avec Gentoo - par exemple - il récupérera les dépendances nécessaires à la compilation, mais une sule fois.
Par contre, avec ton truc, _chaque_ programme récupéré par le gestionnaire de paquets va se trimballer une grosse partie des kdelibs (dans mon exemple) avec lui. Ce qui est bien, mais pas top.
Ce qui n'enlève rien à l'intérêt de ton concept. Une solution qui permettrait - au moins partiellement - de limiter le problème que je soulève serait de faire un diff binaire (xdelta?) entre les différents paquets "logiquement" liés en amont, pour ensuite morceler les téléchargements. Genre "tu as besoin de digikam et d'amarok, alors je te fournis d'abord la partie commune - kdelibs, qt &co - puis les parties spécifiques et tu te chargeras de tout regrouper". On peut même envisager un cache côté client pour ces mêmes parties communes. Si ta technique est vraiment aussi économe en place que tu le dis, le cache ne sera pas _très_ couteux.
[^] # Re: Dépendances?
Posté par Thomas Douillard . Évalué à 2.
[^] # Re: Dépendances?
Posté par steckdenis (site web personnel) . Évalué à 6.
Ce bytecode est très proche du binaire, juste un niveau au dessus, pour être portable. Voici comment se déroule la création d'un paquet :
* Compilation de chaque fichier .c ou .cpp dans un fichier .ll
* Compilation de chaque fichier .ll en un fichier .bc
Si on devait s'arrêter ici, on aurait effectivement plein de redondance, mais ce n'est pas ce qui est fait :
* Utilisation de llvm-link pour lier tous les fichiers .bc en un seul gros fichier .bc
Voilà, c'est là que tout s'est joué. Le bytecode est comme de l'assembleur : les bibliothèques ne sont pas inclues, on ne perd pas de place. On a juste des "call glib_machin_truc" ou "call machin::truc", mais sans rien d'autres.
Une fois le paquet récupérer, c'est là que la liaison est faite :) . C'est à ce moment qu'on dit «glib_machin_truc est un appel vers la fonction blabla dans la lib machin», donc c'est lié dynamiquement.
Par exemple, voici le Makefile utilisé pour compiler Cream :
SOURCES=main.b bookmarks.b callbacks.b command.b CreamView.b download.b favicon.b ftplib.b history.b ini.b keybindings.b
BINARY=cream
LIBS=-lwebkit-1.0 -lgtk-x11-2.0
INCLUDES=-I/usr/include/gtk-2.0 -I/usr/include/webkit-1.0/ -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/libsoup-2.4 -I. -I.. -DPREFIX=\"/usr/local\" -DLOCALEDIR=\"/usr/local/share/locale\" -D_REENTRANT
all: $(SOURCES)
llvm-ld -o all -s $(SOURCES)
# Ici on met dans un paquet, les lignes suivantes sont côté client.
llc -o all.s all.bc
clang -o $(BINARY) all.s $(LIBS)
%.b:%.c
clang-cc $*.c $(INCLUDES) -emit-llvm -o - | llvm-as | opt -std-compile-opts > $*.b
clean:
rm -f *.b
distclean: clean
rm -f all.* $(BINARY)
Et quand je liste le contenu du dossier, on voit ceci :
63564 sep 1 14:36 all.bc
10772 sep 1 14:35 bookmarks.b
19560 sep 1 14:35 callbacks.b
10484 sep 1 14:35 command.b
23392 sep 1 14:35 CreamView.b
5824 sep 1 14:35 download.b
3432 sep 1 14:35 favicon.b
23176 sep 1 14:35 ftplib.b
10256 sep 1 14:35 history.b
5808 sep 1 14:36 ini.b
7524 sep 1 14:36 keybindings.b
17804 sep 1 14:35 main.b
On voit qu'il y a des données qui sont perdues entre la somme des tailles des fichiers .b, et la taille du .bc. Ce sont les répétitions qui sont éliminées.
# LLVM IR n'est pas portable
Posté par meuh31 . Évalué à 2.
Voir la faq llvm : http://llvm.org/docs/FAQ.html => Can I compile C or C++ code to platform-independent LLVM bitcode?
En pratique, tous les modules ont un "target datalayout" et un "target triple".
Exemple :
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i386-pc-linux-gnu"
[^] # Re: LLVM IR n'est pas portable
Posté par steckdenis (site web personnel) . Évalué à 2.
C'est possible, mais alors ceci m'étonne :
$ llc -o - bc.bc -march=ppc32
Donc en ppc32 :
.file "bc.bc"
.text
.global main
.type main, @function
.align 2
main:
mflr 0
stw 0, 4(1)
stwu 1, -16(1)
lis 3, .L.str@ha
la 3, .L.str@l(3)
creqv 0, 0, 0
cror 6, 0, 0
bl printf
li 3, 0
addi 1, 1, 16
lwz 0, 4(1)
mtlr 0
blr
.size main,.-main
.section .rodata.str1.1,"aMS",@progbits,1
.L.str: # '@.str'
.asciz "Salut !"
Maintenant, testons l'ARM, avec le même fichier :
.file "bc.bc"
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.text
.globl main
.align 2
main:
str lr, [sp, #-4]!
ldr r0, .LCPI1_0
bl printf
mov r0, #0
ldr lr, [sp], #+4
bx lr
.LBB1_1:
.LCPI1_0:
.long .L.str
.size main, .-main
.type .L.str,%object
.section .rodata.str1.1,"aMS",%progbits,1
.L.str: @ @.str
.size .L.str, 8
.asciz "Salut !"
et pour finir, le x86_64
.file "bc.bc"
.text
.align 16
.globl main
.type main,@function
main: # @main
.LBB1_0: # %entry
subq $8, %rsp
movl $.L.str, %edi
xorb %al, %al
call printf
xorl %eax, %eax
addq $8, %rsp
ret
.size main, .-main
.type .L.str,@object
.section .rodata.str1.1,"aMS",@progbits,1
.L.str: # @.str
.asciz "Salut !"
.size .L.str, 8
.section .note.GNU-stack,"",@progbits
Pour un truc pas portable, ça passe assez bien. À mon avis, cette en-tête est plutôt là pour dire «J'ai été compilé sur cette arch, donc je risque d'être dépendant de ça. Tu connais les différences entre les deux, corrige-les».
[^] # Re: LLVM IR n'est pas portable
Posté par meuh31 . Évalué à 3.
cat ir.c
int take_ptr(long ptr) {
return *(int*)ptr;
}
clang ir.c -emit-llvm -o - | llvm-as | opt -O3 | llvm-dis
; ModuleID = ''
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i386-pc-linux-gnu"
%struct.__block_descriptor = type { i32, i32 }
%struct.__block_literal_generic = type { i8*, i32, i32, i8*, %struct.__block_descriptor* }
define i32 @take_ptr(i32 %ptr) nounwind {
entry:
%conv = inttoptr i32 %ptr to i32* ; <i32*> [#uses=1]
%tmp1 = load i32* %conv ; [#uses=1]
ret i32 %tmp1
}
Note le "long -> i32" qui ne sera pas valide sur une architecture 64 bits. :(
[^] # Re: LLVM IR n'est pas portable
Posté par steckdenis (site web personnel) . Évalué à 2.
Même avec un GCC normal, on ne sait pas le compiler out-of-the-box sur d'autres architectures.
LLVM est en fait une sorte de GCC qui sort sous forme de bytecode son interprétation au niveau moyen (donc plus du code source, pas du binaire). Si on sait compiler un fichier source avec GCC sur n'importe quelle architecture, on saura utiliser le fichier bytecode LLVM ainsi. Sinon, même GCC aurait nécessité un hack dans le programme.
Il me semble que tout cela a été bien nettoyé depuis le passage au x86_64, il me semble même que Debian a fait pas mal de boulot là-dessus (faut dire que Debian est les architectures, c'est une belle histoire d'amour :-° ).
[^] # Re: LLVM IR n'est pas portable
Posté par Gof (site web personnel) . Évalué à 2.
En C tu vera beaucoup de
MaStruct *plop = (MaStruct *)malloc(sizeof(MaStruct));
Et si MaStruct contiens des pointeurs sa taille sera différente selon la platforme.
Et donc le bytecode ne sera pas portable malgré la portabilité de l'application.
[^] # Re: LLVM IR n'est pas portable
Posté par steckdenis (site web personnel) . Évalué à 4.
Rah, Clang est vraiment le meilleur : cet exemple est portable, super, magnifique !
Code C:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
void *buffer;
int machin;
} maStruct;
int main(int argc, char **argv)
{
maStruct *s = (maStruct *)malloc(sizeof(maStruct));
s->machin = 3;
s->buffer = s;
printf("Le buffer est à l'adresse %ld", s->buffer);
return s->buffer == s;
}
On compile en bytecode, puis on lance :
/usr/local/bin/llc -o - -march=x86 test.bc
Et un petit extrait :
movl $8, (%esp)
call malloc
Remarque le "$8", la taille de ma structure, contenant un pointeur.
Maintenant, sans recompiler le code C, je génère l'assembleur pour x86-64 :
/usr/local/bin/llc -o - -march=x86-64 test.bc
Et j'obtiens ceci :
movl $16, %edi
call malloc
Remarque le $16 : ça marche, yeah :D . Le reste est bien en pur 64-bit (ici, on utilise %edi car malloc attend un int, pas un int64).
Bref, +1 pour Clang et LLVM, ils savent ce qu'ils font :) .
PS: J'ai pas vérifié avec llvm-gcc, je n'arrive pas à le compiler.
[^] # Re: LLVM IR n'est pas portable
Posté par meuh31 . Évalué à 1.
Et effectivement en changeant l'architecture avec -march=XXX, tu changes le target-datalayout utilisé.
Le problème vient du fait qu'un "long" (le type c) n'a pas la même taille sur 32 et 64 bits.
Si tu prends le code suivant :
int main() {
printf("%d\n", sizeof(long)/sizeof(int));
}
Sur 32 bits tu vas avoir le résultat "1" sur 64 bits le résultat sera "2".
En générant l'ir, clang | opt résumera l'appel à
printf("%d\n" , 1); sur 32 bits
et
printf("%d\n" , 2); sur 64 bits
Donc clang lors de la génération de l'ir prend les dimensions de la plateforme (long=4 ou long=8) et génère l'ir. Ca veut dire que l'ir qu'il soit généré avec clang sur 32 ou 64 bits n'aura pas la même tête si il y a des "long" ou autres trucs de ce genre dans ton code.
Le premier exemple que j'ai donné est un bon exemple : il est portable en c et pas en llvm.
[^] # Re: LLVM IR n'est pas portable
Posté par Buf (Mastodon) . Évalué à 2.
(et un développeur qui écrirait un code pareil aujourd'hui devrait être viré immédiatement)
[^] # Re: LLVM IR n'est pas portable
Posté par meuh31 . Évalué à 1.
si tu fais un gcc ir.c sur 32 bits le code généré fonctionnera exactement de la même façon que si tu faisais un gcc ir.c sur 64 bits. C'est donc du code portable.
Par contre si tu prends ton ir.bc que tu l'exécutes sur 64 bits, ça va être bizarre : le bytecode lui n'est pas portable.
Ce code est pas particulièrement sale, le cast d'un pointeur en long est chose commune (par exemple gestion mémoire du kernel).
[^] # Re: LLVM IR n'est pas portable
Posté par hervé Couvelard . Évalué à 7.
On prend un code, par exemple celui dans le tread, certains le trouve crade et pas portable, digne à virer celui qui le fait, et d'autres qu'il n'est pas particulièrement sale.
Qui croire ? les deux ? Aucun ? on s'en fout ? 42 ? Obiwan ?
[^] # Re: LLVM IR n'est pas portable
Posté par meuh31 . Évalué à 3.
Cela dit 42 convient. (forcément).
# Intéressant
Posté par Jehan (site web personnel, Mastodon) . Évalué à 2.
- Tu as testé sur quelques exemples, mais comme tu le dis, à ce que je comprends, llvm est expérimental. Peut-être que sur des bouts de code utilisant des fonctionnalités de langage très particulières, llvm peut montrer des limites? Cela n'est qu'une hypothèse basé sur le fait que llvm est apparemment expérimental (cf tes dires) et que les dévs eux-même semblent surtout destiner ce compilo/VM à des chercheurs (cf. section "LLVM Audience" de la page "Features" du site, où la plupart des lignes désignent chercheurs ou développeurs, hormis la dernière pour un certain type d'utilisateurs finaux).
- Et si le développement de LLVM s'arrête? Ton idée est entièrement dépendante de ce produit. Tout autre gestionnaire de paquet marche avec n'importe quel compilateur.
- Apparemment LLVM ne supporte vraiment que C et C++ pour l'instant (et qques autres en développement). C'est beaucoup étant donné que ce sont les langages les plus utilisés, historiquement. Mais on sait que de nos jours, il y a foultitude plus de langages et que ces autres langages sont de plus en plus utilisés, étant donné qu'on considère de plus en plus le gain de temps apporté par les langages de haut niveau.
Une "solution" serait que les programmes utilisant un langage non supportés seraient en binaire dans tes repositories, et ceux en C/C++ en bytecode. Néanmoins je ne connais pas les statistiques sur le pourcentage de programme non C/C++, mais cela ne m'étonnerait pas que ce soit plus de la moitié des programmes existants. Et dans ce cas, on réduit énormément les intérêts principaux de ton gestionnaire de paquet et de ses dépôts de programme très petits.
Évidemment si à l'avenir, LLVM se met à supporter tous les langages (boulot titanesque), cela n'est plus un problème.
Sinon une petite question: puisque LLVM est avant tout une VM, peut-être n'y aurait-il même pas besoin de compiler en langage machine les programmes chargés, non? Si on considère que qqun utilisant ton gestionnaire de fichier a de toutes façons LLVM d'installé, il peut directement exécuter les fichiers en bytecode, d'où gain de place, de temps, etc. Ensuite je ne sais pas, peut-être que les programmes interprétés ne sont pas suffisamment performants, mais j'ai l'impression de comprendre tout de même que LLVM (qui se définit comme Low Level Virtual Machine) prétend avoir des binaires interprétés plutôt performants. Donc peut-être est-il intéressant de s'arrêter à ce niveau (bytecode) de compilation?
Quoiqu'il en soit, tiens nous au courant des avancées de l'idée...
Film d'animation libre en CC by-sa/Art Libre, fait avec GIMP et autre logiciels libres: ZeMarmot [ http://film.zemarmot.net ]
[^] # Re: Intéressant
Posté par ribwund . Évalué à 2.
Via llvm-gcc, il me semble que llvm supporte les mêmes languages que gcc.
Sinon une petite question: puisque LLVM est avant tout une VM
En fait le nom est assez trompeur, llvm se veut plutot un "compiler toolkit", d'ailleurs le mode just-in-time n'est pas extremement performant (du moins comparé à l'état de l'art, hotspot).
[^] # Re: Intéressant
Posté par Buf (Mastodon) . Évalué à 1.
Il y a en fait 2 front-ends (la partie qui va lire le code) :
- gcc
- CLang
Avec le frontend gcc, ça supporte les mêmes langages que gcc, avec les mêmes extensions non-standard.
CLand est un parseur indépendant réécrit de zéro, qui supporte relativement bien C, mais pour le reste, c'est pas encore ça (mais vu qu'Apple travaille sur LLVM, on peut s'attendre à avoir rapidement un bon support Objective-C)
[^] # Re: Intéressant
Posté par shinobufan (site web personnel) . Évalué à 1.
Et si il est capable de compiler le noyau FreeBSD ou GCC 4.2, c'est qu'il supporte plus que "relativement bien" le C je trouve. C'est très encourageant en tout cas !
[^] # Re: Intéressant
Posté par beagf (site web personnel) . Évalué à 5.
Pour corriger ce que dit l'auteru du journal, on ne peut pas vraiment dire que llvm soit encore vraiment expérimental. Il est relativement proche de ce que 'lon pourrait appeller un programme stable, et encore plus dans le cas de la 2.6 qui va bientot sortir, le freeze c'est produit il y a quelques jours.
Le code intermédiaire devrait être parfaitement compatible dans le sens ou un code actuel devrait rester executable par toutes les futures version de llvm, ce qui n'empeche pas à l'avenir d'ajouter de nouvelles instruction si celles-ci sont nécéssaire.
LLVM est même suffisament stable pour que Apple ait choisit de le mettre au coeur de son système, et contribu pas mal au passage. LLVM est une des brique éssentielle du fameux OpenCL.
Et si le développement de LLVM s'arrête? Ton idée est entièrement dépendante de ce produit. Tout autre gestionnaire de paquet marche avec n'importe quel compilateur.
Vu le projet il y a relativement peut de chance que le dévellopement s'arrete, mais même si c'était le cas, c'est du logiciel libre et il est possible de reprendre le dev.
Apparemment LLVM ne supporte vraiment que C et C++ pour l'instant
LLVM seul ne supporte absolument rien ;-)
C'est juste la spécification d'un code intermédiaire et tout un tas de bibliothèques et outils pour le manipuler et notament le copiler en code natif. Il y a pas mal de projet de compilateurs qui produisent ce code intermédiaire au lieu de produire directement du code natif.
C'est le cas par exemple de clang qui est un copilateur destiner à compiler du C ainsi que d'autre langage dérivés. Et pour CLang, en effet, il supporte actuellement très bien le C et produit du code très performant. L'objective-C est relativeent bien supporté, je sais pas le staus exacte mais là aussi c'est un truc ou apple contribue pas mal. Par contre pour le C++, pour l'instant c'est encore très expérimental et de nombreuse choses ne sont pas implémentée.
Par contre il existe aussi llvm-gcc qui est un bacend pour gcc. C'est-à-dire que c'est une modification de gcc qui lui permet de produire du code llvm au lieu de code pour un processeur. Donc ça permet d'avoir un copilateur qui supporte éxactement les même langages que gcc.
Et il y a différents autres compilos disponibles, même parfois pour des langages auquels on ne penserais as du style un compilateur pour lua.
Sinon une petite question: puisque LLVM est avant tout une VM, peut-être n'y aurait-il même pas besoin de compiler en langage machine les programmes chargés, non?
Comme tu le dis après, L'objectif de llvm c'est quand même de produire du code très performant, et les perfs du code interprété sont quand même pas térrible à côter de celle du binnaire. Et vu le coût du JIT autant ne pas s'en priver.
Et un dernier petit point pour l'auteur du journal. L'argument de ca prend moins de place est loin d'être pertinent, dans la grosse majoritée des pacquet, à mon avis, ce qui prend de la place c'est pas les binnaires mais les donnés. De plus les mesures sont à faire sur le code une foi compressé car à tous les formats de paquets que je connais compressent le tout.
Avant de penser à des optimisation sur la taille du code, il vaudrais mieux faire quelques stat pour savoir s'il y a quelque chose à gagner.
Voilà, j'éspère avoir clarifier quelques points sur llvm et le reste.
# Courgette
Posté par Vincent P (site web personnel) . Évalué à 6.
http://dev.chromium.org/developers/design-documents/software(...)
C'est assez costaud, et il y a le code source dans les sources de Chrome.
http://src.chromium.org/viewvc/chrome/trunk/src/courgette/
Avis aux amateurs qui rêvent de créer leur système de paquet ultra performant...
# simpas l'idée mais ca ne sufit pas pour un getionnaire de paquet
Posté par bibitte . Évalué à 1.
-certain paquet d'un gestionnaire ne contienne que des fichier text (doc, script etc...) et la y'a rien a compiler...
- pour les programme java tu fais comment???
- impossible de faire un paquet pour une appli sans les soucres, je sais si c'est pas libre ca pue. Mais bon en entreprise (pour des raison X ou Y, la n'est pas le sujet) on a pas que du libre et la on ne peut pas l'empaqueter, c'est dommage.
Voila, sinon l'idée est belle...
[^] # Re: simpas l'idée mais ca ne sufit pas pour un getionnaire de paquet
Posté par yellowiscool . Évalué à 2.
Envoyé depuis mon lapin.
[^] # Re: simpas l'idée mais ca ne sufit pas pour un getionnaire de paquet
Posté par steckdenis (site web personnel) . Évalué à 3.
Non, ça ne casse pas, au contraire. Il faut juste garder à l'esprit que tous les paquets ne passeront pas par LLVM.
* Les fichiers qui sont déjà indépendants de l'architecture, tant mieux. Pourquoi changer ça ?
* Les programmes java utilisent déjà une machine virtuelle et sont déjà indépendants de l'architecture, tant mieux aussi.
* De nouveau, le gestionnaire de paquet permettra d'utiliser LLVM, et ne l'obligera pas :) .
Voilà .
[^] # Re: simpas l'idée mais ca ne sufit pas pour un getionnaire de paquet
Posté par bibitte . Évalué à 1.
juste une question (parce que personne ne l'a encore faite ,ou alors j'ai pas vue)) LLVM tu le compile avec quoi ?
[^] # Re: simpas l'idée mais ca ne sufit pas pour un getionnaire de paquet
Posté par steckdenis (site web personnel) . Évalué à 2.
LLVM, ses dépendances, et le kernel seront au moins trois choses compilées avec GCC. Le reste, normalement ça passera (si j'arrive à faire marcher llvm-gcc).
# Avantages et inconvénients
Posté par yellowiscool . Évalué à 2.
Mais l'avantage de pouvoir mettre pleins de drapeaux au moment de la compilation part en fumée.
Envoyé depuis mon lapin.
[^] # Re: Avantages et inconvénients
Posté par ribwund . Évalué à 4.
[^] # Re: Avantages et inconvénients
Posté par kowalsky . Évalué à 2.
[^] # Re: Avantages et inconvénients
Posté par ribwund . Évalué à 2.
A mon avis tu vas voir que si tu lances pas gcc (qui est plutot vieux et lent :) tu gagnes pas énorme à ne pas faire le backend.
[^] # Re: Avantages et inconvénients
Posté par Elfir3 . Évalué à 3.
# De la portabilité de Clang et LLVM
Posté par steckdenis (site web personnel) . Évalué à 3.
Beaucoup d'entre vous se sont inquiétés de la portabilité du bytecode généré par Clang, et utilisé par LLVM.
Il faut dire que le problème est réel, et la doc de Clang très claire, avec un bon exemple : sizeof(void *) est codé en dur dans le fichier .ll
Enfin, c'est ce qui devrait être fait. En effet, dans ce document[1], il est cité quelque-part un warning très intéressant, vraiment très intéressant :
portability.c:4:11: note : sizeof(wchar_t) varies between targets, source is not 'portable'
La ligne de commande d'appel est également très intéressante :
clang -arch ppc -arch linux -fsyntax-only portability.c
Vous avez bien vu, deux architectures sont données. C'est à approfondir, car ça pourrait permettre de dire à Clang «Génère du code portable pour toutes ces architectures», et il trouvera automatiquement ce qui ne va pas (et donc permettra de hacker le code source, et de soumettre un patch :) ).
Affaire à suivre, mais en tous cas, c'est intéressant.
[1] : http://llvm.org/devmtg/2007-05/09-Naroff-CFE.pdf
# Et la compression dans tout ça ?
Posté par Sarcastic . Évalué à 4.
J'ai dans l'idée qu'il se peut que le bytecode passe moins bien la compression que le binaire, auquel cas, la différence pourrait devenir ridicule.
[^] # Re: Et la compression dans tout ça ?
Posté par steckdenis (site web personnel) . Évalué à 3.
* sokoban.bc : 10296 octets (tiens, il devait être plus petit, il faut dire que j'ai un peu changé la chaîne de compilation pour utiliser clang à la place de clang-cc)
* sokoban (éxécutable) : 11360 octets
Maintenant, je compresse les deux en LZMA
* sokoban_bin.lzma : 3755 octets
* sokoban_bc.lzma : 8212 octets
Effectivement, ça calme :/ . Plus qu'à tester sur de plus gros programmes, LLVM est vraiment intéressant et on sait en faire quelque-chose.
Mouais, mais un truc n'est pas bien allé avec le bytecode, il est largement plus gros que ce que je dis dans le journal, ce n'est pas normal (j'ai pourtant utilisé opt, donc ça devrait être bon). Je vais refaire des tests.
[^] # Re: Et la compression dans tout ça ?
Posté par hervé Couvelard . Évalué à 2.
Par exemple, lors de l'installation du système de package-compilation on met les bonnes options de compilations un fois pour toute, avec la possibilité de faire du sur mesure assez pointu, et tous les paquets bytecode seront personnalisés à la compilation, sans se prendre la tête et sans avoir des probs de dépendances de fichiers dev et sans passer X heures et sans gérer les problèmes de compilations exotiques parce que gcc a changé depuis l'écriture du soft.
Maintenant cela impose probablement plus de rigueur dans l'écriture des softs, mais est-ce un mal ? il pourrait par exemple y avoir un 'truc' qui 'pré-compile' le code et qui trouve les choses qui ne sont pas portable, ce qui aiderait grandement les programmeurs du dimanche.
Mais bon, je m'avance un peu car je ne suis pas du tout un pro de l'écriture/compilation, mon expérience s'arrète à faire des poc bien crade\w code de débutant pour montrer ce que j'aimerais avoir et laisser un vrai dev faire le taff. (Et non je ne désire pas faire de poc dans un autre langage car c'est de la triche)
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.