IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Ralentissement en 64 bits


Sujet :

C++

  1. #1
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 43
    Points : 70
    Points
    70
    Par défaut Ralentissement en 64 bits
    Bonjour,

    Je viens appeler à votre aide car je constate un ralentissement assez significatif sur un même code selon que je l'exécute sur des entiers 32 bits ou 64 bits (et cela sur une machine qui est en 64 bits).

    Le code est donné ci-après. Il est inspiré d'un code réel mais a été simplifié pour faciliter la lecture (quoi que…). Du coup ce qu'il calcule maintenant n'a absolument aucun intérêt .
    Le tableau array contient 30 000 000 entiers aléatoires. Le tableau range définit seulement un intervalle à parcourir dans le tableau array (toujours de la même longueur dans ce cas-là).

    J'effectue un certain nombre de requêtes sur mon tableau (1 000 000) et je calcule la somme des entiers rencontrés, histoire de faire quelque chose…

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    void test() {
      uint nb = 300000000;
      uint nb_queries = 1000000;
      ullong sum = 0;
      uint *array = new uint[nb];
      uint range_size = 10;
      uint *range = new uint[nb/range_size+1];
     
      srand(1);
     
      for (uint i=0; i < nb; i++) {
        array[i] = rand() % 1000;
        if (i % range_size == 0) {
          range[i/range_size] = i;
        }
      }
      range[nb/range_size] = nb;
     
      for (uint i=0; i < nb_queries; i++) {
        uint start = rand() % nb;
        for (uint j = range[start / range_size]+1; j < range[start / range_size + 1]; j++) {
          if (array[j-1] % 25 != array[j] % 25)
            sum += array[j];
        }
      }
    }
    Le type uint est défini soit comme un u_int32_t soit comme un u_int64_t selon l'exécution que je veux lancer.
    Je mesure le temps que met la boucle externe (sur la variable i) à s'exécuter en utilisant gettimeofday.
    À la fin j'affiche le temps par requête (c-à-d. le temps de la boucle externe divisé par le nombre de requêtes).

    Le programme est compilé avec les options -Wall -pedantic -O3

    J'ai lancé 10 fois le programme, et voici les résultats en 64 bits:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    0.538002 us     (64-bit)
    0.534345 us     (64-bit)
    0.534997 us     (64-bit)
    0.535865 us     (64-bit)
    0.538192 us     (64-bit)
    0.535768 us     (64-bit)
    0.542856 us     (64-bit)
    0.53733 us      (64-bit)
    0.540097 us     (64-bit)
    0.534318 us     (64-bit)
    Soit un temps moyen de 0,537177 µs par requête.

    Puis en 32 bits :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    0.41998 us      (32-bit)
    0.420473 us     (32-bit)
    0.414799 us     (32-bit)
    0.411799 us     (32-bit)
    0.411982 us     (32-bit)
    0.415471 us     (32-bit)
    0.418673 us     (32-bit)
    0.412244 us     (32-bit)
    0.414136 us     (32-bit)
    0.416502 us     (32-bit)
    Soit un temps moyen de 0,415606 µs par requête.

    La version 64 bits est donc 30% plus lente que la version 32 bits. Je retire alors le
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (array[j-1] % 25 != array[j] % 25)
    et je relance les expériences dans les mêmes conditions.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    0.283565 us     (64-bit)
    0.29084 us      (64-bit)
    0.270837 us     (64-bit)
    0.263805 us     (64-bit)
    0.252101 us     (64-bit)
    0.283732 us     (64-bit)
    0.261196 us     (64-bit)
    0.274833 us     (64-bit)
    0.277358 us     (64-bit)
    0.26613 us      (64-bit)
    Soit un temps moyen de 0,27244 µs par requête.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    0.256369 us     (32-bit)
    0.251514 us     (32-bit)
    0.247946 us     (32-bit)
    0.250032 us     (32-bit)
    0.282004 us     (32-bit)
    0.273818 us     (32-bit)
    0.254479 us     (32-bit)
    0.248506 us     (32-bit)
    0.276108 us     (32-bit)
    0.258223 us     (32-bit)
    Soit un temps moyen de 0,2599 µs par requête.

    Maintenant le code 64 bits est environ 5% plus lent que la version 32 bits.

    Comment s'explique cette différence entre les versions 32 et 64 bits ? Comment puis-je y remédier ?

    Merci d'avance

  2. #2
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 942
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 942
    Points : 5 654
    Points
    5 654
    Par défaut
    Mua,

    Sur quel système (32 ou 64) ?

    Compilé 32 ou 64 (le code n'est pas du tout le même pour travailler avec des variables 64 bits) ?
    Si les cons volaient, il ferait nuit à midi.

  3. #3
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 43
    Points : 70
    Points
    70
    Par défaut
    Arrgh… j'arrive toujours à oublier des choses !

    C'est sur un système 64 bits, bien-sûr, et compilé en 64 bits. Voici ce que donne la commande file sur l'exécutable généré.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped

  4. #4
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 11
    Points : 9
    Points
    9
    Par défaut
    30 000 000 * 4 / (1024 * 1024) = 114,44 Mo
    30 000 000 * 8 / (1024 * 1024) = 228,88 Mo

    Pour moi la différance réside entre le temps nécessaire de transférer 114.44 Mo par rapport à 228.88 Mo entre les RAM et le CPU. Il est n’est pas double car le compilateur optimise les opérations nécessaire aux calcule. De plus le système est 64 bits permettant ainsi d’optimiser au mieux le transfert. Les performances serait pire sur un système de 32 bites.

    Je viens de remarquer que j’ai mal regardé ton code. T’as 2 tableaux et 2 boucles.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    uint nb = 300000000;
      uint nb_queries = 1000000;
      ullong sum = 0;
      uint *array = new uint[nb];
      uint range_size = 10;
      uint *range = new uint[nb/range_size+1];
    Donc "array" pese:
    300 000 000 * 4 / (1024 * 1024 * 1024) = 1144,4 Mo en 32 bits
    300 000 000 * 8 / (1024 * 1024 * 1024) = 2288,8 Mo en 64 bits

    Plus "range" qui pese
    30 000 000 * 4 / (1024 * 1024) = 114,44 Mo en 32 bits
    30 000 000 * 8 / (1024 * 1024) = 228,88 Mo en 64 bits

    Dans la première boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for (uint i=0; i < nb; i++) {
        array[i] = rand() % 1000;
        if (i % range_size == 0) {
          range[i/range_size] = i;
        }
      }
    Le transfert de mémoire (entre RAM et CPU) vaut +- :
    1144,4 Mo + 114,44 Mo en 32 bits
    2288,8 Mo + 228,88 Mo en 64 bits


    Dans la deuxième boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for (uint i=0; i < nb_queries; i++) {
        uint start = rand() % nb;
        for (uint j = range[start / range_size]+1; j < range[start / range_size + 1]; j++) {
          if (array[j-1] % 25 != array[j] % 25)
            sum += array[j];
        }
      }
    Le transfert de mémoire (entre RAM et CPU) vaut au moins +- :
    1000 000 * 10 * 2 * 4 / (1024 * 1024) = 76,29 Mo en 32 bits
    1000 000 * 10 * 2 * 4 / (1024 * 1024) = 152,58 Mo en 64 bits

    Ce qui fait au total:
    1335.13 Mo en 32 bits
    2670.26 Mo en 64 bits

    En conséquence l’augmentation du temps devrait surement s’expliquer par l’augmentation de la quantité de la mémoire à transférer entre les RAM et le CPU (Heureusement le compilateur optimise le code).

  5. #5
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 43
    Points : 70
    Points
    70
    Par défaut
    J'ai pensé aussi à celà mais ça n'explique pas la grosse différence selon qu'il y a le if ou non (la quantité de données transférée reste la même).
    Je ne parle pas de la différence entre la version « avec if » et « sans if », c'est normal, les optimisations sont meilleures s'il n'y a pas de branchement. Mais je parle de la différence relative entre les versions 32 ou 64 bits selon qu'il y ait le if ou non.

Discussions similaires

  1. Comparaison d'un registre 8 bits avec une variable 32 bits
    Par tupperware dans le forum x86 32-bits / 64-bits
    Réponses: 3
    Dernier message: 15/10/2002, 10h25
  2. Main icon (16 bits)
    Par DR dans le forum C++Builder
    Réponses: 2
    Dernier message: 02/09/2002, 08h23
  3. Cherche l'algo crc 16 bits
    Par icepower dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 21/08/2002, 13h27
  4. Debugger 16-32 bits
    Par Mat dans le forum Assembleur
    Réponses: 4
    Dernier message: 28/06/2002, 11h34
  5. Lire 1 bit d'un fichier en C
    Par Anonymous dans le forum C
    Réponses: 3
    Dernier message: 23/05/2002, 18h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo