Artisan Numérique

/développement/distcc/ Mise en oeuvre de distcc

Lorsque l'on dispose de plusieurs machines sur un réseau et que l'on se retrouve dans la nécessité de faire une grosse compilation, il est rageant de ne pouvoir compter que sur le processeur de sa seule bécane. C'est là qu'intervient distcc, un petit outil bien pratique qui permet de distribuer la compilation.

introduction

Basiquement la construction d'une application C/C++ se passe en deux étapes : compilation et link. La première consiste à créer les fichier objets à partir des sources et des headers (.c/.cpp/.h), la seconde va lier ces fichiers binaires aux librairies qu'ils utilisent pour produire l'exécutable Cette séparation implique que la compilation peut virtuellement être faite sur n'importe quelle machine disposant des sources, que celle-ci ait les librairies (dépendances) ou pas. C'est sur ce principe que s'appuie distcc.

Cet outil est composé d'un client et d'un serveur. Le serveur est en écoute du port 3632 (par défaut) et va recevoir les fichiers sources et les headers nécessaire à son bout de compilation. Le client va lui ventiler, en fonction de la charges de chaque machine, les sources à compiler sur ces serveurs.

Maintenant pour que cela fonctionne, il faudrait que gcc puisse savoir communiquer avec ce client. La solution adoptée est en fait un peu différente car le client distcc est paramétré lors de la configuration de la compilation comme étant LE compilateur. Servant ainsi d'intermédiaire entre l'outil make et le compilateur réel gcc, la magie peut opérer, le client distcc peut décider où telle compilation doit se faire.

Configuration des serveurs

Comme nous l'avons vu, distcc a besoin pour fonctionner de connaître les différents serveurs à sa disposition. Il est possible de configurer toutes les machines d'un réseau que celles-ci soient allumée ou pas. En effet distcc vérifiera qu'elle sont utilisable avant de leur envoyer des compilations à effectuer. Autant donc installer ce serveur sur toutes les machines.

Pour communiquer avec un serveur, distcc dispose de deux méthodes. Soit directement en se connectant sur le port 3632 de la machine distante, soit en utilisant SSH. Le premier cas est trés adapté à un réseau local, le second permet d'utiliser des machines en passant par le réseau publique de manière sécurisée avec ou sans mot de passe.

Pour ce qui est du mode "réseau local", il y a encore deux possibilités. La première consiste à lancer le serveur en permanence ou alors utiliser xinetd. Je préfère personnellement la seconde méthode qui évite d'avoir le serveur chargé en mémoire en permanence.

Dans touts les cas, il faut commencer par installer le client. Le paquet varie selon les distributions. Sous Debian il s'agit simple de distcc qui contient tout, client et serveur. Sous Mandriva il y a distcc-daemon-standalone pour la version sans Xinetd et distcc-daemon-xinetd pour la version avec. Sans xinetd le résultat est que vous lancez le service par un /etc/init.d/distccd start. Avec xinetd vous devez avoir le fichier /etc/xinetd.d/distcc suivante:

service distcc
{
        socket_type     = stream
        protocol        = tcp
        wait            = no
        user            = distccd
        server          = /usr/bin/distccd
        server_args     = --inetd
        env             = TMPDIR=/tmp
        disable         = no
}

Une fois le tout installé, vous devez avoir une réponse positive à la commande netstat -anlp | grep 3632

Configuration du client

La définition des serveurs peut se trouver soit dans un fichier ~/.distcc/hosts, soit dans la variable DISTCC_HOSTS.

Que ce soit dans le fichier ou dans la variable, les serveurs sont spécifiés dans leur ordre de priorité (généralement de la machine la plus puissante/moins chargée à la moins puissante/plus chargée).

machine_surpuissante machine_puisante_de_gaston machine_puissante_sur_internet machine_chargé vielle_brouette

Pour définir un serveur utilisable par SSH, il suffit de placer des user@ devant le nom des machines utilisant ssh. user étant l'utilisateur que vous utilisez pour la compilation et dont les clefs sont partagées entre les machines maître et esclaves. S'il s'agit du même utilisateur que celui qui va compiler sur la machine maître, le login peut être omis en le mettant qu'un simple @. Enfin, si la machine est sur un réseau un peu lent ou simplement sur internet, le mieux est d'ajouter une compression des données en mettant ,lzo à la fin du nom. Cela nous donne pour deux machines distantes :

machine_surpuissante gaston@machine_puisante_de_gaston @machine_puissante_sur_internet,lzo @machine_chargé vielle_brouette

Tous les programmes ne se parallélisent pas aussi bien. En effet le problème sont les noeuds, c'est à dire les points de compilation où une série de code doit être compilé pour que la construction sue poursuive. Là si une machine est trop loin (transfert lent) ou trop lente, la compilation est bloquée pour les autres et tout le bénéfice est perdu. Contrairement donc à mon exemple de machine sur le net via SSH et de brouette, on cherchera à privilégier les machines puissantes et proches.

Dernier point, distcc envoi par défaut 4 tâches maximum par machine, sans distinction de CPU. Le problème est que notre dernière machine est une brouette comme son nom l'indique mais tout coup de main n'est pas de refus. Nous allons donc seulement éviter de lui donner trop de travail. Cela se fait très simplement en rajoutant à la fin du nom de machine un /nombre_de_tâches_maximum. Dans le même esprit, une machine plus puissant, un dual-core par exemple, peut prendre plus de 4 compilation à sa charge. Cela nous donne :

machine_surpuissante/8 gaston@machine_puisante_de_gaston @machine_puissante_sur_internet,lzo @machine_chargé vielle_brouette/1

Maintenant ce n'est pas parce que nous déléguons des compilations que la machine locale ne doit rien faire :

machine_surpuissante/8 localhost/2 gaston@machine_puisante_de_gaston @machine_puissante_sur_internet,lzo @machine_chargé @vielle_brouette/1

Lancement de la compilation

Une fois distcc paramétré sur le client et sur les serveurs, son utilisation se fait de deux manières. Soit en spécifiant distcc dans la commande ./configure .... --cc=distcc, soit au moment du make. La deuxième option est la plus sage car si quelque chose ne passe pas avec distcc, il est alors possible de s'en passer en n'y faisant plus appel. Dans tous les cas, make va être utilisé pour spécifier le nombre de fichier à compiler en parallèle grâce à l'option -j. Ainsi si l'on table sur ce qui a été décrit plus haut, on peut aller jusquà environ 14 compilations concurrentes, soit un -j25. Enfin pour rajouter un peu de contrôle dans tout cela, installez le paquet distcc-gnome-monitor et lancez le avant la compilation. Cela nous donne :

lancement du moniteur
gastondistccmon-gnome&

Lancement de la compilation
gastonmake -j 14 CC=distcc
CC      drivers/base/topology.o
CC      drivers/acpi/parser/pswalk.o
CC      arch/x86/pci/irq.o
CC      kernel/irq/resend.o
CC      drivers/acpi/namespace/nsdump.o
CC [M]  arch/x86/kernel/cpu/cpufreq/e_powersaver.o

Un détail très important pour que la compilation soit incrémental, c'est à dire qu'elle puisse reprendre à l'endroit vous l'aurez arrêté, est que chaque machine DISTCC soient exactement à la même heure. Pour cela, vous pouvez utilise cette astuce.

Conclusion

Vous n'avez ici qu'un ébauche pragmatique de ce qu'il est possible de faire avec distcc. Pour aller plus loin avec gestion de cache, équilibrage de charge, etc, allez faire un tour à la fin de cette page.