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

Boost C++ Discussion :

boost::ublas étrangement lent.


Sujet :

Boost C++

  1. #1
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut boost::ublas étrangement lent.
    Bonjour,

    Je suis en train actuellement de coder une classe vectoriel en utilisant les expressions templates, et histoire de voir ce que ça donnait, j'ai fait quelques comparaisons avec une classe template mais sans expression template (une classe codé plus naïvement on va dire), et avec boost::ublas, parceque j'étais curieux de voir ce que ça allait donner.

    Alors que je m'attendais à ce que ublas ridiculise carrément ma classe, ça a été tout le contraire, et je pense qu'il y a un problème quelque part.

    Mon compilo est la dernière version de GCC (3.4.2 je crois), et l'IDE Code::Blocks. Je compile le programme en mode release, avec les options Optimize Fully (for speed) et Expensive Optimizations et les optimisations de l'architecture CPU Athlon XP d'activées.

    Pour mesurer, j'utilise QueryPerformanceCounter et QueryPerformanceFrequency. Je fais 10 séries de cent mille du calcul v1 = v2 + v3 + v1, et voici ce que j'obtient comme performance :

    boost : 0.888361
    moi : 0.0229465
    classe "naïve" : 0.10339

    En relançant plusieurs fois l'applicaiton j'obtient en gros les mêmes résultats donc il ne doit pas trop y avoir de mises en cache, et sinon l'execution confirme les résultats, lorsqu'il fait les calculs de boost, on voit que c'est plus beaucoup plus lent. J'ai aussi vérifié que les résultats soient identiques à la fin.

    Voici comment j'utilise boost::ublas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    boost::numeric::ublas::vector <double> A (3);
       A(1) = 1.0, A(2) = 1.0, A(0) = 1.0;
       boost::numeric::ublas::vector <double> B (3);
       B(1) = 2.0, B(2) = 2.0, B(0) = 2.0;
       boost::numeric::ublas::vector <double> C (3);
       C(1) = 3.0, C(2) = 3.0, C(0) = 3.0;
     
       for (size_t i = 0 ; i != 10 ; ++i)
       {
          for (size_t j = 0 ; j != 100000 ; ++j)
          {
             A = C+B+A;
          }
       }
    Donc si quelqu'un s'en serait déjà servi, où si ce n'est pas tellement dans ce genre d'applications que boost::ublas est efficace, j'en sais rien

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Mon compilo est la dernière version de GCC (3.4.2 je crois)
    GCC 3.4.2 est vieux, la dernière version c'est la 4.1.0.
    Mais bon pour Windows, c'est compliqué d'avoir des versions plus récentes, en particulier si tu veux garder une ABI compatible avec celui de MSVC++.

    Sinon, à part ça, t'es sûr que tes codes font vraiment la même chose ?

  3. #3
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Citation Envoyé par loufoque
    GCC 3.4.2 est vieux, la dernière version c'est la 4.1.0.
    Mais bon pour Windows, c'est compliqué d'avoir des versions plus récentes, en particulier si tu veux garder une ABI compatible avec celui de MSVC++.

    Sinon, à part ça, t'es sûr que tes codes font vraiment la même chose ?
    Oui oui, j'obtient exactement les mêmes résultats à la fin des calculs, donc il font la même chose... Pour GCC, je vais voir si je peux réinstaller une version plus récente.

    EDIT : pourtant sur le site de MinGW, la dernière version en date est la 3.4.5 :p. J'ai vu sur le site de GCC qu'ils en sont à la 4.2.0, et j'ai une question, car j'ai aussi Linux, et de base il y a une version de GCC installée sous Linux ?

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Oui oui, j'obtient exactement les mêmes résultats à la fin des calculs, donc il font la même chose...
    C'est pas ça que je veux dire.
    Par exemple, les vecteurs dans ublas utilisent de l'allocation dynamique. Toi peut-être pas.

    J'ai vu sur le site de GCC qu'ils en sont à la 4.2.0, et j'ai une question, car j'ai aussi Linux, et de base il y a une version de GCC installée sous Linux ?
    Ah oui pardon, la c'est la 4.2.0 la dernière, pas la 4.1.0.
    La plupart des distributions ont un système de paquets avec bien sûr GCC, mais pas nécessairement la dernière version, ni nécessairement installé par défaut.
    Par exemple, sur Ubuntu Feisty Fawn y'a GCC 4.1.2 et ce n'est pas installé par défaut.

  5. #5
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Ouep, je viens de regarder rapidement les sources, on dirait qu'il y a une allocation dynamique de leur vecteur (ils n'ont pas une taille fixe, alors que moi si), mais quand même, ça peut faire une différence aussi grande ?

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Par défaut
    Je vois au moins 2 problèmes possibles:
    -ton bench est très probablement mauvais: trop de boucles sur des vecteurs trop petits. Tu veux pas mesurer le temps d'exexution de tes boucle for. Fais plutôt une seule boucle de calculs, et utilise de grands vecteurs
    -utilise une longueur multiple de 2 pour les doubles, multiple de 4 pour les floats. Car sinon t'as de bonnes chances que les librairies n'utilisent pas les instructions SSE/SSE2

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    boost::ublas est optimisé pour gérer des grands vecteurs, de taille variable (donc allocation dynamique). Visiblement, tu veux utiliser des petits vecteurs de taille fixe. Ce sont deux applications différentes, qui ne s'optimisent pas de la même manière (par exemple, les petits vecteurs peuvent y gagner pas mal en déroulant automatiquement les boucles, ce qui est je crois moins flagrant sur les gros)..

    Si tu veux tester un truc plus proche de ton objectif, peut-être que TinyVector de Blitz ( http://www.oonumerics.org/blitz/docs..._7.html#SEC131 ) pourrait te convenir. Je ne connais rien de plus récent sur le sujet.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    En fait j'aurais une question, la classe que j'ai codé avec les expressions templates est très fouillie pour l'instant, beaucoup trop de code pour ce qu'elle fait, j'ai quelques idées pour la rendre plus petite et virer pas mal de classes mais... est-ce vraiment intéressant les expressions templates en terme de performance, pour de petits vecteurs (3 composantes), sachant que j'aimerais bien utiliser le même procédé pour les matrices (16 valeurs donc) ?

    Je m'étais mis en pause quelques temps au niveau de la prog 3D pour approfondir mes connaissances en C++ ce qui n'a pas été un mal puisque j'ai appris pas mal de choses, et là je commence doucement à rentrer dans ce monde des templates, mais bien que les expressions templates ça ait vachement la classe, ça pète vraiment dans un code, je sais pas si ça peut-être intéressant dans un cas comme ça (étant donné que ces classes là, je compte les utiliser plus tard dans le contexte de la prog JV, où il y a en effet pas mal de calculs de ce genre).

  9. #9
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    A mon avis, ça a de l'intérêt. La preuve, tu as un facteur 5 par rapport à la classe naïve. Dans le monde de la 3D, j'ai vu pas mal de code difficile à maintenir parce que pour éviter le coût des boucles et des temporaires, le code était typiquement écrit sous la forme (le faute de frappe est ici volontaire, pour montrer le genre de problèmes...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    A[0] = A[0] + B[0] + C[0]; 
    A[1] = A[1] + B[1] + C[1]; 
    A[2] = A[1] + B[2] + C[2];
    Et je parle pas des produits vectoriels, où les indices doivent être mélangés...

    Les expression templates permettent d'écrire du code qui reviendra au même en terme de performances, mais qui sera lisible par le développeur. Si je devais faire ce genre de code, je réfléchirait sérieusement à les utiliser.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  10. #10
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Salut,

    Bon j'ai passé une petite après-midi à continuer à me documenter sur les expressions templates, et en fait la méthode que j'ai faite est extrêmement lourde ! J'ai tout recodé, mais maintenant il y a facile 3-4 fois moins de code, et Visual C++ est content, puisque j'obtient d'excellentes perfs à présent, alors que sur mon ancienne classe, Visual avait un gros problème et n'arrivait pas à obtenir les mêmes résultats que sous GCC.

    Par contre le problème c'est que je perds la généricité (on dit comme ça pour classe générique ?), je pense que ya moyen de résoudre ça. Voici le code en question : pour l'instant je n'en suis qu'au début, il faut que je recode tous les opérateurs, mais par rapport à mon ancienne classe c'est carrément le jour et la nuit, c'est carrément plus clair, carrément plus léger et sur les tests que j'ai fait carrément plus rapide.... (et puis cette fois-ci, elle est facile à comprendre sans avoir besoin de lire 30 fois le code pour comprendre ce que ça fait) :

    Classe Vec3 :

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    #ifndef VEC3_HPP
    #define VEC3_HPP
     
    #include <iostream>
    #include "MathOps.hpp"
     
    class Vec3
    {
    	// Surcharge de l'opérateur <<
    	friend std::ostream & operator<< (std::ostream &, const Vec3 &);
     
    	public:
    		// Constructeurs / Destructeur
    		Vec3 ();
    		Vec3 (const Vec3 &);
    		Vec3 (const float, const float, const float);
    		~Vec3 ();
     
    		// Surcharge de l'opérateur [] en écriture et en lecture
    		inline float operator[] (const size_t) const;
    		inline float & operator[] (const size_t);
     
    		// Surcharge de l'opérateur = avec un autre objet Vec3
    		inline Vec3 & operator= (const Vec3 &);
     
    		// Surcharge de l'opérateur = avec une expression template
    		template <typename Expr>
    		inline Vec3 & operator= (const Expr &);
     
    	private:
    		float val [3];
    };
     
    // Constructeur par défaut, ne fait rien
    Vec3::Vec3 ()
    {
    }
     
    // Constructeur de copie
    Vec3::Vec3 (const Vec3 & vec)
    {
    	val[0] = vec[0];
    	val[1] = vec[1];
    	val[2] = vec[2];
    }
     
    // Constructeur prenant trois entiers flottants
    Vec3::Vec3 (const float x, const float y, const float z)
    {
    	val[0] = x;
    	val[1] = y;
    	val[2] = z;
    }
     
    // Destructeur
    Vec3::~Vec3 ()
    {
    }
     
    // Surcharge de l'opérateur [] en lecture
    inline float Vec3::operator[] (const size_t idx) const
    {
    	return val[idx];
    }
     
    // Surcharge de l'opérateur [] en écriture
    inline float & Vec3::operator[] (const size_t idx)
    {
    	return val[idx];
    }
     
    // Surcharge de l'opérateur = avec un autre objet Vec3
    inline Vec3 & Vec3::operator= (const Vec3 & vec)
    {
    	val[0] = vec[0];
    	val[1] = vec[1];
    	val[2] = vec[2];
     
    	return *this;
    }
     
    // Surcharge de l'opérateur = avec une expression template
    template <typename Expr>
    inline Vec3 & Vec3::operator= (const Expr & expr)
    {
    	val[0] = expr[0];
    	val[1] = expr[1];
    	val[2] = expr[2];
     
    	return *this;
    }
     
    // ---------------------------------- FONCTION AMIES ---------------------------------------
    std::ostream & operator<< (std::ostream & out, const Vec3 & vec)
    {
    	out << vec[0] << ' ' << vec[1] << ' ' << vec[2];
     
       return out;
    }
     
    #endif // VEC3_HPP
    Fichier MathOps.hpp, contient les surcharges d'opérateur (enfin pour l'instant LA seule et unique surcharge, + :p), la classe Expression qui crée les expression templates et les structures de calcul :

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    #ifndef MATHOPS_HPP
    #define MATHOPS_HPP
     
    // ------------------------------- Déclaration des structures -------------------------------
    struct opAdd; // Addition
    struct opSub; // Division
     
    // --------------------------- Définition de la classe Expression ---------------------------
    template <typename L, typename OpTag, typename R>
    struct Expression
    {
    	// Constructeur / Destructeur
    	Expression (const L &, const R &);
    	~Expression ();
     
    	// Surcharge de l'opérateur []. Permet l'évaluation de l'expression template
    	inline float operator[] (const size_t) const;
     
       private:
    		const L & l; // Opérande gauche
    		const R & r; // Opérande droite
    };
     
    // Constructeur
    template <typename L, typename OpTag, typename R>
    Expression <L, OpTag, R>::Expression (const L & l, const R & r)
       : l (l), r (r)
    {
    }
     
    // Destructeur
    template <typename L, typename OpTag, typename R>
    Expression <L, OpTag, R>::~Expression ()
    {
    }
     
    // Surcharge de l'opérateur []. Permet l'évaluation de l'expression template
    template <typename L, typename OpTag, typename R>
    inline float Expression <L, OpTag, R>::operator[] (const size_t idx) const
    {
    	return OpTag::Compute (l[idx], r[idx]);
    }
     
     
    // ------------------------ Définition des structures mathématiques ------------------------
     
    // Addition
    struct opAdd
    {
    	// Unique fonction de la structure. Se contente de renvoyer la somme de ses deux paramètres
    	static float Compute (const float a, const float b)
    	{
    		return a+b;
    	}
    };
     
    // -------------------------------- Surcharge des opérateurs --------------------------------
    // Opérateur d'addition (+)
    template <typename L, typename R>
    Expression <L, opAdd, R> operator+ (const L & l, const R & r)
    {
    	return Expression <L, opAdd, R> (l, r);
    }
     
     
    #endif // MATHOPS_HPP
    Je sais pas si ya moyen d'optimiser encore, mais je suis déjà très très satisfait de ce que j'obtient là . Par contre comme j'ai dit, avec cette nouvelle architecture, je n'arrive plus à écrire Vec3 <double> par exemple... je peux faire de la classe Vec3 une classe template, mais ça bloque à l'appel de l'operator+, je ne sais pas où mettre le type T :/.


    EDIT : bon, après avoir refait des tests, il se trouve qu'une méthode bien "classique" semble carrément plus efficace, même si par rapport à mon ancienne méthode avec les ep, la nouvelle est plus performante. En tout cas, ceci est plus rapide (classe vecteur codée "naïvement") :

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    #ifndef NAIVEARRAY_HPP
    #define NAIVEARRAY_HPP
     
    class Vec3
    {
    	// Surcharge de l'opérateur <<
    	friend std::ostream & operator<< (std::ostream &, const Vec3 &);
     
    	public:
    		// Constructeurs / Destructeur
    		Vec3 ();
    		Vec3 (const Vec3 &);
    		Vec3 (const float, const float, const float);
    		~Vec3 ();
     
    		// Surcharge de l'opérateur [] en écriture et en lecture
    		inline float operator[] (const size_t) const;
    		inline float & operator[] (const size_t);
     
    		// Surcharge de l'opérateur = avec un autre objet Vec3
    		inline Vec3 & operator= (const Vec3 &);
     
    		// Surcharge de l'opérateur = avec une expression template
    		template <typename Expr>
    		inline Vec3 & operator= (const Expr &);
     
    	private:
    		float val [3];
    };
     
    // Constructeur par défaut, ne fait rien
    Vec3::Vec3 ()
    {
    }
     
    // Constructeur de copie
    Vec3::Vec3 (const Vec3 & vec)
    {
    	for (size_t i = 0 ; i != 3 ; ++i)
    	   val[i] = vec[i];
    }
     
    // Constructeur prenant trois entiers flottants
    Vec3::Vec3 (const float x, const float y, const float z)
    {
    	val[0] = x;
    	val[1] = y;
    	val[2] = z;
    }
     
    // Destructeur
    Vec3::~Vec3 ()
    {
    }
     
    // Surcharge de l'opérateur [] en lecture
    inline float Vec3::operator[] (const size_t idx) const
    {
    	return val[idx];
    }
     
    // Surcharge de l'opérateur [] en écriture
    inline float & Vec3::operator[] (const size_t idx)
    {
    	return val[idx];
    }
     
    // Surcharge de l'opérateur = avec un autre objet Vec3
    inline Vec3 & Vec3::operator= (const Vec3 & vec)
    {
    	for (size_t i = 0 ; i != 3 ; ++i)
    	   val[i] = vec[i];
     
    	return *this;
    }
     
    // Surcharge de l'opérateur = avec une expression template
    template <typename Expr>
    inline Vec3 & Vec3::operator= (const Expr & expr)
    {
    	for (size_t i = 0 ; i != 3 ; ++i)
    		val[i] = expr[i];
     
    	return *this;
    }
     
    Vec3 operator+ (const Vec3 & a, const Vec3 & b)
    {
    	Vec3 result;
     
    	for (size_t i = 0 ; i != 3 ; ++i)
    		result [i] = a[i] + b[i];
     
    	return result;
    }
     
    #endif // NAIVEARRAY_HPP
    Sur l'opération :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (size_t i = 0 ; i != 10000000 ; ++i)
       d = a+b;
    Naïve style : 1.39683 * 10^-6
    EP style : 0.0739323

    Alors je sais qu'il y a les histoires de cache, donc en changeant ce code par celui-ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (size_t i = 0 ; i != 100000000 ; ++i)
       d = a+b+d;
    Naïve style : 2.45574
    EP style : 2.18216

    EDIT 2 :

    Et j'ai testé juste par curiosité ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for (int i = 0 ; i != 100000000 ; ++i)
    {
       for (size_t j = 0 ; j != 3 ; ++j)
    	d[j] = a[j]+b[j]+d[j];
    }
    Et là j'obtient 0.864855. C'est ce que j'aimerais obtenir or j'obtient le résultat mis à l'EDIT 1 :/.
    Bref, la boucle idéale, et là j'obtient environ :

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Par défaut
    Petite remarque en passant.
    Ta fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // Surcharge de l'opérateur = avec un autre objet Vec3
    inline Vec3 & Vec3::operator= (const Vec3 & vec)
    {
    	for (size_t i = 0 ; i != 3 ; ++i)
    	   val[i] = vec[i];
    	return *this;
    }
    serait bien plus rapide si tu développais la boucle.
    J'avais fais des essais y'a quelques années pour voir si les compilos pouvaient le faire d'eux même pour des boucles à taille constante mais j'ai été très deçu (malgré les promesses des docs de références). je doute que les choses ont changé radicalement.
    Développer les boucles est une méthode de base de l'optimisation, surtout pour les petites boucles, c'est là tout l'intérêt des tiny vecteurs. (Sinon y'a toujours des trucs du genre duff's device pour les plus grandes boucles).
    Les principales raisons du gain de vitesse:
    -pas de cassure du pipeline du processeur pour des sauts mal prédis (même si c'est pas trop d'actualité dans une boucle)
    -moins de code à exécuter (pas de ++i, pas de comparaison...)
    -mais surtout: le calcul de l'adresse mémoire se fait à partir d'un indice constant, permettant de belles optimisations en assembleurs

    J'ai pas regardé le code mais je présume que ton opérateur d'affectation est à la base de tout calcul avec les expression templates...


    De plus y'a les instructions SIMD des processeurs. D'après moi, aucun calcul numérique ne peut prétendre être optimisé s'il n'en fait pas usage.
    Le gain en rapidité des expression template est quasi négligeable en comparaison...

  12. #12
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Bonsoir :p

    Bon vu que je suis en vacances je peux pas mal programmer, et toute la journée j'ai essayé plein de trucs et jamais arriver à ce que je souhaite. J'ai fait ce que tu m'as dit pour les boucles, mais ça ne change pas grand chose... Le tuto du site fait état de ça :

    Une fois ce code inliné et compilé, tout ce qu'il en restera sera la ligne correspondante à notre calcul mathématique déjà citée plus haut. Mission accomplie !
    Donc en toute logique en utilisant les expressions templates je devrais obtenir A PEU PRES le même résultat que :

    for (size_t i = 0 ; i != 1000000 ; ++i)
    {
    for (size_t j = 0 ; j != 3 ; ++j)
    d[j] = a[j] + b[j] + d[j]
    }

    Or comme dit plus haut c'est carrément pas le cas. Ok le calcul du temps est peut-être pas très précis, mais quand je fais
    d = a+b+d et l'expression plus haut, ça se voit carrément à vue d'oeil. Là si je refait le test :

    avec la méthode idéale : 0.0712043
    avec les ep : 1.48643

    Ca m'énèrve, ça sert à quoi ces expressions templates si ça veut pas marcher . C'est marquer sur tous les sites, tous les bouquins que le but c'est d'obtenir les mêmes performances que la boucle directement tout en gardant l'avantage d'une écriture logique tel que d = a+b, et là ça marche pas. Je précise que j'ai essayé également les expressions templates du tuto de Laurent, et j'obtient encore un peu moins bien que pour le miens.

    J'ai mis à jour plus haut le code comme il est actuellement, si quelqu'un veut regarder

    Charlemagne > "De plus y'a les instructions SIMD des processeurs. D'après moi, aucun calcul numérique ne peut prétendre être optimisé s'il n'en fait pas usage." Les instructions SIMD c'est bien les instructions SSE ? Si c'est le cas, je les ait activé dans les options du compilo.

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Par défaut
    Si c'est le cas, je les ait activé dans les options du compilo.
    Erreur classique, quasiment tout le monde croit qu'il suffit d'activer l'option, alors qu'elle ne sert (quasiment) à rien...

  14. #14
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Ah je ne savais pas :p. Il faut donc apprendre les instructions de tout ça. Mais bon dans l'immédiat je voudrais faire marcher mes ET ...

  15. #15
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Bon, après de très très nombreux essais, j'ai ENFIN réussi à avoir les mêmes performances qu'avec une boucle "parfaite" et même un peu mieux ! Par contre, c'est un peu bizarre, en fait, si je déclare tout inline, et que je définit les fonctions en dehors, par exemple :

    class MaClasse
    {
    inline void UneFonction ();
    }

    inline void MaClasse::UneFonction ()
    {
    }

    Et bien là les résultats n'étaient pas bon, par contre en écrivant :

    class MaClasse
    {
    void UneFonction ()
    {
    };
    }

    Et en faisant ça avec toutes les fonctions, les perfs se sont littéralement envolées. Je ne comprends pas tellement pourquoi puisque je vois pas pourquoi il l'inlinerai celles que je définit directement dans le corps de la classe, et pas celles que je définieraient en dehors.

  16. #16
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Erreur classique, quasiment tout le monde croit qu'il suffit d'activer l'option, alors qu'elle ne sert (quasiment) à rien...
    Les versions récentes de GCC font de l'auto-vectorisation.

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Par défaut
    Citation Envoyé par loufoque
    Les versions récentes de GCC font de l'auto-vectorisation.
    Et tu crois aussi au père Noël...
    L'auto vectorisation ça sert en pratique à RIEN, d'autant que GCC est à la masse pour ce qui est de l'optimisation SSE en comparaison à ICL. (c'est une des raisons pour lesquelles je ne fais pas mes benchs avec GCC)

    PS: ceci dit, Visual ne semble pas mieux que GCC.

  18. #18
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 292
    Par défaut
    Citation Envoyé par loufoque
    GCC 3.4.2 est vieux, la dernière version c'est la 4.1.0.
    Mais bon pour Windows, c'est compliqué d'avoir des versions plus récentes, en particulier si tu veux garder une ABI compatible avec celui de MSVC++.
    Cette semaine, j'ai vu passer des mails relatifs à un port de GCC 4.3 pour cygwin.
    C'est encore laborieux. Je sens qu'il ne va pas falloir s'attende à une version récente de GCC pour windows (cygwin comme mingw) avant encore un bon moment.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

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

    Informations forums :
    Inscription : Mars 2004
    Messages : 743
    Par défaut
    Y'en a qui compilent quand-même sous Windows les versions récentes de GCC.
    http://www.develer.com/oss/GccWinBinaries

    Sous cygwin il suffit de taper une commande du genre, pour compiler avec cette version.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    export PATH="/cygdrive/c/Program Files/MinGW/bin/":$PATH
    Ca compile bien pour moi.
    Par contre je ne sais pas quoi faire pour que le linker marche.

  20. #20
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 292
    Par défaut
    Cela remonte à deux versions de GCC. Et c'est pour du MingW, et non du Cygwin visiblement. (ne pouvant pas avoir de version correcte de mutt avec MingW, je l'ai laissé tomber il y a bien longtemps.)
    Bref, rien d'officiel avant un bon moment -- j'avais oublié une partie des choses que je voulais dire
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

Discussions similaires

  1. ublas excessivement lent
    Par Invité dans le forum Boost
    Réponses: 4
    Dernier message: 25/02/2011, 17h30
  2. boost::timer trop lent.
    Par nuKs dans le forum Boost
    Réponses: 13
    Dernier message: 28/01/2011, 10h57
  3. Boost.uBlas et sous-vecteur de matrice
    Par Le Farfadet Spatial dans le forum Boost
    Réponses: 11
    Dernier message: 30/04/2008, 23h25
  4. [BOOST] utilisation de boost uBLAS non compile avec visual c++
    Par le_voisin dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 06/09/2006, 22h03
  5. probleme boost::ublas
    Par p_moiret dans le forum Bibliothèques
    Réponses: 4
    Dernier message: 19/12/2005, 16h10

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