<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Artisan Numérique</title>
  <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1170"/>
  <link rel="self" type="application/atom+xml" href="http://artisan.karma-lab.net/node/1170/atom/feed"/>
  <id>http://artisan.karma-lab.net/node/1170/atom/feed</id>
  <updated>2008-10-21T16:03:45+02:00</updated>
  <entry>
    <title>Mise en oeuvre de distcc</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1170" />
    <id>http://artisan.karma-lab.net/node/1170</id>
    <published>2008-08-12T21:37:10+02:00</published>
    <updated>2008-10-21T16:03:45+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Outils" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>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 <a class='external' target='_blank' href='http://distcc.samba.org/' >distcc</a>, un petit outil bien pratique qui permet de distribuer la compilation.</p>    ]]></summary>
    <content type="html"><![CDATA[<p>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 <a class='external' target='_blank' href='http://distcc.samba.org/' >distcc</a>, un petit outil bien pratique qui permet de distribuer la compilation.</p>


	<a name='chapter_1'></a>
  <h2>introduction</h2>
	
<p>
   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 <kbd>distcc</kbd>.  
</p>
<p>
   Cet outil est composé d'un client et d'un serveur. Le serveur est en écoute du port <kbd>3632</kbd> (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.  
</p>
<p>
   Maintenant pour que cela fonctionne, il faudrait que <kbd>gcc</kbd> puisse savoir communiquer avec ce client. La solution adoptée est en fait un peu différente car le client <kbd>distcc</kbd> est paramétré lors de la configuration de la compilation comme étant LE compilateur. Servant ainsi d'intermédiaire entre l'outil <kbd>make</kbd> et le compilateur réel <kbd>gcc</kbd>, la magie peut opérer, le client <kbd>distcc</kbd> peut décider où telle compilation doit se faire.  
</p>


	<a name='chapter_2'></a>
  <h2>Configuration des serveurs</h2>
	
<p>Comme nous l'avons vu, <kbd>distcc</kbd> 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 <kbd>distcc</kbd> vérifiera qu'elle sont utilisable avant de leur envoyer des compilations à effectuer. Autant donc installer ce serveur sur toutes les machines. 
</p>
<p>
  Pour communiquer avec un serveur, <kbd>distcc</kbd> dispose de deux méthodes. Soit directement en se connectant sur le port <kbd>3632</kbd> 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 <a class='external' target='_blank' href='/node/82' >sans mot de passe</a>. 
</p>

<p>
	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 <a class='external' target='_blank' href='http://www.xinetd.org/' >xinetd</a>. Je préfère personnellement la seconde méthode qui évite d'avoir le serveur chargé en mémoire en permanence. </p>


<p>
  Dans touts les cas, il faut commencer par installer le client. Le paquet varie selon les distributions. Sous Debian il s'agit simple de <kbD>distcc</kbd> qui contient tout, client et serveur. Sous Mandriva il y a <kbD>distcc-daemon-standalone</kbd> pour la version sans Xinetd et <kbd>distcc-daemon-xinetd</kbd> pour la version avec. Sans xinetd le résultat est que vous lancez le service par un <kbd>/etc/init.d/distccd start</kbd>. Avec xinetd vous devez avoir le fichier <kbd>/etc/xinetd.d/distcc</kbd> suivante:
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  service distcc<br />
{<br />
&nbsp; &nbsp; &nbsp; &nbsp; socket_type &nbsp; &nbsp; = stream<br />
&nbsp; &nbsp; &nbsp; &nbsp; protocol &nbsp; &nbsp; &nbsp; &nbsp;= tcp<br />
&nbsp; &nbsp; &nbsp; &nbsp; wait &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= no<br />
&nbsp; &nbsp; &nbsp; &nbsp; user &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= distccd<br />
&nbsp; &nbsp; &nbsp; &nbsp; server &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= /usr/bin/distccd<br />
&nbsp; &nbsp; &nbsp; &nbsp; server_args &nbsp; &nbsp; = --inetd<br />
&nbsp; &nbsp; &nbsp; &nbsp; env &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = TMPDIR=/tmp<br />
&nbsp; &nbsp; &nbsp; &nbsp; disable &nbsp; &nbsp; &nbsp; &nbsp; = no<br />
}
  </div>
  <div class='caption'>/etc/xinetd.d/distcc</div>
  </div>
  </p>
<p>
  Une fois le tout installé, vous devez avoir une réponse positive à la commande <kbd>netstat -anlp | grep 3632</kbd>
  </p>
  

	<a name='chapter_3'></a>
  <h2>Configuration du client</h2>
	
<p>La définition des serveurs peut se trouver soit dans un fichier <kbd> ~/.distcc/hosts</kbd>, soit dans la variable <kbd>DISTCC_HOSTS</kbd>. 
</p>

<p>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). 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  machine_surpuissante machine_puisante_de_gaston machine_puissante_sur_internet machine_chargé vielle_brouette
  </div>
  
  </div>
</p>
<p>
  Pour définir un serveur utilisable par SSH, il suffit de placer des <kbd>user@</kbd> devant le nom des machines utilisant ssh. <kbd>user</kbd> é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 <kbd>@</kbd>. 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 <kbd>,lzo</kbd> à la fin du nom. Cela nous donne pour deux machines distantes :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  machine_surpuissante gaston@machine_puisante_de_gaston @machine_puissante_sur_internet,lzo @machine_chargé vielle_brouette
  </div>
  
  </div>
</p>
<div class='inline-box note'>
   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. 
</div>
<p>
Dernier point, <kbd>distcc</kbd> 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 <kbd>/nombre_de_tâches_maximum</kbd>. 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 :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  machine_surpuissante/8 gaston@machine_puisante_de_gaston @machine_puissante_sur_internet,lzo @machine_chargé vielle_brouette/1
  </div>
  
  </div>
</p>
<p>
Maintenant ce n'est pas parce que nous déléguons des compilations que la machine locale ne doit rien faire :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  machine_surpuissante/8 localhost/2 gaston@machine_puisante_de_gaston @machine_puissante_sur_internet,lzo @machine_chargé @vielle_brouette/1
  </div>
  
  </div>
</p>


	<a name='chapter_4'></a>
  <h2>Lancement de la compilation</h2>
	
<p>
<image file="distcc-mon.png" width="150px"/>Une fois <kbd>distcc</kbd> paramétré sur le client et sur les serveurs, son utilisation se fait de deux manières. Soit en spécifiant <kbd>distcc</kbd> dans la commande <kbd>./configure .... --cc=distcc</kbd>, soit au moment du <kbd>make</kbd>. 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, <kbd>make</kbd> va être utilisé pour spécifier le nombre de fichier à compiler en parallèle grâce à l'option <kbd>-j</kbd>. Ainsi si l'on table sur ce qui a été décrit plus haut, on peut aller jusquà environ 14 compilations concurrentes, soit un <kbd>-j25</kbd>. Enfin pour rajouter un peu de contrôle dans tout cela, installez le paquet <kbd>distcc-gnome-monitor</kbd> et lancez le avant la compilation. Cela nous donne :

  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># lancement du moniteur</div><div class='command'><span class='prompt'>gaston$</span>distccmon-gnome&</div><div class='result'>&nbsp;</div><div class='co0'># Lancement de la compilation</div><div class='command'><span class='prompt'>gaston$</span>make -j 14 CC=distcc</div><div class='result'>CC      drivers/base/topology.o</div><div class='result'>CC      drivers/acpi/parser/pswalk.o</div><div class='result'>CC      arch/x86/pci/irq.o</div><div class='result'>CC      kernel/irq/resend.o</div><div class='result'>CC      drivers/acpi/namespace/nsdump.o</div><div class='result'>CC [M]  arch/x86/kernel/cpu/cpufreq/e_powersaver.o</div><div class='command'><span class='prompt'>gaston$</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>

<div class='inline-box attention'>
  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 <a class='external' target='_blank' href='/node/1146' >cette astuce</a>.
</div>


	<a name='chapter_5'></a>
  <h2>Conclusion</h2>
	
<p>
   Vous n'avez ici qu'un ébauche pragmatique de ce qu'il est possible de faire avec <kbd>distcc</kbd>. Pour aller plus loin avec gestion de cache, équilibrage de charge, etc, allez faire un tour à la fin de cette <a class='external' target='_blank' href='http://distcc.samba.org/' >page</a>.
</p>
    ]]></content>
  </entry>
</feed>
