Journal GCC lent

Posté par  (site web personnel) .
Étiquettes : aucune
17
5
juil.
2009
Bonjour Journal,

Je vient ici me plaindre, et en profiter pour voir si vous aviez une idée pour corriger le tir.

Voici l'explication : J'ai un énorme logiciel (en C AINSI) qui génère une suite de librairie (une 10aine) statique (en mode release, les librairies tournent aux alentour de 40Mo), et une suite de binaire (environ 500), linké avec toute les librairies en statique.

Les librairies statique étant interdépendant, je suis obligé d'utiliser --start-proc et --end-proc du linker pour qu'il répète régulièrement les librairies (du genre -la -lb -la -lb -la -lb). L'autre solution est de passer du temps à chercher les dépendances et de le répéter manuellement.

Je compile l'ensemble sur de machine a peu prés équivalente. Une sous Windows avec MinGW et l'autre sous Linux avec GCC.

Et là c'est le malheur. Sous Windows la phase de compilation dure une 10aine d'heure avec MinGW (encore moins avec VisualStudio) et qui met plus de 48H sous Linux.

La phase la plus longue (et la plus consommatrice en mémoire) est la phase de link...

Comment se fait-il que Linux soit plut lent à Compiler et à Linker que Windows (alors que MinGW est normalement un GCC pour Windows). Est-ce que Windows gère mieux la mémoire ?

Qu'est il possible pour accélérer la phase de Linkage (passer les librairies en dynamique n'est pas possible, les binaires doivent être statique).

J'avoue ne pas savoir trop quoi penser. Je savais que GCC était lent, mais là c'est impressionnant. Je suis du coup un peu déçus de GCC (ou de Linux, je ne sais pas à qui donner la faute).

