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 :

Instruction SIMD, véritable gain ou chimère


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Novembre 2002
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2002
    Messages : 31
    Points : 29
    Points
    29
    Par défaut Instruction SIMD, véritable gain ou chimère
    Voilà je m'explique ..;

    Je m'acharne ces derniers temps à gagner des performances en utilisant les instructions SIMD;

    Je travaille sur des structures assez simple et au final, on ne peut pas dire que le gain que j'obtienne soit transcendant ...
    Dans tous les cas, il est loin des x4 indiqués dans la documention Intel;

    Je réalise mes comparaisons entre une version classique et une version modifiée pour utiliser manuellement les instructions SIMD;
    je travaille sous Visual Studio 2005 et j'utilise son compilateur;
    Dans les deux cas, je compile mon code en activant les options de compilations pour accélérer la vitesse du code.

    Pour le moment, je m'explique mes faibles gains de performances par deux raisons :
    - Mon utilisation manuelle des instructions SIMD n'est guère plus performante que celle mise en place automatiquement par le compilateur
    - Le fait que j'utilise des formats spéciaux à la place des formats classiques (int, float, ... ) empeche le compilateur de mettre en place certaines optimisations et donc ... je perds des performances;


    Enfin, voilà mes problèmes, j'aurais voulu savoir si certains ont déjà rencontrés mes problèmes ou si il y avait une autre explication à mon faible gain de performance;

    Merci d'avance pour vos remarques

    ++ Beleys

    (Il reste la solution que je me suis loupé quelque part ..; mais à force d'être dessus, je commence à douter)

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    116
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 116
    Points : 149
    Points
    149
    Par défaut
    Pourquoi veux-tu utiliser simd à la place des optims du compilo ?
    l'idéal serais de combiner les deux non ?

    Et au niveau algo, pas moyen d'optimiser ?
    Paralléliser ?

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Novembre 2002
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2002
    Messages : 31
    Points : 29
    Points
    29
    Par défaut
    Je ne veux pas remplacer l'une par l'autre.
    Mais plutot comprendre pourquoi la version dans laquelle j'ai implémenté ses instructions manuellement n'est guere plus rapide que la version "classique" ...
    alors que je devrais atteindre des coefs de type légèrement inférieur à 8 pour des types comme le short et légérement inférieur à 4 pour des flottant ...

    En gros j'aurais voulu voir si une implémentation manuelle pouvait être plus efficace qu'une implémentation automatique ...

    Après pour ce qui est de la parallélisation, je voudrais m'en passer dans un premier temps.

    ++ Beleys

  4. #4
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Avec les intrinsincs, le compilateur ne devrait pas voir de différence avec un appel de fonction ou une instruction classique et peut optimiser comme d'habitude. Si tes données ne sont pas alignées, tu vas perdre de la vitesse, c'est peut-être ça ?

  5. #5
    Inactif  
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    743
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Points : 460
    Points
    460
    Par défaut
    J'obtiens bien des gains proches des gains théoriques.
    Du genre x3.8 ou x1.9 pour la somme de 2 grands vecteurs de floats ou de doubles.

    Je crois que tu fais trop confiance au compilo.
    Pour utiliser les instructions SIMD, soit il faut programmer en assembleur, soit tu utilises les fonctions intrinsic. Je te conseils les fonctions intrinsic...

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Novembre 2002
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2002
    Messages : 31
    Points : 29
    Points
    29
    Par défaut
    Juste afin de vérifier que je ne fais pas fausse route:

    Voilà le corps des deux fonctions que je compare,
    dans les deux cas, il s'agit de l'addition de matrice (qui comme elle sont stockées sous forme de vecteur, reviens à faire une addition de vecteur ...)

    Fonction addition classique :
    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
     
    template <class T>
    Matrix<T> OpeCpu<T>::addition(Matrix<T> & mat1, Matrix<T> & mat2)
    {
      int m1X, m1Y, m2X, m2Y;
     
      m1X = mat1.LireNx();
      m1Y = mat1.LireNy();
     
      m2X = mat2.LireNx();
      m2Y = mat2.LireNy();
     
     
      Matrix<T> resMat(m1X,m1Y);
      if (m1X == m2X && m1Y == m2Y) {
        for (int i = 0; i < m1X*m1Y  ; i++){
             resMat.mat[i] = mat1.mat[i]+ mat2.mat[i];
        }
      }
      return resMat;
    }

    Fonction addition SSE (en théorie ..)
    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    #include <dvec.h>
    #include <emmintrin.h>
     
    template < >
    Matrix<short> OpeSSE<short>::addition(Matrix<short> & mat1, Matrix<short> & mat2)
    {
      Matrix<short> resMat(mat1._tx,mat1._ty);
      int m1X, m1Y, m2X, m2Y;
     
      m1X = mat1.LireNx();
      m1Y = mat1.LireNy();
     
      m2X = mat2.LireNx();
      m2Y = mat2.LireNy();
     
      if (m1X == m2X && m1Y == m2Y) {
        __m128i *pr;
        __m128i const *p0;
        __m128i const *p1;
     
        pr = (__m128i *) &resMat.mat[0];
        p0 = (__m128i *) &mat1.mat[0];
        p1 = (__m128i *) &mat2.mat[0];
        int i;
        for ( i = 0; i < m1X*m1Y-7; ++p0,++p1, i+=8, ++pr){
          Is16vec8 mmx0(_mm_loadu_si128(p0));
          Is16vec8 mmx1(_mm_loadu_si128(p1));
          Is16vec8 mmxr= mmx0 + mmx1;
          _mm_storeu_si128(pr,mmxr);
        }
        for (i; i <m1X*m1Y; ++i){
          resMat.mat[i] = mat1.mat[i] + mat2.mat[i];
        }
      }
      return resMat;
    }
    Point important :
    - J'utilise des vecteurs non alignés (impératif technique)
    - Apres c'est du tout simple


    Performances obtenues:

    Addition de 2 matrices 10 000 x 10 000
    Processeur : Intel Xeon 2.49 Ghz
    3.25 Go de Ram

    Temps classique = 0.766
    Temps SSE = 0.359
    Gain = 2.13

    Si quelqu'un à une explication, je suis preneur ...

    Meci d'avance

    ++ Beleys

  7. #7
    Membre éclairé

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Points : 858
    Points
    858
    Par défaut
    Citation Envoyé par beleys Voir le message
    Addition de 2 matrices 10 000 x 10 000
    Avec autant de données (près de 400 Mo) le processeur passe sont temps à lire et écrire les données en RAM, l'addition en elle même devient négligeable. C'est donc assez étonnant que tu ais un quelconque gain en parallélisant. En théorie tu gagnerai plus en pré-chargeant les données (instruction prefetch ...).

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Novembre 2002
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2002
    Messages : 31
    Points : 29
    Points
    29
    Par défaut
    Je conserve ce gain mm avec des matrices de tailles moins grandes et j'ai aussi essayé d'itérer sur un nombre successif d'addition de plus petite taille ...

    Le gain reste relativement constant (mais quasi nulle)

    pour une 3000 x 3000 CPU 0.078 SSE 0.031
    pour une 2000 x 2000 CPU 0.031 SSE : 0.015

    Pour des taille plus petites, les temps annoncés ne sont plus fiables
    (déjà que même pour les temps que j'affiche ici cela ne vaut pas grand chose)

    Je m'en vais toutefois regardé ses fonctions de préchargement

    Merci du conseil

    ++ Beleys

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    116
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 116
    Points : 149
    Points
    149
    Par défaut
    Et si tu fais 1000 fois une addition de 3000*5000 ?
    Tu devrais avoir des résultats probablement plus significatifs ?

  10. #10
    Inactif  
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    743
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Points : 460
    Points
    460
    Par défaut
    Les instructions de pré-chargement n'apportent en pratique pas souvent de gain. En outre:
    - mon compilo (Intel Compiler) ne les place pas aux endroits les plus judicieux, les autres compilos ne font probablement pas beaucoup mieux, ce qui imposerait de programmer en assembleur.
    - dans le cas de mémoire contigüe les Pentium4 pré-chargent automatiquement les pages de mémoire, ce qui rend les instructions de pré-chargement en théorie plutôt contre productive.

    Le problème de Beyles vient plutôt:
    - des instructions de lectures non alignée. D'après mes benchs, ces instructions ruinent les gains potentiels des instructions SIMD, elles sont donc à proscrire et à n'utiliser qu'exceptionnellement. Je vois pas pourquoi on s'imposerait d'utiliser des allocations mémoires non alignées avec des instructions SSE. Si Beyles veut se l'imposer quand même, il n'a qu'à faire une petite boucle au départ jusqu'à obtenir des données alignées, mais même ça n'est pas LA solution
    - une mauvaise compilation de son compilateur. Il faut toujours vérifier le code généré avec des instructions SIMD, avant de mettre en doute les gains des instructions SIMD... A titre d'exemple voilà la boucle que j'obtiens pour la somme de 2 vecteurs stockée dans un 3ème.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    00401144  movaps      xmm0,xmmword ptr [edx] 
    00401147  addps       xmm0,xmmword ptr [eax] 
    0040114A  movaps      xmmword ptr [esi],xmm0 
    0040114D  add         ecx,0FFFFFFFFh 
    00401150  add         edx,10h 
    00401153  add         eax,10h 
    00401156  add         esi,10h 
    00401159  test        ecx,ecx 
    0040115B  jg          main+144h (401144h)

Discussions similaires

  1. Optimiser une boucle à l'aide d'instructions simd
    Par moomba dans le forum Débuter
    Réponses: 5
    Dernier message: 10/11/2012, 19h31
  2. SIMD SEE instructions
    Par nasboy3d dans le forum C++
    Réponses: 4
    Dernier message: 04/08/2010, 13h40
  3. Instruction SIMD, classe F32vec4
    Par beleys dans le forum C++
    Réponses: 2
    Dernier message: 26/05/2008, 09h36
  4. [Packages]Un véritable gain de performance ?
    Par New dans le forum Oracle
    Réponses: 7
    Dernier message: 28/10/2005, 14h19
  5. [Crystal Report][VB6] instruction PrintReport
    Par yyyeeeaaahhh dans le forum SDK
    Réponses: 4
    Dernier message: 29/07/2002, 14h58

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