Performances de build Java sous Linux ?

Un matin, j’en ai eu assez d’attendre 15 min à chaque construction mon application par l’usine de développement. Sur mon Mac Book Pro, cela mets deux fois moins de temps. Je suis donc aller chez le revendeur informatique d’à coté, pour acheter un serveur tout neuf. J’installe un Linux (Ubuntu 9.10), je lance mon build, je patiente, et je constate que cela mets 11 minutes. C’est toujours plus lent que sur mon Mac Book Pro; quelle déception ! Effectivement, mon Mac Book Pro est puissant, mais le nouveau serveur contient quand même un coreI5 quad core (le plus rapide que j’ai trouvé), avec 6Go de Ram DDR3 et des disques en RAID 1 !

Pour couronner le tout, un collègue arrive et me dit : j’ai un Windows Seven 32 bits sur une clé USB, on peut essayer si tu veux … On installe, on build, 5 min 30. Ce n’est donc pas le hard qui est en cause …

S’en suit des essais sur plein de distribution linux différentes. J’ai même essayé OpenSolaris. A noter que je souhaite utiliser une distribution « out of the box », c’est à dire que sans effectuer aucune configuration particulière dessus, sans recompiler le noyau ou autre (c’est pourquoi je n’ai pas testé Gentoo).
Chaque essai se déroule de la façon suivante :

  • installation de l’OS
  • installation de la JVM Sun JDK 6 Update 20 (64 ou 32 bits selon l’OS)
  • installation de maven, d’un repository maven pré rempli, du code source
  • 2 builds complets, afin de noter les temps et de faire une moyenne

Voici les résultats :
Sur mon Mac Book Pro Core 2 Duo 3.06 GHz, 8Go de Ram, Disque SSD

OS Temps de build
Mac OS X 10.6 7 min 38

Sur le serveur, Core I5 670 Quad Core 3.46 GHz, 6Go de Ram, Disque 500G Seagate

OS Temps de build Version du noyau Linux
Ubuntu server 9.10 32 bits 11 min 29 2.6.31
Ubuntu server 9.10 64 bits 11 min 11 2.6.32
Open Solaris 2009.06 x86 5 min 16  
Fedora 12 64 bits 10 min 42 2.6.32
Open Suse 11.2 64 bits 10 min 50 2.6.31
Suse Linux Entreprise Server 11 64 bits 4 min 48 2.6.27
Ubuntu server 10.04 LTS 64 bits 4 min 17 2.6.32
Windows Seven 32 bits 5 min 19  

Que constate-t-on ? : Les écarts entre les OS sont énormes !

J’ai fait quelques essais complémentaires :

Virtualisation J’ai essayé ces mêmes distributions en environnement virtualisé sur mon Mac Book Pro, avec Virtual Box. Les temps de compilation sont sensiblement identiques quelque soit la distribution. A noter que OpenSolaris virtualisé compile un poil plus vite que Mac OS X natif !
Ramdisk J’ai aussi essayé de compiler dans un Ramdisk, avec différents filesystems : pas de différences notables. Cela ne semble donc pas venir des IOs.
64 vs 32 Il n’y a pas de différence significative entre un build sur Ubuntu 32 avec JVM 32 et un build sur Ubuntu 64 sur JVM 64. La compression de pointeur (-XX:+UseCompressedOops) spécifiques 64 bits permet d’améliorer le temps de compilation d’une dizaine de % sur JVM 64 bits.
Changer de JVM J’ai essayé, sous Ubuntu 9.10 64 de builder avec une autre JVM : OpenJDK 6, JRockit 5. J’ai obtenu des temps de build sensiblement équivalent.

Est-ce généralisable à tous les builds Java ? Probablement. Mon build n’a rien d’extraordinaire (compilation Java, compilation GWT, beaucoup de tests).

Est-ce généralisable à une application J2EE qui tourne dans un serveur d’application ? c’est possible, mais ce n’est pas prouvé. Le comportement de la JVM sur une exécution longue, contrairement à un build qui est court, peut être assez différent. A tester !

Qu’en conclure ?

  • que les performances de build Java peuvent varier, sur un même hard, d’un facteur 2 selon les distributions Linux. Ce qui est énorme.
  • que je ne sais toujours pas d’où ça vient. Je penche pour une différence de configuration au niveau du noyau linux, mais sans preuve.
  • que faire quelques benchs avant de choisir une distribution n’est donc pas inutile.
  • que faire ces benchs est très facile, toutes les distributions s’installent aujourd’hui en moins d’une demi heure.

