Rencontre des Développeurs LLVM 2012

Posté par . Édité par baud123, Xavier Claude, Benoît Sibaud et Pierre Jarillon. Modéré par Pierre Jarillon. Licence CC by-sa
Tags : aucun
35
25
nov.
2012
C et C++

Les 7 et 8 novembre derniers a eu lieu la Rencontre des Développeurs LLVM 2012 (2012 LLVM Developers' Meeting) à San José en Californie. C'est la sixième rencontre du genre et les participants sont toujours de plus en plus nombreux. Dans son introduction, Chris Lattner, le père de LLVM, a fait un rapide bilan de l'année écoulée.

LLVM (anciennement appelé Low Level Virtual Machine en français : « machine virtuelle de bas niveau ») est une infrastructure de compilateur conçue pour optimiser la compilation, l'édition de liens, l'exécution d'un programme écrit dans un langage quelconque.

En plus des nouvelles fonctionnalités (notament C++11) et des nouvelles architectures prises en charge (Hexagon et MIPS64), Chris a fait état d'une communauté des développeurs LLVM et Clang très dynamique. En ce qui concerne LLVM, 78 nouveaux committers (personnes qui ont du code qui a été incorporé) sont arrivés cette année pour porter le total à 167 committers différents. Les chiffres sont quasiment identiques pour Clang (le frontend C/C++/Objective-C de LLVM) : 72 nouveaux committers pour un total de 132. Le code source de LLVM a grossi de 131 KLoc pour un total de 1,4 MLoc tandis que le code de Clang a grossi de 260 KLoc pour un total de 1,0 MLoc.

La conséquence est l'apparition de nouveaux problèmes : certains patchs ont du mal à être revus, l'infrastructure de build et de test de performance commence à montrer ses limites, la gestion des sorties de nouvelles versions se complique. Chris a donc fait un appel à la communauté pour demander de l'aide dans l'analyse des problèmes de performance, dans l'infrastructure de test, dans la documentation, etc.

Il a également demandé aux contributeurs les plus impliqués de devenir «propriétaire de code» (au sens responsable dudit code). Concrètement, il s'agit de prendre en charge une sous-partie de LLVM dont le propriétaire s'engage à assurer la bonne maintenance et évolution, notamment en passant en revue les patchs concernant cette sous-partie. Immédiatement, de nombreux volontaires se sont fait connaître ou ont été proposés.

La suite de la dépêche propose un résumé de quelques présentations qui ont eu lieu lors de cette rencontre.

Sommaire

LLVM et Clang sur le supercalculateur le plus puissant du monde — Hal Finkel, Argonne National Laboratory

Hal Finkel montre comment LLVM a été adapté sur un des plus gros super-ordinateurs du monde, le BlueGene/Q nommé Mira et installé au Laboratoire National Argonne, laboratoire affilié au Département US de l'Énergie. Ce super-ordinateur est classé 3e du Top500 de juin 2012.

Les processeurs de ce super-ordinateur sont des dérivés de PowerPC avec des capacités étendues de calcul flottant et de calcul vectoriel. Le but, en utilisant LLVM, était d'avoir un compilateur C/C++ performant et à jour. Et aussi, éventuellement, d'avoir accès à d'autres langages qui utilisent LLVM pour produire du code. Il fallait donc pour cela définir un nouveau générateur de code pour cette nouvelle architecture, en se basant sur l'architecture PowerPC déjà en place dans LLVM. Le travail n'a pas été de tout repos et a permis d'améliorer également la prise en charge de l'architecture PowerPC.

Le travail va continuer, notamment autour des aspects parallélisation (OpenMP et MPI).

Résumé - Présentation

Le backend AArch64 : état et prévisions — Tim Northover, ARM

AArch64 est le nom donné à l'architecture 64 bits des processeurs ARM. Aucun processeur réel n'est encore sorti (même s'il existe un modèle) pour cette architecture, mais ARM travaille déjà sur un compilateur basé sur LLVM. Le but de ARM est d'avoir un compilateur pouvant générer des binaires ELF sur Linux, capable de prendre en charge les instructions assembleur, bien testé et capable de compiler du C/C++. Dans un premier temps, les optimisations sont mises de côté.

Le développement du générateur de code pour AArch64 a pris neuf mois et demi. Le framework MC Hammer qui permet de tester de manière systématique l'ensemble des opcodes a été utilisé à nouveau pour construire une suite de tests de non-régression. Des parties plus difficiles ont été rencontrées comme les relocations, la gestion des exceptions, la gestion des informations de debug.

Résumé et Présentation

Analyser les commentaires de documentation avec Clang — Dmitri Gribenko, HPC Center at National Technical University of Ukraine « Kiev Polytechnic Institute »

Dmitri Gribenko s'est attaqué à un élément important de tout bon code source : sa documentation. Le constat de départ était que Clang ignorait superbement les commentaires et que les générateurs de document comprenaient assez mal le C++. L'idée était donc de permettre à Clang de comprendre les commentaires, pour permettre de les tenir à jour, pour permettre à d'autres outils comme les IDE ou les outils de refactoring de les comprendre et pour, peut-être, construire un meilleur outil d'extraction de documentation.

Dmitri est parti de l'idée que les commentaires dans les codes sources C/C++ avaient tous le même format : le format Doxygen. Il a donc ajouté à Clang la capacité de lire et comprendre les commentaires, puis de les attacher aux bonnes déclarations. Les commentaires sont ainsi décomposés pour permettre de détecter des erreurs comme un changement de nom de paramètre non-répercuté dans la documentation, une documentation qui annonce un retour alors que la fonction n'en a pas, etc. L'outil permet aussi d'exporter les commentaires en format XML pour les traiter plus tard.

Le travail ne fait que commencer mais les résultats sont déjà impressionnants et vont sans doute permettre d'améliorer la documentation du code (pour ceux qui considèrent que c'est utile).

Résumé et Présentation

MemorySanitizer, ThreadSanitizer. Détection scalable de lecteur de mémoire non initialisée et data races avec les outils de LLVM — Kostya Serebryany, Google

Kostya Serebryany présente trois outils qui sont utilisés chez Google : AddressSanitizer (ou ASan), ThreadSanitizer (ou TSan) et MemorySanitizer (ou MSan). ASan permet de détecter des erreurs tels que les usages (de mémoire) après libération et les dépassements de tampon. TSan permet de détecter une situation de compétition. MSan permet de détecter les utilisations de mémoire non-initialisée.

Ces trois outils fonctionnent en instrumentant du code LLVM, appuyé par une bibliothèque externe. Comparé à des outils similaires, comme Valgrind, l'instrumentation directe permet une amélioration des performances (un ralentissement de 2 pour ASan contre 20 pour Valgrind). ASan a permit de trouver plus de 500 bugs dans Chrome en une année et demie et plus de 1000 bugs dans d'autres projets (Firefox, FreeType, LLVM, etc). TSan, quant à lui, a un ralentissement entre 2,5 et 7, mais il a permis de trouver plus de 200 bugs dans les applications serveur de Google, plus de 80 bugs dans des programmes Go, et même un bug sérieux dans OpenSSL. Pour l'instant, TSan fonctionne uniquement sur Linux 64 bits. Enfin, MSan a un ralentissement entre 3 et 6 fois, suivant qu'on veuille détecter l'origine de l'erreur ou non. MSan a permis, en deux heures, de détecter une vingtaine de bugs dans une application propriétaire de plus d'un million de lignes de code, tandis que Valgrind faisait la même chose en plus de 24 heures.

Résumé et Présentation et Poster

Modules — Doug Gregor, Apple

Doug Gregor présente une belle idée mais qui n'a sans doute aucune chance de voir le jour : les modules en C. Concrètement, il s'agirait d'implémenter un système de paquetage comme on peut en rencontrer dans d'autres langages (Java, Go) en remplacement des traditionnels en-têtes C. Doug analyse les faiblesses des en-têtes C : ils sont fragiles et peu performants. Là où un simple Hello world en C peut être écrit en 64 octets, si on prend en compte les en-têtes, ce sont 11072 octets qui sont lus. Pour C++, c'est encore pire, un Hello world de 81 octets fait en fait 1163033 octets une fois les en-têtes inclus (<iostream>). Et les en-têtes précompilés ne sont pas, selon lui, une solution.

Il propose donc un système de module. Un import permet alors de faire appel à l'API du module importé. Par exemple, Hello world serait écrit en C :

import std.stdio;

int main() {
  printf(“Hello, World!\n”);
}

Le module std comprendrait plusieurs sous-modules correspondants aux en-têtes actuels : stdio, stdlib, etc.

Les modules seraient implémentés directement dans le fichier C et un outil permettrait d'extraire l'API publique, faisant ainsi disparaître les en-têtes. Pour assurer une transition douce, Gregor propose de passer par des fichiers de mapping entre les modules et les en-têtes :

// /usr/include/module.map
module std {
  module stdio { header “stdio.h” }
  module stdlib { header “stdlib.h” }
  module math { header “math.h” }
}

La compilation permettrait alors de mettre en cache les modules pour une réutilisation optimale, ce qui permettrait d'améliorer les temps de compilation. Les maps pourraient aussi inclure les drapeaux de compilation et de liaison. Enfin, il ne serait plus nécessaire d'inclure dans les objets toutes les bibliothèques, surtout celles à base de template (du genre iostream), alors qu'elles sont éliminés parce que redondante à la liaison.

Ce système de module va être mis en place dans LLVM pour tester sa faisabilité.

Résumé et Présentation

Quelle est la qualité des messages de diagnostic de Clang ? — Matt Beaumont-Gay, Google

Google a fait un bilan des messages d'erreurs renvoyés par la compilation de ses applications internes avec Clang. Plus de 30000 ingénieurs-semaines ont été analysées, pour un total de presque quatre millions de diagnostics : 1472752 notes, 591 warnings et 2383858 erreurs (dont 147893 provenant de -Werror), 34613 erreurs fatales.

Parmi les erreurs les plus fréquentes, plus de 580000 sont des identifiants non-déclarés, presque 300000 sont des membres inexistants, plus de 200000 sont des types inconnus. La force de LLVM est de pouvoir proposer des corrections dans de nombreux cas. En l'occurrence, des corrections sont proposées dans 24% des cas pour les erreurs de noms de membres, dans 31% des cas pour les identifiants non-déclarés, 57% pour les types inconnus.

En ce qui concerne les warnings, ils sont triés par les drapeaux de compilation qui les émettent. Plus de 46000 proviennent de -Wnon-virtual-dtor, plus de 25000 viennent de -Wc++98-compat, plus de 8000 de -Wreturn-type. L'appel à printf est également un grand générateur de warning. Plus de 5800 sont des erreurs de types entre celui qui est annoncé dans la chaîne de format et le type du paramètre et presque 5000 sont des paramètres qui ne sont pas des types de base du C. Parmi les erreurs de types, on trouve des couples assez connus (le premier est le type spécifié, le second le type du paramètre) : int vs size_type (plus de 500 occurrences), char * vs StringPiece (plus de 350 occurrences), int vs int64 (plus de 300 occurrences).

En ce qui concerne les notes (des informations ajoutées à une erreur), l'erreur qui génère le plus de notes en volume par erreur est la conversion de type ambiguë (17,76 notes en moyenne, sur 41 erreurs). L'erreur la plus fréquente qui génère des notes est l'application de sizeof à un type incomplet (8203 erreurs).

Enfin, les erreurs fatalesl'erreur fatale vient d'un fichier non trouvé.

Résumé et Présentation

Construire un vérificateur en 24 heures — Anna Zaks, Apple et Jordan Rose, Apple

Ana Zaks et Jordan Rose nous montrent comment implémenter une vérification dans l'outil Clang Static Analyzer, en moins de 24 heures. L'analyseur statique est chargé d'examiner tous les chemins possibles dans une application, à l'aide d'une exécution symbolique. La complexité d'une telle analyse est exponentielle, mais bornée.

L'idée est, pour cet exemple, de vérifier que l'ouverture et la fermeture d'un fichier sont faites correctement : pas de double fermeture, pas de fichier laissé ouvert, pas de perte de la référence. Après avoir défini un graphe d'états possibles, les différentes transitions entre ces états sont ajoutés quand il y a un appel à fopen ou fclose. Enfin, quand une transition mène à un état d'erreur, un message est affiché. La vérification sait même traiter les deux cas où l'ouverture a échoué ou réussi.

Résumé et Présentation

  • # WOW

    Posté par (page perso) . Évalué à  4 .

    Super intéressants les retours de Google.
    Surtout les outils d'analyse mémoire et autres joyeusetés. Dommage par contre que ça ne tourne que sur du x86, et pas sur des archis un peu plus exotiques (embarquées? :)).

    • [^] # Re: WOW

      Posté par . Évalué à  3 .

      Je pense que ça demande des fonctionnalités très bas niveau. Et comme Google doit fonctionner surtout avec du 64 bits, ils se concentrent sur cette architecture. La présentation donne quelques explications sur pourquoi c'est compliqué en 32 bits.

  • # Ingénieur-semaine

    Posté par . Évalué à  3 .

    C'est très intéressant mais qu'est-ce qu'un "ingénieur-semaine" ? :D

  • # clang

    Posté par . Évalué à  3 .

    Les chiffres sont quasiment identiques pour Clang (le frontend C/C++/Objective-C de LLVM) : 72 nouveaux committers pour un total de 132.

    Si seulement ça permettait d'éviter ce genre de saleté
    #if defined(_WIN32)
    AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.2");
    AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.1");
    AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.2");
    AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
    AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
    AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
    #endif

    Tout le fichier en est rempli

    • [^] # Re: clang

      Posté par (page perso) . Évalué à  4 .

      Comment penses-tu qu'il faudrait faire les choses ? (clang ayant pour but de tourner sur un maximum d'architecture + OS)

      • [^] # Re: clang

        Posté par . Évalué à  3 .

        Perso je pense que le problème vient de mingw car ça serait quand même plus simple et standardisé d'installer une clé de registre et que clang se base dessus pour savoir ou sont les headers. A l’époque ou je jouais encore avec mingw j'avais déjà été choqué par ce bout de code. Il faudrait juste modifier l'installeur de mingw
        ce qui ne doit pas etre très compliqué.

      • [^] # Re: clang

        Posté par . Évalué à  1 .

        Peux être que le but est louable, mais partir de l'hypothèse que mingw est installé sur c:/mingw/ est une assertion vachement bancale. Un argument à la configuration de clang dans le genre de gcc avec "--with-gxx-include-dir" serait quand même plus approprié.

        • [^] # Re: clang

          Posté par (page perso) . Évalué à  3 .

          ben c'est l'option --sysroot justement non ? là c'est juste la recherche d'un chemin par defaut un peu potable. Mais effectivement remplacer le C: par $SYSTEMDRIVE ça serait pas un mal

  • # bitcode vs bytecode ?

    Posté par . Évalué à  4 .

    J'ai cru comprendre que le bitcode utilisé par LLVM n'était pas sensé être stable dans le temps et donc ne pouvait pas être utilisé pour de la diffusion de code (contrairement au bytecode JVM/CLR/Dalvik…). Pourtant, je me disais que ça serait bien pratique d'avoir un langage intermédiaire stable et de pouvoir compiler Debian<notre distro favorite> pour une seule architecture "virtuelle" (je considère naïvement que le gros du temps de compilation doit être dans le frontend+optimisation, mais je suis preneur d'avis éclairés sur la question !), et que apt-get s'occupe de la dernière phase (backend+édition de liens…). ça éviterait à <la distro favorite> de devoir stocker les versions compilées pour toutes les architectures (ce qui occupe de la place sur les serveurs), et ça permettrait aussi d'utiliser les optims spécifiques à son CPU (i386/i686, Altivec, SSE, armhf/armel, etc.) sans pour autant avoir les inconvénients d'une Gentoo (temps de compilation prohibitif, surtout sur des petites machines). Qu'en pensez-vous ? Est-ce que l'IR de LLVM pourrait tenir ce rôle à terme ? Ou sinon, <votre bytecode préféré> ?
    (N.B. bon évidemment ça ne marche pas avec les programmes qui contiennent de l'asm inline. Mais je présume que ces programmes sont minoritaires dans une distro ?)

    • [^] # Re: bitcode vs bytecode ?

      Posté par (page perso) . Évalué à  9 .

      Paul Tagliamonte et moi même travaillons à utiliser un peu plus de LLVM & Clang dans Debian.
      Paul pousse justement ta proposition pour produire une Debian LLVM IR. Un des problèmes, c'est que l'IR LLVM n'est pas portable comme celle Java peut l'être…
      Un de ses objectifs serait de pouvoir utiliser KLEE (http://klee.llvm.org/) sur cette IR.

    • [^] # Re: bitcode vs bytecode ?

      Posté par (page perso) . Évalué à  10 .

      pour une seule architecture "virtuelle"

      Sauf que le bytecode LLVM n'est pas indépendent de l'architechture.

      Tous les pointeurs sont déjà convertis en 32 ou en 64 bits. Et les trucs comme sizeof() sont déjà calculer.
      Sans même parler des instruction asm dans le code, ajoutons le fait que il y a l'étape du préprocesseur:

      #if LITTLE_ENDIAN
      
      

      Donc cet objectif me parraît impossible.

      les optims spécifiques à son CPU (i386/i686, Altivec, SSE, armhf/armel, etc.)

      Il y a effectivement beaucoup d'extensions de l'architecture x86_64 qui ne sont pas utilisées car le binaire doit être suffisamment générique.

      Cepandent, il faut relativiser: Quel est le gain réel que l'on peut espérer ici ? en sachant que la vectorisation en général est assez difficile à faire par le compilateur, et que les bibliothèques bas niveau profitent déjà de ces optimisations grâces au intrinsics et une vérification au runtime.

      Qu'en pensez-vous ?

      Je pense que il y airais peut-être un avantage à distribuer du bytecode LLVM pour permettre de faire du Just In Time. Et ré-optimiser les parties de code fréquemment utilisée avec plus d'inlining et de caching et ce genre de choses.

    • [^] # Re: bitcode vs bytecode ?

      Posté par . Évalué à  3 .

      Comme le disent Sylvestre et Gof, le bitcode LLVM n'est actuellement pas portable. Cependant, il peut servir de base. Il y a des travaux en cours pour définir une représentation intermédiaire, appelée SPIR, pour pouvoir distribuer des programmes OpenCL binaires. SPIR est très largement fondée sur LLVM. Et donc, je pense qu'il y aura un impact pour que le bitcode LLVM deviennent plus portable.

      Voir : http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-September/053125.html

  • # Rencontre LLVM à l'IRILL

    Posté par . Évalué à  2 .

    Très intéressants ces résumés ! Ça vaut le coup de garder un oeil sur certain d'entre eux.

    L'IRILL (Initiative de Recherche et Innovation sur le Logiciel Libre—http://www.irill.org/) avait organisé une rencontre très informelle autour de LLVM/Clang (prononcé 'klang' et non 'ci-lang') le 25 septembre dernier.

    Un commentaire pour :

    1. faire connaître l'IRILL qui propose des rencontres et présentation toujours intéressantes. L'une des dernières parlait d'"une introduction informelle aux méthodes formelles" (voir http://www.irill.org/blog/une-introduction-informelle-aux-methodes-formelles-par-prof.-roberto-bagnara-universite-de-parma) ;

    2. mettre le lien du résumé de cette rencontre qu'on a trouvée fort sympathique ;-) http://www.logilab.org/blogentry/106255 Entre autre: présentation LLVM/Clang, exemple du format '*.ll', du JIT avec Python, les projets autour de LLVM, des pizzas et des bières, des liens, etc.

    http://identi.ca/bejazzy/

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.