Est-qu'il y a des options à GCC pour dire de compiler plus rapidement ?
  • # forum?

    Posté par  . Évalué à -9.

    Les journaux sont destinés à des informations qui ne sont pas suffisamment intéressantes pour être validées en dépêche (sinon n'hésitez pas à proposer votre information en dépêche), qui sont sans rapport avec Linux ou le libre, ou simplement pour donner votre avis. Si vous désirez poser une question, merci d'utiliser les forums.
    • [^] # Re: forum?

      Posté par  . Évalué à 10.

      Franchement, sa question mérite bien un journal. Voir une dépèche dans la section humeur.

      Parce que GCC est une loutre bouffie et lente.

      J'aime ce journal qui dénonce.
      • [^] # Re: forum?

        Posté par  . Évalué à 0.

        > Parce que GCC est une loutre bouffie et lente.

        C'est crétin, car il n'a pas de problème avec GCC sous Windows...

        Tu veux un journal car tu crois que c'est l'occasion de dézinguer GCC.
        Son problème doit seulement être un bug.
  • # .

    Posté par  . Évalué à 10.

    Il faut d'abord déterminer l'origine du problème :
    - Est-ce que le CPU tourne à fond pendant la compil et le link ? Si c'est pas le cas, ça signifie que le proc attend des données. Dans ce cas il faut tester le disque. Un petit benchmark sur les deux machines peut te donner des infos intérressantes. Si il y'a un disque 5 fois plus rapide que l'autre, ça peut jouer fortement sur le temps total ( il n'y a pas si longtemps j'ai vu une base oracle sur un serveur linux plus que costaud se trainer. Il y avait une version pourrie de drivers raid qui faisait se trainer les I/O à 2 MO/s ! ).
    • [^] # Re: .

      Posté par  (site web personnel) . Évalué à 2.

      Oui enfin le monsieur dit qu'il y a une différence de 10 à 48h...il n'y a pas qu'un problème de machine a priori
      • [^] # Re: .

        Posté par  . Évalué à 6.

        non, il y a peut-être un problème de pilote... goto loop;
    • [^] # Re: .

      Posté par  (site web personnel) . Évalué à 2.

      C'est la consommation mémoire qui prend le plus pendant la phase de link : 1Go par ld. Les CPUs est presque à fond (variation entre 90% et 100% par CPU), mais je ferait un benchmark des disques pour comparer.
      • [^] # Re: .

        Posté par  (site web personnel) . Évalué à 3.

        Les versions du linker sont les mêmes ?

        "La première sécurité est la liberté"

      • [^] # Re: .

        Posté par  . Évalué à 8.

        En complément, il pourrait être intérêssant de voir ce que fait ton processeur pendant les différentes phases de ta compilation. Pour cela lances un vmstat 5 par exemple et regardes que tes 90%-100% de CPU sont majoritairement de la CPU utilisateur. Ensuite vérifie que tu n'a pas de swap pendant ta compilation (colonnes si et so).

        En gros (j'y vais au rouleau compresseur) il faut que tu aies un minimum de runqueue (première colonne du vmstat) soit une valeur max de 4 pour un dual core (et encore certains extrémistes diraient 2), ensuite il ne faut pas que tu aies de process bloqués (colonne b), que ta valeur de swap ne bouge pas (grosse perte de performance en général), ton free il doit déjà être à une valeur basse, le buffer normalement tu t'en fous, le cache pareil même si on pourrait en discuter. Ensuite le si/so je l'ai déjà dit, le reste on zap et vient la colonne "us" qui doit avoir dans ton cas la valeur la plus haute possible par rapport à ta consommation totale de CPU. La valeur "sys" faudrait qu'elle soit inférieure à 10% quand t'es à 100%, l'idle on passe et le "wa" disons qu'on oublie pour éviter de faire sursauter les ingés BDD ou de stockage :-) Mais si tu fais des lectures/écritures sur disque local alors là ça peut monter haut et dans ce cas il faudrait réfléchir à avoir physiquement une source différente de la cible (pareil si tu utilises des disques réseaux).

        Donc si t'as un profil différent, il est fort probable que les ressources du serveur soient mal utilisées pendant la compilation. Maintenant reste à savoir pourquoi.

        Sinon quand tu parles de 1Go, c'est 1Go de RSS (RES) ou de VSZ (VIRT) ? Peut être que tu dépasses la mémoire de la machine car j'ai lu plus bas qu'il y avait 2Go sur la machine, donc si t'as 2 ld, potentiellement tu exploses les ressources dispos et là tu dois avoir du swap (cf remarque plus haut).

        Cdt,
  • # Bibliothèques

    Posté par  . Évalué à 10.

    On ne dit pas "librairie" mais "bibliothèque".

    Sinon, je sais pas ce que c'est --start-proc, mais je connais un --start-group qui dit ça :
    --start-group archives --end-group
    The archives should be a list of archive files. They may be either
    explicit file names, or -l options.

    The specified archives are searched repeatedly until no new unde‐
    fined references are created. Normally, an archive is searched
    only once in the order that it is specified on the command line.
    If a symbol in that archive is needed to resolve an undefined sym‐
    bol referred to by an object in an archive that appears later on
    the command line, the linker would not be able to resolve that ref‐
    erence. By grouping the archives, they all be searched repeatedly
    until all possible references are resolved.

    Using this option has a significant performance cost. It is best
    to use it only when there are unavoidable circular references
    between two or more archives.
    • [^] # Re: Bibliothèques

      Posté par  (site web personnel) . Évalué à 2.

      Oui c'est bien --start-group
      Mais comme j'utilise la même option sous Windows et sous Linux, je ne crois pas que c'est cette partie qui change énormément (bien que je dois pouvoir y gagner si je trouve le bonne ordre).
      • [^] # Re: Bibliothèques

        Posté par  (site web personnel) . Évalué à 6.

        Tu trouves normal d'avoir des références circulaires entre lib ?!

        "La première sécurité est la liberté"

        • [^] # Re: Bibliothèques

          Posté par  (site web personnel) . Évalué à 2.

          Personnellement je ne trouve pas cela normal mais ce n'est pas moi qui ai écris ce logiciel et il est bien trop tard (vu sa taille) pour changer ce point (en tout cas ce n'est pas pour tout de suite).
          • [^] # Re: Bibliothèques

            Posté par  (site web personnel) . Évalué à 3.

            Et au lieu d'autoriser tous les ordres possible, cela n'est pas possible de trouver le "bon" ordre, cela doit limiter la taille des recherches pour le linker.

            "La première sécurité est la liberté"

            • [^] # Re: Bibliothèques

              Posté par  (site web personnel) . Évalué à 2.

              Y-a-t-il une bonne méthode pour trouver le bon ordre ?

              Le problème est qu'il y a 11 librairies qui peuvent dépendre l'une de l'autre, j'ai donc des milliers de ligne de undefined reference, et j'ai du mal à retrouver qui va avant quoi (et avec les dépendances circulaire, il faut parfois mettre deux fois la librairie sur la même ligne :( )

              Une fois compilé, est-il possible avec une commande, d'extraire l'ordre des dépendances des librairies statique ?
              • [^] # Re: Bibliothèques

                Posté par  (site web personnel) . Évalué à 2.

                Je ne n'en connais pas. Mais parfois l'essai/erreur permet d'aller assez vite.

                Les outils pour jouer avec les symboles sont souvent nm et objdump, je crois que cela fait parti des binutils.

                "La première sécurité est la liberté"

    • [^] # Re: Bibliothèques

      Posté par  . Évalué à 3.

      Oui, mais bilbio biblibo bibio, bibliothèque c'est chiant à écrire
      • [^] # Re: Bibliothèques

        Posté par  . Évalué à 1.

        Vu le reste du texte, je n’ai pas l’impression que ça lui fasse peur de faire des raccourcis (pourquoi pas « bib. » p.ex.) ou des fautes…
  • # gold

    Posté par  . Évalué à 8.

    Il y a existe un linker alternatif pour gcc qui s'appelle gold. Celui-ci est codé en c++ uniquement (ld se base sur des scripts), ce qui le rend plus rapide. L'utilisez-vous ?
    • [^] # Re: gold

      Posté par  . Évalué à 7.

      Celui-ci est codé en c++ uniquement [...] ce qui le rend plus rapide
      Je dois être un vieux con mais je ne vois pas de lien de cause à effet entre "codé en C++" et "le rend plus rapide" :-)
      • [^] # Re: gold

        Posté par  . Évalué à 10.

        Peut-être que dans l'autre sens ce serait moins trollesque ? Soit: ld utilise une myriade de scripts shell, ce qui le rend plus lent qu'une implémentation compilée tout en un.


        "At the moment gold has only one significant advantage over the
        existing linker: it is faster. On large C++ programs, I have measured
        it as running five times faster." http://sourceware.org/ml/binutils/2008-03/msg00162.html
        • [^] # Re: gold

          Posté par  (site web personnel) . Évalué à 6.

          juste pour pinailler: les scripts de ld ne sont pas des scripts shells, mais des scripts ld http://sourceware.org/binutils/docs-2.19/ld/Scripts.html
          • [^] # Re: gold

            Posté par  . Évalué à 2.

            Ah ok merci pour cette précision. Je n'étais pas sur, c'est pour cela que je ne l'avais pas mentionné dans mon premier commentaire. Le souvenir des autotools m'a induit dans l'erreur. Ceci explique pourquoi la vitesse mesurée n'est "que" de 5x.

            Maintenant, il s'avère que gold implémente aussi un support partiel des scripts ld. Si j'ai bien compris, sa plus grande vitesse est due au fait qu'il "hardcode" plus de choses, tout en se limitant au format elf.
    • [^] # Re: gold

      Posté par  (site web personnel) . Évalué à 2.

      C'est intéressant, je vais m'empresser de le tester pour voir le résultat.
      Merci de l'information
  • # ...

    Posté par  . Évalué à 10.


    Les librairies statique étant interdépendant, je suis obligé d'utiliser --start-proc et --end-proc du linker pour qu'il répète régulièrement les librairies (du genre -la -lb -la -lb -la -lb). L'autre solution est de passer du temps à chercher les dépendances et de le répéter manuellement.

    Ca te choques pas d'avoir des lib interdépendantes ?
    C'est quoi l'intérêt d'avoir plusieurs lib dans ce cas ?
    • [^] # Re: ...

      Posté par  (site web personnel) . Évalué à 10.

      Voici l'explication : J'ai un énorme logiciel (en C AINSI) qui génère une suite de librairie (une 10aine) statique (en mode release, les librairies tournent aux alentour de 40Mo), et une suite de binaire (environ 500), linké avec toute les librairies en statique.

      Est-ce qu'il ne faudrait pas commencer par là ? Ne pas compiler en statique, mais utiliser des bibliothèques dynamiques.
      • [^] # Re: ...

        Posté par  (site web personnel) . Évalué à 5.

        Comme dit dans le journal, il ne m'est pas possible de compiler en dynamique. Le but est de pouvoir livrer un exécutable et pas l'ensemble des exécutables en cas de correction (et on ne vas pas gérer les problématiques de compatibilité binaire entre les librairies et les exécutables). On veux également, en cas de bug, pouvoir livrer un exécutable sans impacter la configuration existante du reste du serveur chez le client (les autres exécutables, qui sont censé fonctionné). Bref quand ca marche on touche pas.

        Ensuite, j'ai une autre problématique, le logiciel est vieux de quelque milliers d'année (1992), il y a donc des choses qui ont été écrites d'une certaine manière (inter-dépendance des librairies), qui même si je trouve ça dommage, je ne vais pas pouvoir y faire grand chose vu la taille du bousin.
        • [^] # Re: ...

          Posté par  . Évalué à 3.

          Bah, en compilant en statique, si tu as une erreur dans une des bibliothèques de ton projet, tu dois recompiler et fournir des versions corrigées de tous tes exécutables.

          J'avoue avoir du mal à comprendre la logique.
        • [^] # Re: ...

          Posté par  (site web personnel) . Évalué à 10.

          et si tu merges tous les libs statiques interdependantes en une seule avec un ar bien placé ça ne linke pas plus vite ?
          • [^] # Re: ...

            Posté par  (site web personnel) . Évalué à 2.

            Bonne idée ça, pourquoi faire des lib pour ensuite tout rassembler ?

            "La première sécurité est la liberté"

  • # Tuyaux et compilation parallèle ?

    Posté par  (site web personnel) . Évalué à 8.

    En général pour optimiser la vitesse de compilation avec gcc on utilise :
    - l'option -pipe pour éviter d'écrire des fichiers intermédiaires
    - deux processus par cœur de processeur pour optimiser la latence.
    (J'imagine que même les compilateurs sous widows savent faire ce genre de chose.) Est-ce que ces deux astuces sont bien utilisés de manière équivalentes dans les compilation comparée ? Aussi, est-ce que les niveaux d'optimisation sont comparables ?

    « IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace

    • [^] # Re: Tuyaux et compilation parallèle ?

      Posté par  . Évalué à 8.

      - l'option -pipe pour éviter d'écrire des fichiers intermédiaires
      Ca dépend de l'espace mémoire nécessaire à la compilation. C'est bien beau de loger les intermédiaire de compilation en mémoire, mais si c'est pour que la compilation en elle même se fasse dans le swap c'est pas super rentable.

      deux processus par cœur de processeur pour optimiser la latence.
      Houlà ! C'est bien d'avoir un processus de plus que le nombre de CPU pour avoir toujours une suite compilation prête en mémoire quand un processus fini. Eventuellement si on a beaucoup de coeur ou une très grosses suite de petites compils on peut en mettre deux voire trois de plus que le nombre de CPU. Mais je doute fort que mettre 8 processus de compil sur un quadricore soit rentable (toujours pour des questions d'occupation mémoire). En tout cas ici sur mon Q6600 je vais plus vite avec 5 ou 6 process (5 pour le C++, 6 pour le C Ansi) qu'avec 8.
      • [^] # Re: Tuyaux et compilation parallèle ?

        Posté par  (site web personnel) . Évalué à 1.

        Je vais regarder si je n'utilise pas l'option pipe, mais je crois que je l'utilise déjà. Cette option ne fonctionne que pour la compilation ou également pour la phase de linkage ?

        Pour la compilation multi-cpu, je suis à trois process par CPU (make -j3) sur les deux machines (des dual core).
        Je pourrais monté à plus pendant la phase de compilation (CC) mais je suis limité en mémoire pendant la phase de link (LD), 3 processus est alors le maximum.
      • [^] # Re: Tuyaux et compilation parallèle ?

        Posté par  (site web personnel) . Évalué à 2.

        Si tu es en NFS vu la lenteur des IOs, je faisais souvent des "make -j".

        "La première sécurité est la liberté"

  • # option d'optimisation ?

    Posté par  . Évalué à 2.

    D'après la page de man de gcc les options d'optimisation (-O1, -O2…) prennent plus de temps…

    Une compilation en -O0 améliorerais peut-être la vitesse de compilation, si c'est ça qui t'intéresse le plus ?
  • # options

    Posté par  (site web personnel) . Évalué à 6.

    Il y a des options de GCC "buggées".
    Tu peut tout à fait faire ta liste d'options de compilation (-fno-fast-math -o3,-do-what-I-mean…) et reposer ta question sur la ML de gcc en indiquant cette liste et la version de gcc que tu utilises.
    Il y a des cas pathologiques où gcc pédale dans la semoule, surtout avec du code C généré (car tu peux avoir des fonctions de milliers de lignes).
    Regarde aussi si la compilation swappe à mort.

    Dans tous les cas, pour gagner du temps, utilise distcc et ccache. Tu pourras passer de 40 heures à 10 heures la prochaine fois, ou de 10 à quatre, qui sait.
    • [^] # Re: options

      Posté par  (site web personnel) . Évalué à 2.

      Ce serait pas de chance, le problème est le même avec gcc 2.95, gcc 3.xx, et gcc 4.xx.

      Mais j'enverrai un mail à la mailing list si jamais je ne peux pas améliorer plus les perfs avec gold ou -pipe.
  • # Machines "à peu près" équivalentes

    Posté par  (Mastodon) . Évalué à 3.

    Question con, mais niveau RAM, t'as autant de RAM sur l'une et sur l'autre ?

    Parce que la compilation bouffe énormément de RAM, ne serait-ce que pour le cache des fichiers utilisés.

    En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

  • # Quel linker ?

    Posté par  (site web personnel) . Évalué à 6.

    Si c'est la phase de link qui est lente, ce n'est pas tellement un problème de gcc. Il faut voir que ce qu'on appelle GCC est en fait un compilateur (le binaire est cc1) et un « driver » (le fameux binaire gcc) qui appelle dans l'ordre le compilateur, l'assembleur, le linker. L'assembleur et le linker sont des binaires qui ne font pas partie de GCC.

    Sous Linux, a priori, c'est GNU ld qui sera appelé. Mais est-ce le cas sous Windows (gcc --verbose te le dira) ? Je ne serai pas surpris que ce soit simplement un autre linker, plus rapide, qui soit applé.
    • [^] # Re: Quel linker ?

      Posté par  (site web personnel) . Évalué à 3.

      C:\Users\uvandenhekke>Configured with: ../gcc-3.4.5-20060117-3/configure --with-gcc --with-gnu-ld --with-gnu-as --host=mingw32 --target=mingw32 --prefix=/mingw --enable-threads --disable-nls --enable-languages=c,c++,f77,ada,objc,java --disable-win32-registry --disable-shared --enable-sjlj-exceptions --enable-libgcj --disable-java-awt --without-x --enable-java-gc=boehm --disable-libgcj-debug --enable-interpreter --enable-hash-synchronization --enable-libstdcxx-debug
      Thread model: win32
      gcc version 3.4.5 (mingw-vista special r3)

      D'après ce que je crois lire, c'est ld aussi, mais peut-être un ld made in mingw.
  • # Ranlib?

    Posté par  . Évalué à 4.

    Je suppose que les libs statiques sont créées avec la commande 'ar'.
    Vérifie qu'elles possèdent un index des symboles avec

    # nm -s libXXX.a | grep "Archive index"

    Tu peux recréer l'index avec la commande ranlib:

    # ranlib libXXX.a

    Sur les gros projets, la présence des informations de debug peut aussi être une cause de lenteur lors du link. Essaye donc de retirer -g où c'est possible.
  • # Version de gcc et cygwin ?

    Posté par  (site web personnel) . Évalué à 1.

    Une autre question con ... c'est la même base de gcc pour les compilateurs ?
    Car c'est connu que le passage du 2.9x au 3.x s'est accompagné d'une grosse baisse de performance.

    Par contre pour ld, j'en sais rien.
    • [^] # Re: Version de gcc et cygwin ?

      Posté par  (site web personnel) . Évalué à 1.

      La version sous Windows, et la version 3.x et sous Linux la version 4.x mais j'avais déjà fait des tests avant avec d'autres version pour voir si cela changé quelque chose.
  • # Merci à tous pour toutes les informations

    Posté par  (site web personnel) . Évalué à 6.

    Merci à tous pour toutes ces informations, je pense qu'elle pourront être utile à d'autres.
    Voilà ce que j'ai changé :
    - utilisation de l'option -pipe
    - utilisation du linker gold

    Je suis passé de plus de 40h à 75m ... La phase de link sur les exe (qui sont en faite au nombre de 800) passe de quelque minute par exe à quelque seconde (voir centième de seconde).

    Je pense que c'est surtout grâce à gold. J'espère qu'il est maintenu et qu'il sera améliorer, car c'est vraiment un très bon linker (grâce à lui la compilation est plus rapide que celle avec VisualStudio sous Windows).

    Merci

Suivre le flux des commentaires

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