I. Informations générales▲
Qui es-tu ? Peux-tu te présenter à nos lecteurs ?
Je m'appelle Laurent Bourgès, 40 ans et je vis à Grenoble. J'ai appris la programmation enfant en autodidacte en commençant par le BASIC (sur ZX 81 puis TO7), Pascal (PC 486) puis C++, car j'ai toujours aimé l'infographie, c'est-à-dire le rendu sur ordinateur (graphisme, ray-tracing 3D…).
J'ai étudié la physique (ingénieur) puis travaillé 9 ans à Paris dans plusieurs sociétés de services (SSI) où j'ai découvert Java et son écosystème (bibliothèques, open source) en réalisant des applications d'entreprise J2EE, où je me suis fortement impliqué dans la conception en architecture distribuée, l'optimisation, le diagnostic et les tests de performance.
En 2009, j'ai rejoint une équipe du laboratoire d'astrophysique de Grenoble pour développer des logiciels utilisés par les astronomes pour préparer leurs observations et exploiter ces données (GUI Java et web services).
En quoi consiste ton travail au quotidien ?
À l'observatoire de Grenoble, je développe des logiciels en méthode agile avec les astronomes et géophysiciens et aussi dev-ops, car je m'occupe de la conception, du développement, des builds, jusqu'à l'exploitation des logiciels et services. J'utilise différents langages (shell, Java, C/C++, Python, Web) pour réaliser soit des interfaces graphiques soit des web services, mais mon expertise porte surtout sur Java avec 15 années d'expérience orientées sur la performance, la robustesse et la programmation multi-thread.
J'utilise de nombreuses bibliothèques open source et souvent je rapporte des bogues et des corrections (grâce aux sources libres).
C'est par hasard en testant mes logiciels en 2013 avec OpenJDK 1.7 fourni par la distribution Ubuntu que j'ai découverte que OpenJDK souffrait d'un problème de performance au niveau du moteur de rendu vectoriel lorsque l'antialiasing était activé : le profileur Netbeans m'a rapidement indiqué une forte consommation de mémoire et beaucoup de temps passé dans les classes sun.java2d.pisces.* présentes dans Open JDK depuis la version 1.6.
J'ai donc récupéré les sources de OpenJDK 8 (~ 1 Go) et étudié le cœur du pipeline Java2D de rendu et surtout décortiqué les classes de la brique Pisces par reverse-engineering pour voir comment l'améliorer. C'était un exercice difficile, car il n'y avait quasiment pas de documentation ni de commentaires dans le code pour expliquer les algorithmes utilisés (Computer Graphics).
Quels sont tes projets actuels ?
Je ne vais pas détailler les projets réalisés dans mon travail (de jour), mais présenter par la suite mes projets open source, réalisés sur mon temps libre (le plus souvent en soirée et des fois le week-end). Depuis 2014, je développe plusieurs projets sous licence GPL sur mon compte github https://github.com/bourgesl/ dont les principaux :
- Marlin renderer : un moteur optimisé d'antialiasing pour le rendu vectoriel, dérivé du moteur Pisces. Il est utilisé par la JVM pour implémenter Graphics2D.draw/fill (Shape) et des releases binaires sont disponibles et compatibles de Java 1.6 à Java 8 ;
- Marlin FX : le portage du Marlin renderer pour JavaFX 8 (intégration différente dans le moteur graphique Prism) ;
- MapBench : un outil de test et de benchmark de rendu java2D utilisant des cartes réelles (sérialisées à partir de GeoServer).
L'outil MapBench est complémentaire au développement du Marlin renderer, car ces tests de qualité et de performances m'ont permis d'évaluer les gains de chaque micro-optimisation réalisée que ce soit en single-thread (GUI) ou en multi-thread (server-side).
J'ai vraiment passé énormément de temps sur ces projets en 2014/2015, puis sur l'intégration de Marlin dans OpenJDK 9 (2015) et de MarlinFX dans OpenJFX 9 (2016), complètement bénévolement et en solo.
Quels sont tes projets futurs ?
Je souhaite poursuivre, dans la mesure du possible, l'évolution du moteur Marlin pour améliorer la qualité de rendu (gamma correction), la précision de l'antialiasing (algorithmes « exact sampling » au lieu de « super sampling » comme proposé dans la bibliothèque agg), mais aussi un clipping efficace (absent pour l'instant) pour accélérer les formes complexes où des parties sont en dehors de la zone visible.
Cependant, ces améliorations algorithmiques nécessitent beaucoup de temps et d'investissement (R&D) pour mettre au point le code, tester dans tous les sens et ensuite itérer des phases de benchmark et d'optimisation ! J'aurais besoin d'un coup de main : cependant il est difficile de rentrer dans ce genre de code vraiment pointu (algorithmes avancés en Computer Graphics) et optimisé (difficile à lire et pleins d'astuces).
Pour l'instant, je vais poursuivre la maintenance (branches github vs OpenJDK/OpenJFX), améliorer quelques faiblesses (bogues simples) dans Java2D et JavaFX, par exemple mes patchs sur les classes Path2D ou PNGImageWriter.
Enfin, j'aimerais faire une présentation à JavaOne 2017 pour présenter le moteur Marlin intégré dans le JDK9, mais il m'est difficile de trouver des sponsors pour financer une mission à San Francisco en contrepartie de ma contribution à titre personnel à OpenJDK.
II. Marlin et MarlinFX▲
Tu es le créateur de Marlin et MarlinFX, peux-tu nous en dire plus à ce sujet ? Quelle est la genèse du projet ?
Le projet Marlin a émergé en 2014 sur github après quelques mois de travail à reprendre le code du moteur Pisces issu de OpenJDK 8 et avoir proposé mes premiers patchs, sans succès, sur la liste 2d(@openjdk.java.net). Andréa Aimé, leader technique du projet GeoServer, m'a vraiment poussé à poursuivre mes efforts en créant un fork sur github en open source (GPL v2) pour le distribuer et faire ses preuves sur des vrais cas d'utilisation : cette démarche a été un succès.
Pour mieux comprendre, ce moteur calcule la proportion des pixels couverts par les formes Shape (path constitués de segments et de courbes) en estimant le nombre de sous-pixels couverts (super-sampling 8x8). Il comporte aussi la gestion du pinceau (Stroker width), des pointillés (Dasher) et du remplissage (draw or fill Shape).
J'ai d'abord optimisé sa consommation de mémoire en recyclant les nombreux tableaux int[], float[] utilisés pour éviter l'overhead du Garbage Collector (GC) notamment avec de nombreux threads (server-side map rendering). J'ai donc utilisé un contexte (ThreadLocal) qui représente ~ 512 K de mémoire où je stocke et recycle tous les tableaux et j'ai adopté une approche efficace de nettoyage partiel de ces tableaux : pourquoi effacer entièrement chaque tableau si je sais que seulement les 13 premiers éléments sont « dirty ».
En février 2014, j'ai distribué une première version Marlin 0.3 qui a démontré l'intérêt de ce nouveau moteur optimisé : ~ 30 % plus rapide que Pisces sur un benchmark GeoServer réaliste. Ensuite, j'ai optimisé progressivement et minutieusement, de plus en plus le code (chaque boucle), puis revu chaque algorithme (merge sort, block & tile fills) sans oublier d'améliorer aussi la qualité visuelle (subpixel accuracy). Mon objectif avec Marlin était d'atteindre les performances du moteur Ductus (codé en C, closed-source) du Oracle JDK et Marlin (en pur Java) est parvenu à être aussi rapide (voire plus) en mono-thread que ce moteur « professionnel » intégré depuis JDK 1.2. Bien entendu, Marlin a une scalabilité idéale pour du rendu multi-thread, contrairement au moteur Ductus et surpasse facilement le moteur Pisces.
En 2015, j'ai participé à la conférence FOSDEM à Bruxelles où j'ai eu la chance de discuter avec des membres d'OpenJDK comme Dalibor Topic (Oracle) et Mario Torré (Red Hat). Ils m'ont proposé de rejoindre le projet graphics-rasterizer pour y intégrer Marlin et évaluer son code, ses performances et sa possible intégration dans OpenJDK. Avec l'aide de Jim Graham et Phil Race (Java2D team), j'ai passé six mois à adapter Marlin pour OpenJDK 9 en proposant des patchs, revus et corrigés (webrev). Cette étape a été longue et fastidieuse avec de très longs échanges de mails sur les revues de code. Cette première intégration réussie (avec cinq patchs importants) a abouti à proposer le Java Evolution Process 265 (JEP) pour intégrer Marlin dans OpenJDK9 comme moteur d'antialiasing par défaut. Le JEP 265 a été accepté et nous avons de nouveau collaboré pour intégrer le code et fixer quelques problèmes avec Jigsaw (modules Java 9) avant fin 2015 pour la Feature Freeze Deadline.
En 2016, j'ai présenté mon travail sur l'intégration de Marlin dans OpenJDK à la conférence FOSDEM 2016, corrigé quelques bogues, continué à améliorer le code (refactoring) et optimisé quelques cas pathologiques (formes étendues donc optimalisation des copies partielles de tableaux). Comme j'ai reçu des demandes répétées sur OpenJFX, j'ai fini par me décider à porter Marlin pour JavaFX, c'est-à-dire réécrire les interfaces entre le pipeline Prism et Marlin - ce qui a donné le projet MarlinFX -, mais cela a aussi permis de récupérer des corrections réalisées par Oracle dans OpenPisces (Dasher/Stroker). Plus rapidement que prévu, MarlinFX a été opérationnel (~20 % à 50 % gain FPS) et j'ai proposé cette contribution comme Request For Enhancement pour OpenJFX9 qui a été acceptée. MarlinFX a été finalement intégré en décembre 2016 (à la dernière minute), mais il reste désactivé par défaut dans JDK 9 (Java Pisces ou Native Pisces restent utilisés).
Enfin, cet effort sur MarlinFX m'a permis de fixer des problèmes de précision numérique (double vs single precision) en générant le code d'une 2e variante du moteur de rendu en double précision que j'ai depuis repris dans le projet Marlin. Donc Marlin et MarlinFX proposent maintenant deux pipelines aux performances quasi identiques.
Bien sûr, cela me pose des problèmes pour gérer toutes ces variantes, branches entre github, OpenJDK 9 et OpenJFX 9 au le bénéfice de la communauté et je me demande comment je pourrai maintenir tout cela dans le futur.
FOSDEM 2016 slides about 'Marlin renderer, a successful fork and join the OpenJDK 9 project': https://bourgesl.github.io/fosdem-2016/slides/fosdem-2016-Marlin.pdf
Qu'est-ce que cela va apporter au futur JDK ?
Dans Java 9, Marlin est le moteur d'antialiasing par défaut de rendu Java2D (Ductus reste disponible dans Oracle JDK9, Pisces dans OpenJDK9) et MarlinFX est disponible, mais désactivé par défaut pour JavaFX (NativePisces reste le moteur par défaut).
Cela apporte de meilleures performances, surtout pour les formes (Path) complexes, mais aussi une meilleure qualité du rendu et des corrections nombreuses (bogues fixés) par rapport à Pisces et Ductus.
Concernant les performances, Marlin reste un moteur de rendu Software, donc il utilise seulement le CPU et pas le GPU. En exploitant OpenGL, il est possible d'écrire un moteur de rendu beaucoup plus rapide (sans comparaison), mais il y aura des différences visuelles notables par rapport à l'existant. Enfin, Marlin gère très bien le multi-threading donc il a une très bonne scalabilité sur un serveur comme GeoServer, qui réalise du rendu vectoriel en parallèle.
Pourquoi MarlinFX n'est pas activé par défaut sous Java 9 ?
J'ai réalisé ce projet en 2016, et proposé son intégration dans OpenJFX9, après la Feature Freeze de OpenJDK9. Le responsable de OpenJFX9 a accepté s'il restait désactivé par défaut pour éviter tout risque potentiel si proche de la release Java 9, prévu en mars 2017 (à ce moment-là). Depuis avril 2017, MarlinFX (double précision) est le moteur par défaut dans OpenJFX 10.
Comment ta création a-t-elle fini au sein du JDK et comment se déroule le travail coopératif au sein de l'OpenJDK ou de l'OpenJFX ?
Comme je l'ai déjà expliqué, Marlin est dérivé du code de Pisces fourni dans OpenJDK sous licence GPL v2. Pour respecter cette licence dite « virale », Marlin adopte la même licence et son code est disponible sur github. Pour moi, le but initial de cette licence est de libérer les codes source pour permettre à quiconque de l'améliorer au bénéfice de la communauté. C'est pourquoi j'ai pu récupérer le code de OpenJDK Pisces, le modifier (fork) pour le rendre plus performant tout en souhaitant retourner ces améliorations dans OpenJDK (join) pour partager le plus largement possible.
Pour proposer des patchs sur le JDK, il faut rejoindre la communauté OpenJDK en s'inscrivant d'abord aux mailing-lists et envoyer un mail de proposition. Ensuite, cela dépend de l'intérêt de ce groupe de personnes pour le patch proposé. Il faut parvenir à convaincre de son intérêt, facile pour un « bug fix », mais très délicat pour un code comme Marlin (~ 10 000 LOC). Ensuite il faut suivre le fil de discussion qui peut durer assez longtemps à cause des décalages horaires et des délais entre chaque message : il faut de la persévérance. De plus, mes participations aux conférences FOSDEM m'ont bien aidé à convaincre quelques responsables du projet OpenJDK en discutant directement avec eux.
Ainsi, j'ai obtenu les droits d'avoir un compte sur l'infrastructure OpenJDK (bugs.java.net, cr.openjdk.java.net pour héberger les patchs et change requests) et progressivement je suis passé de simple « contributor » à « commiter » sur OpenJDK9 ce qui veut juste dire que je respecte les règles communes : builds, tests, emails, utilisation des web reviews, gestion de revue de code, mercurial pull & push. Contribuer à OpenJDK permet d'apprendre beaucoup de choses, mais le processus pour soumettre et intégrer un patch est long, car il faut répéter la séquence à chaque changement de code : faire une build à jour (get_source.sh + make images), rejouer les tests, mettre à jour le fichier webrev, uploader sur cr.openjdk.java.net, envoyer un mail pour répondre aux commentaires, etc.
Heureusement, Phil Race a rédigé pour moi le JEP 265 et bien aidé à le faire accepter dans la roadmap JDK9 (deux sponsors nécessaires). De plus, chaque patch doit être associé à un bug ID, donc il faut aussi créer et gérer des bogues sur bugs.java.net, mais cela contribue à une meilleure traçabilité et visibilité des changements.
Voir :
- http://openjdk.java.net/contribute/
- https://bugs.openjdk.java.net/browse/JDK-8076529?jql=text%20~%20%22marlin%22
Que penses-tu des applications bureau face aux applications web ? Ont-elles encore de l'avenir ?
En étant un « vieux » développeur, j'ai vu évoluer le web de façon impressionnante et j'avoue que certaines applications web avec des tonnes de JavaScript me font peur et je me demande comment ça peut se déboguer et être maintenu. Pour moi, le web servait à afficher des pages alors que maintenant, il est possible de gérer des fichiers, de la visualisation de cartes, données (d3.js, web gl)… Cependant, si le volume de données est trop important, alors le client web va être à la peine (transfert réseau) et gestion des millions d'objets en JavaScript.
Je développe des applications scientifiques en Java avec des plots interactifs (zoom, images calculées à la volée) et je préfère un langage typé (Java ou C) ou alors des notebook python, car ce langage est utilisable par les scientifiques, contrairement au Java ou JavaScript.
En conclusion, les applications de bureau vont persister tant qu'elles permettent de réutiliser du code (bibliothèques C ou Java)c(car porter tout en JavaScript n'est pas la panacée) et offrent une meilleure ergonomie ou de meilleures performances qu'une application web.
III. Developpez.com▲
Connais-tu Developpez.com ? Si oui, qu'est-ce que cela t'apporte ou t'a apporté ?
Oui, cela m'arrive de lire des articles ou parcourir des tutoriels pour faire de la veille technologique.
Quelles sont tes impressions sur cette communauté francophone basée sur le développement ?
C'est vraiment génial d'avoir des articles et tutoriels en français pour les débutants et ceux qui ne parlent pas bien anglais, ce qui n'est plus mon cas (;-D) Bravo !
IV. Suivez Laurent Bourgès▲
- Twitter : https://twitter.com/laurent_bourges
- Google + : https://plus.google.com/111406946106562758726
- Github : https://github.com/bourgesl
V. Remerciements▲
Nous tenons à remercier Laurent Bourgès d'avoir accepté de se prêter à cette interview et de nous faire partager son expérience sur sa contribution à la prochaine version de Java 9.
Nous tenons à remercier Claude Leloup pour la relecture orthographique de cet article et Mickael Baron pour la mise au gabarit.