J’ai réinstaller le serveur sous Ubuntu 10.04 LTS. Comme c’est maintenant notre usine de développement officielle, je ne peux plus l’utiliser pour faire des benchs Linux. J’aimerais cependant bien trouver d’où viennent ces différences. Je vous propose d’en débattre dans les commentaires, je ferais une synthèse si nous trouvons quelque chose.

33 commentaires sur “Performances de build Java sous Linux ?”

  • Il serait interessant de conduire ce test avec un projet public afin de pouvoir collecter des mesures et peut-être trouver ce qui cloche.
  • Quelle version de maven est-utilisée ? La même sur toutes les plateformes ?
  • Est-ce que vous êtes sûrs d'utiliser le compilateur du JDK et pas gcj par exemple ?
  • La version de maven est la 2.0.9, et c'est la même sur toutes les plateformes. J'utilise une version installée à la main du JDK, pas une version packagée dans la distribution, donc je suis sûr que ce n'est pas gcj.
  • Quel système de fichier utilisez-vous ? La dernière version d'Ubuntu utilise Ext4 ...
  • Quand tu parles de build, as-tu inclu les tests ? Peut-être les tests doivent ils lancer un jetty ? Un bug bien connu sous Linux oblige à lancer jetty avec ce paramètre : -Djava.security.egd=file:/dev/./urandom pour éviter un délai de près de 20s au démarrage de chaque jetty.
  • Très intéressant comme étude. La piste du système de fichier est pertinente vu le nombre de fichiers qui sont générés ou déplacés au cours du build d'un projet. Mais je crois que Suse n'utilise pas encore ext4 par défaut, et que Ubuntu 9.10 l'utilisait déjà (peut-être pas en version serveur ?).
  • Moi aussi je suis sous Linux (Ubuntu 9 ou 10 suivant les machines), et mes builds sont super rapides. -Sur mon PC de dev, avec un disque SSD en ext4, ça met 2 à 3 secondes. -Sur mon Netbook, avec un disque dur classique en ext4, ça met dans les 10 secondes. -Sur mon serveur, avec des disques SSD en Raid1 et en ext3, ça met 7 secondes. De mon expérience l'essentiel de la lenteur d'un build maven vient du filesystem. Je suppose donc qu'il y a un problème sur tes disques: 1) Tu as essayé des utilitaires comme Bonnie++ pour tester? 2) Si tu es en Raid 1, il est certain que tu as du "fakeraid", c'est-à-dire que c'est Linux qui fait le RAID 1 en réalité. Tu devrais tester en supprimant le RAID. 3)Tu peux aussi tester en faisant tourner ton build sur /dev/shm. Mets également le JDK et Maven sur /dev/shm pour des perfs optimales, et tu devrais avoir un build équivalent à celui que j'ai sur mon SSD.
  • Sur ubuntu 9.10, j'ai essayer de compiler dans un RamDisk, ou dans /dev/shm, avec différents filesystems sur le ramdisk (reiserfs, xfs), je n'ai pas eu de différence notable.
  • Au risque d'être un peu lourd, je me répète :) Si vous avez toujours les machines à dispo il serait intéressant de rejouer les tests avec un projet public afin que l'on puisse collecter plus de mesures.
  • Pour ma part j'avais eu beaucoup de variations lors de la mise en place de nos build sous TeamCity. Notre serveur étant hébergé chez OVH, j'ai pu tester différentes versions de noyaux avant de trouver la meilleure configuration (noyau 2.6.32.2 SMP pour une distrib ubuntu 8.04 LTS 64 bits). Un des points importants est la bonne utilisation d'un multi coeur par la JVM. Je pense que l'utilisation de l'option -localWorkers pour la compilation GWT n'est pas négligeable en terme de gain de perf. Si tu compares le temps total entre ton Mac et ton serveur, est-ce que tu as la même répartition de temps (tout est plus lent ou uniquement certaines tâches spécifiques)?
  • Tu n'as pas de différence entre: - Un build sur des disques durs magnétiques en RAID 1 - Un build sur /dev/shm ??? Là tu dois avoir une mauvaise config quelque part, parce que c'est clairement la plus grosse source de gain (ou perte) de perf avec Maven. Ton build ne doit pas faire que compiler, packager et faire des tests unitaires, je me trompe? Je dis bien tests unitaires, pas tests d'intégration.
  • Moi, la question que je me pose, c'est s'il n'existerait pas un projet java destiné à benchmarker/comparer plusieurs environnements. Par exemple, générer un fichier de 1/10/100Mo pour tester le comportement des IO, lever une exception, etc. Un tel projet existe ou il faut le créer ? :)
  • Le type de VM par défaut("HotSpot Client VM" ou "HotSpot Server VM") ne varierait-il pas en fonction de l'OS ? Pouvez-vous essayer en forçant "java -server" et "java -client" ?
  • Serait-il possible de faire les tests de compile pour les distributions graphiques dans un shell natif (alt+shift+1 par exemple) ? Ce que je trouve étrange, c'est la différence entre : - Ubuntu server 9.10 64 bits - Ubuntu server 10.04 LTS 64 bits Une explication possible : les sorties très verbeuses de la compilation, il est possible qu'en passant par X + émulateur de terminal graphique (xterm ou autre) il y ait un facteur de pertes de perfs très important qui viendrait simplement de l'affichage et non de la config kernel ? Sinon, je ne vois pas trop d'où ça peut venir dans le noyau, peut être des options de scheduler, mais j'en doute franchement. Sinon, je suis très agréablement surpris par le temps de compile sous windows 7 Fred
  • Ah ouiii, +1 pour sys. De mémoire, c'est le cas : sous les unices, -server est activé par défaut il me semble.
  • Est-ce que cela ne pourrait pas venir de la gestion du multi-coeur ?
  • Je me souviens d'un collègue qui avait remarqué de grosses différences de performance du compilo GWT entre linux et mac (à l'avantage du mac). Il serait intéressant de faire des tests avec un projet pur java pour voir si ça vient de la partie GWT ou pas.
  • Bonjour Bertrand. Il ne serait pas inintéressant de faire un gros build de code natif, genre kernel ou gcc, très long. Le problème vient peut être de réglages différents dans la partie scheduling Linux et l'avis de spécialistes du noyau serait les bienvenus.
  • Bonjour, A cette liste d'OS, est-ce que tu peux ajouter une distribution RHEL "libre" (ie. CentOS 5.4 par exemple) pour voir si la version "enterprise" de RedHat donne ou non de bon résultats ? Comme aujourd'hui beaucoup de serveurs tournent sur RHEL5.x, le test me paraît pertinent.
  • Je voudrais nuancer... Contrairement à la majorité des gens sur ce forum, je pense plutôt que cela vient du JDK. En effet, Sun doit faire avec le "dénominateur commun". Or, le noyau Linux n'arrête pas d'évoluer : pthreads, NPTL, TLS, etc... Et le support au niveau de la glibc qui va avec. Le JDK Sun a forcément du mal à suivre. TOUS les logiciels "propriétaires" sous Linux ont du mal à suivre (et j'entends ici par "propriétaire" : "dont les sources sont indisponibles" - le JDK Sun coûte 0 €). L'ABI du noyau Linux change vite. MacOS X a une ABI plus stable... Pas étonnant que Sun ait pu "viser juste" du premier coup. Pour donner un exemple, là où je travaille, on utilise le même JDK Sun (1.6) sur RHEL4 et RHEL5 (Centos 4 et Centos 5, même combat). Mais le noyau de RH5 (Centos 5) a bien plus de possibilités de parallélisation (pas de TLS sous RH4 par exemple). Le JDK Sun ne les exploite pas... La "solution" ? Regarder du côté d'OpenJDK... Dont le degré de maturité reste à définir. RH5 le propose, cependant : l'auteur du poste initial pourrait-il faire un test avec cet environnement (RH5/OpenJDK) particulier ?
  • J'ajouterai simplement ceci : le fait que RH5 propose OpenJDK est en soi une garantie de sa pérennité. Red Hat n'a jamais, dans son histoire, essayé de vendre une techno "pas mûre" en entreprise. Par conséquent, cela vaudrait vraiment le coup de voir ce que donnerait, non seulement en temps de compil mais aussi en tenue en charge, un couple RH/Sun vs du "RH pur". Il faudrait que j'essaie...
  • @fge: - open jdk est le jdk de sun - apple fait son jdk, pas sun - de quels logiciels propriétaires parlez vous ? Quel rapport avec le coût du jdk sun ? - qu entendez vous par rh pur ?
  • Il faudrait distinguer le temps pris par la compilation du temps pris par les tests et savoir ce que font ces tests. Sinon, impossible de conclure.
  • Je pense savoir pour quelle raison ton build est si long: la compilation GWT. Effectivement sur mes bécanes Linux GWT est très lent, et je ne me souviens pas que c'était si pénible sous Mac (mais ça fait quelques années maintenant). Est-ce que tu pourrais faire le même genre de test sans GWT, ou exclure GWT de ton build? Va savoir ce que fait GWT à la compilation... Tu as forcément un problème de config ou un truc anormal, sur mes 3 machines le build Maven sous Ubuntu est ultra rapide.
  • Bonjour, Je réponds à tout le monde d'un coup, c'est plus simple pour moi. Mon build contient (j'ai mis le temps de chaque phase sur mon mac): - une phase d'initialisation et de génération de code avec CXF et GWT (25 secondes) - une phase de compilation Java (1732 classes, 11 secondes) - une phase de compilation GWT (102 secondes) - une phase de compilation de test (528 classes, 5 secondes) - une phase de test (plus de 3000 tests). Ces tests sont des tests unitaires, et des tests d'intégration (un jetty est lancé -une seule fois- pour héberger des mocks de web services) (295 secondes) - une phase de packaging (20 secondes) J'ai constaté, que, quelque soit la longueur globale du build, le ratio GWT/total ou test/total est quasiment constant. Je confirme ne pas avoir de différence entre build en RamDisk et build sur un vrai disque dur (que cela soit une VM, un SSD, ou un HDD). J'ai essayé avec ou sans -server, pas de différence notables. Pour les Ubuntu, j'installe des distributions serveur dans serveur X. A noter le temps de compilation très rapide avec OpenSolaris, qui contient un serveur X. La plupart des compilation se font à distance via SSH. Pour le multi coeur, la compilation GWT se fait sur plusieurs JVM, donc à ce momment tous les coeurs sont utilisés. Pour tout le reste (compilation Java + test, on a une forte consommation CPU, mais pas 100%). Sur mon mac : entre 70 % et 100 % de moyenne sur les 2 coeurs. La machine n'est actuellement plus disponibles pour faire d'autres tests.
  • J'ai eu de grosse différence sur des temps de build à cause du fork (ou pas) des tests JUnit dans un build Ant. Forker une JVM semble très couteux, c'est mieux d'éviter donc (le problème c'est qu'on ne part plus d'une JVM "propre").
  • Bonjour Bertrand, Peux-tu préciser quel est la phase qui varie entre tes builds rapides et les plus lent ?
  • Sorry for speaking english, but I have a suggestion as to what may be causing this problem: Your linux may be running out of entropy for the secure random number generation. It turns out that File.createTempFile is a client of SecureRandom, which in turn delegates to os-level random number generation ( I know, it's EXTREMELY important that the random part of a temp-file be bullet-proof ;) Although secure random number generation through /dev/random is a kernel-level feature, it is possible for different distros to install "providers" of entropy to the kernel. Furthermore behaviour is different in different kernel versions. Some MacOSx's and most solarises are also affected by this issue. On linux you can determine if this is happening by running "cat /proc/sys/kernel/random/entropy_avail" in a window as your build runs. If the number goes below 50 and stays there for any amount of time you're probably in trouble. If you think you have trouble, the first advise in this article solved it for me: http://bredsaal.dk/improving-randomness-and-entropy-in-ubuntu-9-10
  • Kristian, it's a very good point and should be checked. Sinon, je confirme le fork d'une JVM est très couteux. J'ai eu le cas d'une application Java, simple, ou le temps d'initialisation de la JVM était plus long que celui de traitement.
  • Bonjour @Philippe voncken : globalement, le temps de chaque phase est proportionnel au temps global de build. C'est notamment valable pour : - la génération du code (GWT et CXF) - la compilation java - la compilation GWT - les tests Donc, il n'y a pas de phase spécifique qui justifie la différence entre les builds lents et rapide. @Kristian Rosenvold Under Ubuntu 10.04, available entropy is between 130 and 200. Sometimes, entropy available goes under 10 under a build. But, it's not systematic, and build seems not to be slower. On my old software factory, average value is 3000. It goes under 150 during a build (particulary during tests). I will to try to check this point under ubuntu 9.
  • Sous une Suse SLES 10 SP2, je suis en constant à 3592
  • Salut, je fais un petit UP... mais beaucoup n'ont pas vu un mot important .. Le disque dur sur ton MACBOOK est un SSD alors que sur ton serveur, tu as un HDD... La différence vient de là, pas plus ni moins.... ;)
    1. Laisser un commentaire

      Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *


      Ce formulaire est protégé par Google Recaptcha