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 :

[métaprogrammation]les arbres syntaxiques inutilisables?


Sujet :

C++

  1. #1
    Membre chevronné

    Homme Profil pro
    ingénieur de recherche
    Inscrit en
    Mars 2011
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : ingénieur de recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mars 2011
    Messages : 103
    Par défaut [métaprogrammation]les arbres syntaxiques inutilisables?
    Bonjour,

    Dans l'optique de faire un moteur physique, j'ai choisi d'utiliser les template pour faire des arbres syntaxiques et simplifier mes calculs.
    le système est éxpliqué dans ce tutoriel:
    http://loulou.developpez.com/tutorie...taprog/#LIII-C

    Je travaille sur des vecteur de 3 double et des matrices de 3*3 doubles.
    Ce que je veux faire est dériver une expression mathématique, pour ensuite rentrer dans un solveur les tèrmes inconnus( les tèrmes inconnus seront les tèrmes de dérivée seconde). Pour l'instant j'ai simplement implémenté la dérivation et l'évaluation de l'expression. Et le problème est que le compilateur n'inline pas assez l'arbre syntaxique, or sa complexité devient quadratique en fonction du nombre d'éléments dans l'arbre syntaxique. On peut facilement le voir lorsque l'on fait une sortie assembleur:
    Par exemple si l'arbre syntaxique est réellement construit (ce qui ne devrait pas arriver si l'inlining fonctionne bien):

    Pour une suite d'additions la taille de la variable de l'expression a la taille de l'ensemble des variable qu'il contitent
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sizeof(v1+v2+v3+v4+v5+v6+v7+v8)==sizeof(v1)*8
    Or la construction de l'arbre se fait comme suit:
    (avec Tn+1==Opplus<Tn,T> et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sizeof(Tn)==sizeof(T)*n
    )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Opplus<Tn,T>(Tn a, T b):op1(a),op2(b){}
    La construction du type intérmédière Tn se fait en copiant une variable de taille n*sizeof(T)
    Or il ya n type intérmédière construit donc la taille totale des variables déplacée est sizeof(T)n*(n+1)/2

    Ce qui fait beaucoup, la complexité devient quadratique alors que l'on voulait gagner en complexité!!
    Le compilateur ne fait pas son travail! Deplus cela devient dangereux lorsque je dérive une expression qui fait intervenir des multiplication:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sizeof(derive(derive(v*v*v)))==sizeof(v)*27
    J'ai donc de gros template, si le template n'est pas optimisé la complexité finale dans le pire des cas est de
    27*28/2*C(copie)+27*C(opérations)
    alors qu'il ne devrait y avoir seulement 27*C(opérations)

    Voilà le code du template pour quelques opérations(ce code fonctionne):
    essais.h
    matr9d.cpp
    matr9d.h
    essais.cpp
    patrons.h

    matr9f.h et matr9f.cpp contienne le vecteur de 3 double et la matrice de 3*3 double, avec plein d'opérations.
    patrons.h contient deux trois template
    essai.cpp contient le main et essai.h contient l'arbre syntaxique.

    On peut essayer différentes expressions qui réalisent la même chose entre le calcul direct et le calcul par évaluationde l'arbre syntaxique. On voit que la sortie assembleur effectuée avec l'arbre syntaxique est plus longue.

    compilation pour sortie assembleur:
    g++ -O2 -S -std=c++0x *.cpp


    Y a-t-il un truc pour régler ce problème?

    Merci d'avance pour vos réponses
    Mes tutoriels avancés sur la triangulation par filet à surface et sur les octree - N'hésitez pas à consulter les tutoriels et FAQ 2D/3D/jeux.

  2. #2
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par défaut
    J'ai peut-être parcouru trop vite tes fichiers, mais je ne vois nul part de construction d'arbre syntaxique par métaprogrammation... Où sont tes méta-opérateurs ? Où sont tes méta-constructeurs ?

  3. #3
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Par défaut
    Je répond uniquement sur la question de l'inlining (pour le reste : 0. la question est trop floue, ça parle de métaprogrammation mais il n'y a que les base de la programmation générique 1. Au vu du titre je m'attendais à voir la construction d'une expression qui ressemble à de la lazy evaluation + simplification de l'arbre qui rentre les expressions dans des types "plus haut" 2. Plusieurs choses me gène dans ce code mais surtout : pourquoi ne pas utiliser la bibliothèque standard (std::swap, std::vector) ?)

    Donc, si tu veux que le compilateur puisse inliner, le plus simple est de mettre la définition des fonctions dans un fichier d'entête. Il existe une solution pour forcer l'inlining, cette solution dépend du compilateur ; utiliser BOOST_FORCE_INLINE devrait suffire.

  4. #4
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Je rajoute mon p'tit grain de sel
    Mettre les définitions dans l'en-tête, et si la définition n'est pas dans sa classe, ajouter le spécificateur inline

  5. #5
    Membre chevronné

    Homme Profil pro
    ingénieur de recherche
    Inscrit en
    Mars 2011
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : ingénieur de recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mars 2011
    Messages : 103
    Par défaut
    Désolé pour le manque de précision, je m'explique un peu plus:

    Toutes les fonctions de l'arbre syntaxique sont dans essais.h.
    A la différence du tutoriel que j'ai cité : http://loulou.developpez.com/tutorie...taprog/#LIII-C
    Je n'utilise pas une classe pour les opérateurs binaires et une classe pour les opérateurs unaires, mais j'ai une classe par opérateur, sinon l'arbre syntaxique est fondamentalement pareil.

    J'ai inliné toutes les fonctions du fichier contenant l'arbre syntaxique (essai.h).

    Ensuite effectivement j'ai voulu réaliser un arbre syntaxique le plus simple possible pour faire apparaître ce problème. Mais si ce problème arrive pour un arbre simple comme celui-ci, je trouve que l'on ne peut plus faire confiance à ce type de système.

    Je n'utilise pas de tableaux dans mon arbre syntaxique. Il y a effectivement une classe dynamictab qui ressemble à la classe std::vector et une fonction echange qui est exactement la fonction swap, mais celles si n'on rien a voir avec le code utilisé( ce sont des rèste d'autre programme que j'ai fait).

    Le seul code à regarder est la classe essais.h

    La question est:
    auriez vous un arbre syntaxique qui ne soit pas limité par ce problème pour que je m'en inspire?
    auriez vous une méthode pour que l'inline se fasse a tout les coups (si possible avec gcc)?

    Ou simplement connaissez vous ce problème?
    Mes tutoriels avancés sur la triangulation par filet à surface et sur les octree - N'hésitez pas à consulter les tutoriels et FAQ 2D/3D/jeux.

  6. #6
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Inline sur les fonctions ne sert pas, 1) parce que le mot clef n'est pas fait pour ça, et 2) parce que le compilo s'en contrefout. En plus, c'est le comportement par défaut des fonctions template.

    Concernant les fichiers en assembleur, au bureau, celui avec l'arbre syntaxique est 2 fois plus petit. Je viens de restest chez moi et les fichiers font la même taille pour un contenir très proche.

    Concernant les types dans l'arbre, pourquoi ne pas prendre des références / références constantes ? Ainsi, plus de copie.

  7. #7
    Membre chevronné

    Homme Profil pro
    ingénieur de recherche
    Inscrit en
    Mars 2011
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : ingénieur de recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mars 2011
    Messages : 103
    Par défaut
    Merci pour vos réponses, j'ai fait quelques tests unitaires et les configurations les plus efficaces sont:

    Pour l'inlining il suffit d'utiliser __attribute__((always_inline)) sur gcc à la place de inline pour que la fonction s'inline à tout les coups. Cela doit être peut être l'équivalent de BOOST_FORCE_INLINE.

    il faut que les objets de l'arbre ne soit pas des référence (T const&) mais des objets (T).

    il faut que les objets passés en paramètre de l'arbre soient petits (des références par exemple (T const&) contrairement aux éléments de l'arbre).
    Au final l'arbre est bien détruit, il n'y a pas de phénomènes quadratique comme évoqués précédemment.

    Le seul problème est l'optimisation: l'optimisation est beaucoup plus limité dans l'arbre que si l'on déroule sois-même l'arbre.

    Voilà un code qui fonctionne tout seul, et qui reprend les tests unitaires, compilé en sortie assembleur avec la commande: g++ -O2 -S -std=c++0x *.cpp

    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
    #include <stdlib.h>
    #include <stdio.h>
     
    #define inline __attribute__((always_inline))
     
    /*************  vecteur de trois double avec l'opérateur plus************/
     
    class Vect3d{
    	public:
    	double x,y,z;
    	inline Vect3d(){x=y=z=0;}
    	inline Vect3d(double a,double b,double c){x=a;y=b;z=c;}
     
    	inline Vect3d operator+=(Vect3d const&v){x+=v.x;y+=v.y;z+=v.z;}
     
    	void print(const char* nom)const {printf("%s : %f %f %f \n",nom,x,y,z);}
    };
    inline Vect3d operator+(Vect3d const&v1,Vect3d const&v2){Vect3d c(v1); c+=v2; return c;}
     
    /*****************  méta-opérateur plus  *********************************/
     
    template< class T1, class T2>
    class Opplus{
    	public:
    	inline Opplus(T1 const&op1, T2 const&op2):p1(op1),p2(op2){}
    	inline Opplus(){}
    	T1 p1;// pas T1 const&p1
    	T2 p2;// pas T2 const&p2
    	inline decltype(p1.eval()+p2.eval()) eval()const{return p1.eval()+p2.eval();}
    };
    template<class T1, class T2>
    inline Opplus<T1,T2> operator+(T1 const&a,T2 const&b){return Opplus<T1,T2>(a,b);}
     
    /***********  la classe sur laquelle on va construire l'arbre  *****************/
     
    class Vect3ddiff{
    	public:
    	Vect3d const&a;// pas Vect3d a;
    	inline Vect3ddiff():a(a){}// constructeur utile pour decltype
    	inline Vect3ddiff(Vect3d const&v):a(v){}
    	inline Vect3d eval()const{return a;}
    };
     
    /**************************** Le main ******************************************/
     
    int main(){
    	Vect3d a(1,2,3);
    	Vect3ddiff b(a);
    	/*
    	(b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b
    	+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b
    	+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b).eval().print("test1");//*/
    	//evaluation après construction d (1180 lignes assembleur)
     
    	//(b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b).eval().print("test2");
    	//evaluation après construction de l'arbre  (370 lignes assembleur)	
    	/*
    	(a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a
    	+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a
    	+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a).print("test3");//*/
    	//addition directe : optimisation toujours complête : (72 ligne essembleurs)
     
    	(b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b).eval().print("test4");
    	// opérations maximums dans l'arbre syntaxique pour une optimisation complête (72 ligne essembleurs)
     
     
    	return 0;
    }
    (Désolé pour le titre agressif du post)
    Mes tutoriels avancés sur la triangulation par filet à surface et sur les octree - N'hésitez pas à consulter les tutoriels et FAQ 2D/3D/jeux.

  8. #8
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define inline __attribute__((always_inline))
    WHAT!!!!

  9. #9
    Membre chevronné

    Homme Profil pro
    ingénieur de recherche
    Inscrit en
    Mars 2011
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : ingénieur de recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mars 2011
    Messages : 103
    Par défaut
    oui normalement il faut le rajouter en plus du inline, mais dans le code que j'ai montré ça fonctionne sans le inline. Il faudrait faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #define force_inline __attribute__((always_inline))
     
    force_inline inline foo(){...}
    Mes tutoriels avancés sur la triangulation par filet à surface et sur les octree - N'hésitez pas à consulter les tutoriels et FAQ 2D/3D/jeux.

  10. #10
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Le seul problème est l'optimisation: l'optimisation est beaucoup plus limité dans l'arbre que si l'on déroule sois-même l'arbre.
    Que veux-tu dire ?

    inline Vect3d operator+(Vect3d const&v1,Vect3d const&v2){Vect3d c(v1); c+=v2; return c;} -> inline Vect3d operator+(Vect3d v1,Vect3d const&v2){v1+=v2; return v1;}

  11. #11
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    oui normalement il faut le rajouter en plus du inline, mais dans le code que j'ai montré ça fonctionne sans le inline. Il faudrait faire:
    Non c'est soit tu utilise inline soit tu utiles force_inline. Mon "What" c'était pour la macro qui redéfini un mot clé...

  12. #12
    Membre chevronné

    Homme Profil pro
    ingénieur de recherche
    Inscrit en
    Mars 2011
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : ingénieur de recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mars 2011
    Messages : 103
    Par défaut
    Je ne sais pas se que fait exactement le compilateur gcc mais lorsque j'utilise l'arbre syntaxique, j'obtient un code 2 fois plus long que si je calcul moi même le résultat de l'arbre syntaxique. Seulement ce problème n'arrive que si les opération "primaire" ne sont pas inlinées. Par exemple si l'opération de base de l'addition de vecteurs est inlinée: pas de différence entre le code fourni par l'arbre et le code fourni sans l'arbre. Sinon l'arbre fourni un code deux fois plus long, et dans ce code il apparait beaucoup d'opérations de déplacement de variable "movq", donc le problème est que le compileur n'optimise pas bien.

    Voilà l'exemple qui est plus pertinent que précédemment( voir ci-dessus pour le compiler)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Vect3d test(Vect3d const&a){
    	Vect3ddiff b(a);
    	return (b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b).eval();//avec arbre -> 600 lignes assembleur
    	//return a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a;//sans arbre -> 300 lignes assembleur
    }
    Ici soit l'évaluation est calculée après construction de l'arbre (somme de b)
    soit l'évaluation est calculée directement. Il n'y a normalement absolument aucune différence entre les deux ligne, il y en a une seulement à la compilation lorsque l'addition entre vecteur est non inline. Ce qui est très bizarre puisque cette opération n'a rien à voir avec les templates des métaopérations. Et pour le reste comme j'utilise des matrices 3*3, je n'ai pas envi d'inliner toutes les opérations que j'utilise car certaines sont lourdes.
    l'opération d'addition de vecteur inline :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    inline Vect3d operator+(Vect3d v1,Vect3d const&v2){v1+=v2; return v1;}
    l'opération d'addition de vecteur non inline, pour cela il faut alourdir la fonction sinon le compilateur l'inline quand même:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Vect3d operator+(Vect3d v1,Vect3d const&v2){v1+=v2;v1+=v1;v1+=v2;v1+=v1;v1+=v1; return v1;}
    conclusion:
    opérateur primaire inline; arbre syntaxique totalement détruit et optimisé.
    opérateur primaire non inline: arbre syntaxique totalement détruit mais deux fois plus d'opération que sans arbre.

    C'est pour cela que je ne peut pas me résoudre à les utiliser, (mais pour moi le problème est uniquement le compilateur à ce niveau).
    Mes tutoriels avancés sur la triangulation par filet à surface et sur les octree - N'hésitez pas à consulter les tutoriels et FAQ 2D/3D/jeux.

  13. #13
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Citation Envoyé par PierroVsf Voir le message
    C'est pour cela que je ne peut pas me résoudre à les utiliser, (mais pour moi le problème est uniquement le compilateur à ce niveau).
    Çà me semble être un problème de compilo oui.

    En changeant légèrement ton code pour qu'il compile sur VS2015
    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
    #include <stdlib.h>
    #include <stdio.h>
     
    #define inline __forceinline /*__attribute__((always_inline))*/
     
    /*************  vecteur de trois double avec l'opérateur plus************/
     
    class Vect3d {
    public:
    	double x, y, z;
    	inline Vect3d() { x = y = z = 0; }
    	inline Vect3d(double a, double b, double c) { x = a; y = b; z = c; }
     
    	inline Vect3d operator+=(Vect3d const&v) { x += v.x; y += v.y; z += v.z; return *this; }
     
    	void print(const char* nom)const { printf("%s : %f %f %f \n", nom, x, y, z); }
    };
    inline Vect3d operator+(Vect3d const&v1, Vect3d const&v2) { Vect3d c(v1); c += v2; return c; }
     
    /*****************  méta-opérateur plus  *********************************/
     
    template< class T1, class T2>
    class Opplus {
    public:
    	typedef typename T1::type type;
    	inline Opplus(T1 const&op1, T2 const&op2) :p1(op1), p2(op2) {}
    	inline Opplus() {}
    	T1 p1;// pas T1 const&p1
    	T2 p2;// pas T2 const&p2
    	inline type eval()const { return p1.eval() + p2.eval(); }
    };
    template<class T1, class T2>
    inline Opplus<T1, T2> operator+(T1 const&a, T2 const&b) { return Opplus<T1, T2>(a, b); }
     
    /***********  la classe sur laquelle on va construire l'arbre  *****************/
     
    class Vect3ddiff {
    public:
    	typedef Vect3d type;
    	Vect3d const&a;// pas Vect3d a;
    	inline Vect3ddiff() :a(a) {}// constructeur utile pour decltype
    	inline Vect3ddiff(Vect3d const&v) : a(v) {}
    	inline Vect3d eval()const { return a; }
    };
    (Principal changement : decltype remplacé par un typedef dans Opplus::eval()).

    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
    int main() {
    00007FF6C7451070  sub         rsp,58h  
    00007FF6C7451074  mov         rax,qword ptr [__security_cookie (07FF6C7453000h)]  
    00007FF6C745107B  xor         rax,rsp  
    00007FF6C745107E  mov         qword ptr [rsp+48h],rax  
    00007FF6C7451083  vmovupd     xmm0,xmmword ptr [__xmm@40000000000000003ff0000000000000 (07FF6C7452250h)]  
    	Vect3ddiff b(a);
     
    	(b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b).eval().print("test4");
    00007FF6C745108B  vmovsd      xmm3,qword ptr [__real@4045000000000000 (07FF6C7452238h)]  
    00007FF6C7451093  vmovsd      xmm2,qword ptr [__real@4035000000000000 (07FF6C7452230h)]  
    	Vect3d a(1, 2, 3);
    00007FF6C745109B  vmovsd      xmm1,qword ptr [__real@4008000000000000 (07FF6C7452228h)]  
    00007FF6C74510A3  vmovupd     xmmword ptr [a],xmm0  
    	Vect3ddiff b(a);
     
    	(b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b).eval().print("test4");
    00007FF6C74510A9  vmovsd      xmm0,qword ptr [__real@404f800000000000 (07FF6C7452240h)]  
    00007FF6C74510B1  vmovd       r9,xmm3  
    00007FF6C74510B6  vmovd       r8,xmm2  
    00007FF6C74510BB  lea         rdx,[string "test4" (07FF6C7452220h)]  
    00007FF6C74510C2  lea         rcx,[string "%s : %f %f %f \n" (07FF6C7452210h)]  
    00007FF6C74510C9  vmovsd      qword ptr [rsp+20h],xmm0  
    	Vect3d a(1, 2, 3);
    00007FF6C74510CF  vmovsd      qword ptr [rsp+40h],xmm1  
    	Vect3ddiff b(a);
     
    	(b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b).eval().print("test4");
    00007FF6C74510D5  call        printf (07FF6C7451010h)  
    	// opérations maximums dans l'arbre syntaxique pour une optimisation complête (72 ligne essembleurs)
     
    	return 0;
    00007FF6C74510DA  xor         eax,eax  
    }
    => Aucun calculs

    En 32 bits, le compilo s'en sort moins bien
    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
    int main() {
    00BB1050  push        ebp  
    00BB1051  mov         ebp,esp  
    00BB1053  and         esp,0FFFFFFF0h  
    00BB1056  sub         esp,50h  
    00BB1059  mov         eax,dword ptr ds:[00BB3004h]  
    00BB105E  xor         eax,esp  
    00BB1060  mov         dword ptr [esp+4Ch],eax  
    	Vect3ddiff b(a);
     
    	(b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b).eval().print("test4");
    00BB1064  vmovsd      xmm2,qword ptr ds:[0BB2120h]  
    	Vect3d a(1, 2, 3);
    00BB106C  vmovsd      xmm3,qword ptr ds:[0BB2128h]  
    00BB1074  vmovaps     xmm0,xmmword ptr ds:[0BB2140h]  
    00BB107C  vmovaps     xmmword ptr [esp+20h],xmm0  
    	Vect3ddiff b(a);
     
    	(b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b).eval().print("test4");
    00BB1082  vmovdqu     xmmword ptr [esp],xmm0  
    00BB1087  vaddsd      xmm0,xmm2,mmword ptr [esp+8]  
    00BB108D  vunpcklpd   xmm0,xmm2,xmm0  
    00BB1091  vunpckhpd   xmm0,xmm0,xmm0  
    00BB1095  vaddsd      xmm0,xmm0,xmm2  
    00BB1099  vaddsd      xmm0,xmm0,xmm2  
    00BB109D  vaddsd      xmm0,xmm0,xmm2  
    00BB10A1  vaddsd      xmm0,xmm0,xmm2  
    00BB10A5  vaddsd      xmm0,xmm0,xmm2  
    00BB10A9  vaddsd      xmm0,xmm0,xmm2  
    00BB10AD  vaddsd      xmm1,xmm3,xmm3  
    00BB10B1  vaddsd      xmm1,xmm1,xmm3  
    00BB10B5  vaddsd      xmm1,xmm1,xmm3  
    00BB10B9  vaddsd      xmm1,xmm1,xmm3  
    00BB10BD  vaddsd      xmm1,xmm1,xmm3  
    00BB10C1  vaddsd      xmm1,xmm1,xmm3  
    00BB10C5  vaddsd      xmm0,xmm0,xmm2  
    00BB10C9  vaddsd      xmm1,xmm1,xmm3  
    00BB10CD  vaddsd      xmm0,xmm0,xmm2  
    00BB10D1  vaddsd      xmm1,xmm1,xmm3  
    00BB10D5  vaddsd      xmm0,xmm0,xmm2  
    00BB10D9  vaddsd      xmm1,xmm1,xmm3  
    00BB10DD  vaddsd      xmm0,xmm0,xmm2  
    00BB10E1  vaddsd      xmm1,xmm1,xmm3  
    	Vect3ddiff b(a);
     
    	(b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b).eval().print("test4");
    00BB10E5  vaddsd      xmm0,xmm0,xmm2  
    00BB10E9  vaddsd      xmm1,xmm1,xmm3  
    00BB10ED  vaddsd      xmm0,xmm0,xmm2  
    00BB10F1  vaddsd      xmm1,xmm1,xmm3  
    00BB10F5  vaddsd      xmm0,xmm0,xmm2  
    00BB10F9  vaddsd      xmm1,xmm1,xmm3  
    00BB10FD  vaddsd      xmm0,xmm0,xmm2  
    00BB1101  vaddsd      xmm1,xmm1,xmm3  
    00BB1105  vaddsd      xmm0,xmm0,xmm2  
    00BB1109  vaddsd      xmm1,xmm1,xmm3  
    00BB110D  vaddsd      xmm0,xmm0,xmm2  
    00BB1111  vaddsd      xmm1,xmm1,xmm3  
    00BB1115  vaddsd      xmm0,xmm0,xmm2  
    00BB1119  vaddsd      xmm1,xmm1,xmm3  
    00BB111D  sub         esp,18h  
    00BB1120  vaddsd      xmm0,xmm0,xmm2  
    00BB1124  vaddsd      xmm1,xmm1,xmm3  
    00BB1128  vaddsd      xmm2,xmm0,xmm2  
    00BB112C  vaddsd      xmm1,xmm1,xmm3  
    00BB1130  vaddsd      xmm0,xmm1,xmm3  
    00BB1134  vmovsd      qword ptr [esp+10h],xmm0  
    00BB113A  vmovsd      xmm0,qword ptr ds:[0BB2130h]  
    00BB1142  vmovsd      qword ptr [esp+8],xmm2  
    00BB1148  vmovsd      qword ptr [esp],xmm0  
    00BB114D  push        0BB2118h  
    00BB1152  push        0BB2108h  
    	Vect3d a(1, 2, 3);
    00BB1157  vmovsd      qword ptr [esp+50h],xmm3  
    	Vect3ddiff b(a);
     
    	(b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b + b).eval().print("test4");
    00BB115D  call        printf (0BB1010h)  
    	// opérations maximums dans l'arbre syntaxique pour une optimisation complête (72 ligne essembleurs)
     
    	return 0;
    }
    Pour la version sans arbre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main() {
    	Vect3d a(1, 2, 3);
    	Vect3ddiff b(a);
     
    	(a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a).print("test 5");
    	// opérations maximums dans l'arbre syntaxique pour une optimisation complête (72 ligne essembleurs)
     
    	return 0;
    }
    x64
    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
    int main() {
    00007FF6D7411070  sub         rsp,38h  
    	Vect3d a(1, 2, 3);
    	Vect3ddiff b(a);
     
    	(a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a).print("test 5");
    00007FF6D7411074  vmovsd      xmm3,qword ptr [__real@4045000000000000 (07FF6D7412230h)]  
    00007FF6D741107C  vmovsd      xmm2,qword ptr [__real@4035000000000000 (07FF6D7412228h)]  
    00007FF6D7411084  vmovsd      xmm0,qword ptr [__real@404f800000000000 (07FF6D7412238h)]  
    00007FF6D741108C  vmovd       r9,xmm3  
    00007FF6D7411091  vmovd       r8,xmm2  
    00007FF6D7411096  lea         rdx,[string "test 5" (07FF6D7412220h)]  
    00007FF6D741109D  lea         rcx,[string "%s : %f %f %f \n" (07FF6D7412210h)]  
    00007FF6D74110A4  vmovsd      qword ptr [rsp+20h],xmm0  
    00007FF6D74110AA  call        printf (07FF6D7411010h)  
    	// opérations maximums dans l'arbre syntaxique pour une optimisation complête (72 ligne essembleurs)
     
    	return 0;
    00007FF6D74110AF  xor         eax,eax  
    }
    => Aucun calculs.

    x86
    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
    int main() {
    00181050  push        ebp  
    00181051  mov         ebp,esp  
    00181053  and         esp,0FFFFFFC0h  
    	Vect3d a(1, 2, 3);
    	Vect3ddiff b(a);
     
    	(a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a + a).print("test 5");
    00181056  vmovaps     xmm0,xmmword ptr ds:[182130h]  
    0018105E  sub         esp,18h  
    00181061  vmovups     xmmword ptr [esp+8],xmm0  
    00181067  vmovsd      xmm0,qword ptr ds:[182120h]  
    0018106F  vmovsd      qword ptr [esp],xmm0  
    00181074  push        182118h  
    00181079  push        182108h  
    0018107E  call        printf (0181010h)  
    00181083  add         esp,20h  
    	// opérations maximums dans l'arbre syntaxique pour une optimisation complête (72 ligne essembleurs)
     
    	return 0;
    00181086  xor         eax,eax  
    }
    => Aucun calculs.

    Doit y avoir un truc qui dérange le compilo et l’empêche d'optimiser le code dans certains cas, reste à trouver quoi. =)

  14. #14
    Membre chevronné

    Homme Profil pro
    ingénieur de recherche
    Inscrit en
    Mars 2011
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : ingénieur de recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mars 2011
    Messages : 103
    Par défaut
    Alors cela arrive aussi sur les autre compilo que gcc!

    En allant un peut plus loin pour voir quelles concéquences dans son application réelle peut avoir ce problème, j'ai fais des test à l'intérieur d'une fonction, comme cela, le compiler ne peut pas directement évaluer les paramètre et calculer le résultat, contrairements aux tests dans le main que nous avons fait. La différence de longueur de code fourni est moins importante mais demeure. En moyenne avec des grosses expression avec l'abre syntaxique le code est 2 fois plus long, (la moitié du code assembleur est fait de "mov").

    Avec de petites expressions, c'est un peut moins grave mais le problème se fait quand même ressentir: ici un code où la fonction test (composée de 9 opérations +) est 20% plus longue avec l'arbre syntaxique que sans en sortie assembleur sous gcc. En augmentant ce nombre d'opération ce pourcentage passe à 100%.
    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
     
    //#define inline __attribute__((always_inline))
     
    /*************  vecteur de trois double avec l'opérateur plus************/
     
    class Vect3d{
    	public:
    	double x,y,z;
     
    	inline Vect3d operator+=(Vect3d const&v){x+=v.x;y+=v.y;z+=v.z;return *this;}
    };
    //inline Vect3d operator+(Vect3d v1,Vect3d const&v2){v1+=v2; return v1;}
    Vect3d operator+(Vect3d v1,Vect3d const&v2);
     
    /*****************  méta-opérateur plus  *********************************/
     
    template< class T1, class T2>
    class Opplus{
    	public:
    	typedef typename T1::type type;
    	inline Opplus(T1 const&op1, T2 const&op2):p1(op1),p2(op2){}
    	inline Opplus(){}
    	T1 p1;// pas T1 const&p1
    	T2 p2;// pas T2 const&p2
    	inline type eval()const{return p1.eval()+p2.eval();}
    };
    template<class T1, class T2>
    inline Opplus<T1,T2> operator+(T1 const&a,T2 const&b){return Opplus<T1,T2>(a,b);}
     
    /***********  la classe sur laquelle on va construire l'arbre  *****************/
     
    class Vect3ddiff{
    	public:
    	typedef Vect3d type;
    	Vect3d const&a;// pas Vect3d a;
    	inline Vect3ddiff():a(a){}// constructeur utile pour decltype
    	inline Vect3ddiff(Vect3d const&v):a(v){}
    	inline Vect3d eval()const{return a;}
    };
     
    Vect3d test(Vect3d const&a);//le prototype d'une fonction test
     
    /**************************** Le main ******************************************/
    int main(){	
    	return 0;
    }
     
    Vect3d test(Vect3d const&a){//la fonction test
    	Vect3ddiff b(a);
    	return (b+b+b+b+b+b+b+b+b+b).eval();//évaluation avec arbre
    	//return a+a+a+a+a+a+a+a+a+a;//évaluation directe
    }
    //la fonction test alourdie pour qu'elle ne soit pas automatiquement inlinée par le compilateur
    Vect3d operator+(Vect3d v1,Vect3d const&v2){v1+=v2;v1+=v2;v1+=v2;v1+=v2;return v1;}
    Le problème arrive d'autant plus rapidement que la taille des variable est grosse, par exemple avec une somme de matrice 3*3, il suffit d'une dixaine d'opérations pour que le rapport de longueur entre les deux code soit de 2.

    Au final l'arbre donne un code moins optimisé, mais c'est peut être propre à l'évaluation de l'arbre, si l'on réalise d'autre opérations que l'évaluation, peut être que le résultat sera meilleur...ou pire?


    et merci pour les conseils sur le code
    Mes tutoriels avancés sur la triangulation par filet à surface et sur les octree - N'hésitez pas à consulter les tutoriels et FAQ 2D/3D/jeux.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Conception] Arbre syntaxique
    Par dessinateurttuyen dans le forum Général Java
    Réponses: 6
    Dernier message: 02/01/2006, 22h42
  2. Problèmes de pointeurs avec les arbres
    Par thierry57 dans le forum C
    Réponses: 17
    Dernier message: 22/12/2005, 23h35
  3. Tutoriel sur les arbres
    Par emidelphi77 dans le forum Langage
    Réponses: 2
    Dernier message: 09/10/2005, 23h09
  4. [LG]Les Arbres
    Par SaladinDev dans le forum Langage
    Réponses: 6
    Dernier message: 08/03/2005, 11h51
  5. Recherche documentation sur les arbres
    Par Oberown dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 22/09/2004, 01h40

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