Forum Programmation.autre [résolu] math exp() : performance 32-bit vs 64-bit

Posté par . Licence CC by-sa
Tags :
3
24
juin
2015

Bonjour,

Est-ce que quelqu'un saurait expliquer la difference de performance entre un build 32-bit et 64-bit de exp()?

Code:

#include <math.h>

#define SIZE (10000)

int main()
    {
        for (int i = 0; i < SIZE; ++i)
            for (int j = 0; j < SIZE; ++j)
                exp(i + j);

        return 0;
    }

Compilation (O3 ne change rien, j'utilise juste O0 pour eviter que le code ne soit completement saute):

$ g++ -o /tmp/test_exp_64 test_exp.cpp -Wall -O0
$ g++ -o /tmp/test_exp_32 test_exp.cpp -Wall -O0 -m32

$ time /tmp/test_exp_32; time /tmp/test_exp_64
    real    0m24.235s
    user    0m24.192s
    sys     0m0.004s

    real    0m2.764s
    user    0m2.748s
    sys     0m0.002s

En regardant l'assembleur genere on a - evidemment - des implementations tres differentes, mais je suis surpris par la difference de performance.

Comme je ne connais pas grand-chose au calcul numerique, est-ce que quelqu'un pourrait m'eclairer, et notamment donner une piste pour ameliorer la performance sur 32-bit ?

Merci d'avance !

  • # j'ai pas le code assembleur sous les yeux

    Posté par . Évalué à 4.

    mais il est probable qu'il y ait des instructions spécifique au x86_64 permettant de faire quelques optimisations, alors que ton code 32bit a des chance d'être compilé pour du 386 ou 586, essaye d'activer manuellement les options pour ces archis

    typiquement
    -mtune=i686 ou voir
    -march=i686 si jamais ça ne risque pas de tourner en dessous ou -march=pentium4 ou -march=athlon-4

    mais bon un man gcc à la section Intel 386 and AMD x86-64 Options pour voir les archi possibles ou un cat /proc/cpuinfo | grep flags pour voir quels fonctionnalités sont dipos sur le proc en question. Attention cependant, -mtune permettra de tourner partout, c'est juste des optimisations spécifiques, -march va utiliser des instructions qui ne sont pas dispo sur tous les processeurs x86.
    typiquement sur les proc pas antédéluviens -mfpmath=sse

    Bref ça dépends de l'archi d'exécution. Les archis 64bits sont plus récente et ont forcément des jeux d'instruction qu'on est pas certain de retrouver sur les 32bits ce qui fait que par défaut plus d'options sont activées.

    Il ne faut pas décorner les boeufs avant d'avoir semé le vent

  • # Registres

    Posté par . Évalué à 1.

    Si ma mémoire est bonne, en 64-bits tu as (évidemment) accès à des registres plus grand, mais aussi plus nombreux.

    Les 64-bits te permettent ainsi de faire des calculs numériques plus précis (et donc potentiellement d'en faire moins), tout en bénéficiant d'une meilleure localité des données du fait de la présence de plus de registres.

    Comment améliorer les performances en 32-bits ? Passer en 64-bits !

    Sinon, tu peux toujours essayer de te recompiler la lib C en O3 (j'imagine qu'elle est compilée en O2), mais il est assez probable que le gain soit ridicule.

  • # Libc différentes

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

    Je pense que la principale différence ne vienne pas forcément du compilateur, mais de la bibliothèque C à laquelle ton programme est liée.

    La version 32 bits (resp 64 bits) de ton programme est liée à la version 32 (resp 64) bits de la lib C. Du coup, il s'agit de 2 lib différentes. Et à moins d'avoir toi même compilé la libc, tu peux avoir 2 implémentations différentes, 2 versions différentes, etc… Ce n'est pas forcément la même lib compilé une fois en 32 bits et l'autre fois en 64 bits.

    Et même s'il s'agit de la même libc (comprendre : issu de la même source), il faudrait dans ce cas vérifier que le choix 32/64 bits ne modifie pas l'implémentation de exp sous jacente (les morceaux de code inclu dans des #ifdef sont courants dans la libc).

    • [^] # Re: Libc différentes

      Posté par . Évalué à 2.

      J'aurais avancé peu ou prou la même chose. Si tu as un kernel x64 (ce qui est le cas puisque tu executes du code x64), il y a peut-être des options de retro compatibilité, ce qui nous amènerait au fait que le x64 execute mal le 32bits, et qu'il vaut mieux privilégier l'architecture native :)

      J'imagine que faire tourner ton code sur un live usb amd64 vs i686 doit permettre d'avoir une idée plus précise.

    • [^] # Re: Libc différentes

      Posté par . Évalué à 2.

      Merci, mais c'est évident que les versions 32-bit et 64-bit sont linké avec des libm différentes (/lib vs /lib64).
      Ce que j'aimerais savoir c'est pourquoi la version 32-bit est tellement lente.

      • [^] # Re: Libc différentes

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

        Et c'est exactement ce que je te disais. Comme il s'agit de bibliothèque différente, tu n'es même pas sur que l'implémentation soit la même sur une architecture et sur une autre. Tu peux compiler ton programme avec -O0, cela n'influencera que ton programme et pas les libs avec lesquelles il est lié.

        Et à mon avis, la différence de performance que tu as est lié à l'implémentation de exp(), pas à son appel en lui-même.

        • [^] # Re: Libc différentes

          Posté par . Évalué à 1.

          Non mais en tourne en rond là, c'est évident, ce qui m'intéresse c'est pourquoi la version 32 bit est si lente (je compile uniquement en -O0 pour que gcc n'optimise pas complètement la boucle, étant donné que je n'utilise pas les valeurs retournées par exp() et que c'est une fonction pure).

          • [^] # Re: Libc différentes

            Posté par . Évalué à 2.

            Ben, on t'a répondu…

            Regarde les implémentations, c'est pas les mêmes. Si tu veux que quelqu'un le fasse pour toi, je comprend, c'est pas évident de s'y retrouver dans la glibc, demande, mais poser encore et encore la même question n'est pas une bonne stratégie.

            Tu peux empêcher gcc de faire l'optimisation en faisant un truc à la con avec le résultat de exp, genre l'accumuler dans une variable et le retourner à la fin. Mais ça changera rien parce que la lib n'est pas recompilée, tu aura toujours une différence énorme.

            Please do not feed the trolls

            • [^] # Re: Libc différentes

              Posté par . Évalué à 1.

              Comme je l'ai dit il est évident que les implémentations sont différentes et que la différence vient de là, je voulais savoir si quelqu'un avait une idée plus précise du pourquoi une telle différence de performance (voir ci-dessous, c'est probablement parce qu'on atteint un range error sur 32-bit). J'ai déjà jeté un oeil à l'assembleur, mais je n'avais rien vu d'évident (mis à part que les implémentations n'ont rien à voir).

              D'ailleurs, en y repensant, l'appel à la fonction ne peut pas être optimisé, parce qu'elle n'est pas pure (elle peut changer errno).

              • [^] # Re: Libc différentes

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

                Comme la dis Zylabon, "Ben, on t'a répondu…"

                Maintenant, si tu veux qu'on aille plus loin, donne nous le code assembleur de chacune des implémentations et on en reparle. Mais ne t'attends pas à ce que l'on fasse tout le boulot pour toi ;)

  • # overflow

    Posté par . Évalué à 9.

    C'est visiblement lié à un overflow/domain représentable par un double sur 32-bit.

    En changeant l'appel à exp() en :
    exp((i + j) / (double)SIZE);

    Les performances sont comparables.

Suivre le flux des commentaires

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