Attention ca va faire mal : template,inlining et AltiVec en autres

Attention ca va faire mal : template,inlining et AltiVec en autres - C++ - Programmation

Marsh Posté le 24-04-2003 à 14:20:33    

Quelques questions :
 
1. Y a t il un eoption sous gcc/g++ pour obtenir les fichiers sources intermedaires dans lesquels se trouveraient toue les templates que j'ai pu utilisé mais sous forme instanciée, si vous voyez ce que je veux dire ? j'ai chercher dans le manuel mais j'ai rien trouver.
 
2. Quelles sont exactements l slimitations d'une variable register ? Je sais qu'on peut pas en prendre l'adresse mais peut on prendre un reference dessus ou tout autre moyen de la refenrencer ?
 
3. Quelles sont les conditions generales de l'inlining des meta-programmes templates ? Se deroulent ils tous ? ou partiellement ou pas du tout selon leur contenu ?
 
4.Enfin, une derniére pour les gens qui connaissent un peu AltiVec.
Quel est la difference de perf entre  
 
 

Code :
  1. register __vector float a,b,c,r;
  2. for(inti=0;i>NBVECTOR;i++)
  3. {
  4.   a = vec_ld(i,data1);
  5.   b = vec_ld(i,data2);
  6.   c = vec_ld(i,data3);
  7.    vec_st( vec_add(a,vec_add(b,c)),i,result);
  8. }

 
 
et
 

Code :
  1. register __vector float a,b,c,r;
  2. for(inti=0;i>NBVECTOR;i++)
  3. {
  4.    a = vec_ld(i,data1);
  5.    b = vec_ld(i,data2);
  6.    c = vec_ld(i,data3);
  7.    r = vec_add(b,c);
  8.    r = vec_add(a,r);
  9.    vec_st( r,i,result );
  10. }

 
 
Merci d'avance  [:joel f]

Reply

Marsh Posté le 24-04-2003 à 14:20:33   

Reply

Marsh Posté le 24-04-2003 à 14:58:25    

pour le 1) sais pas, mais pour le 2,3,4 ça dépends totallement de ton compilateur, et des options que tu as passé en paramètres ou dans le makefile.
 
la seule chose que je puisse te dire, c'est de contrôler le code asm produit en demandant au compilo de te sortir un listing.
 
ensuite pour tout ce qui est inliné, le compilo inline tout, mais si un moment tu utilises une référence sur une routine d'inlinée, le compilo produira du code inlinée et une version normale quie sera appellée (par call/ret ou brs/rts).  
(et la référence pointera sur la version normale).
 
dans les cas des templates, ça produit généralement du code inliné (le compilo fera plus facilement du inline avec une template qu'avec une classe standard).
 
pour le 4), si le compilo est au max de ses optimisations et que c'est un bon compilo, il devrait produire le même code machine dans les deux cas.
 
le mot clé register est souvant un faux-ami, car un bon compilo utilisera automatiquement les registres et ce de manière intelligente & dynamique.
 
alors que si tu forçes des variables en register, il risque de bloquer un registre pour une variable, alors que le registre aurait été plus utile pour autre chose.
 
par exemple ça c'est débile:
 

Code :
  1. register int i;
  2. for( i=0 ; i < maxi ; i++ )
  3.   for( int j=0 ; j < maxj ; j++ )
  4.   {
  5.     //innerloop de quelque chose
  6.   }


 
ça c'est cohérent d'un point de vue optimisation:
 

Code :
  1. for( int i=0 ; i < maxi ; i++)
  2. {
  3.   register int j;
  4.   for( j=0; ; j < maxj ; j++)
  5.   {
  6.      // innerloop
  7.   }
  8. }


 
mais je dirais que si le compilo optimise bien, il choisira automatiquement quand quelque chose doit être maintenu dans un registre et le fera tout le temps...
---
 
donc tout ceci est sujet à variations de compilateur à compilateur et suivant les options que tu lui passes.
 
mais je dirais, ayant codé en asm, et controlant de temps ce que produit un compilo, l'inline c'est bien pour les fonctions utilisée à haute-fréquence, mais le mot-clé register c'est soit inutile si c'est un bon compilo, soit c'est mal, soit c'est à utiliser uniquement en ayant décortiqué le code machine produit, et ayant une connaissance aigue du cpu.
 


Message édité par bjone le 24-04-2003 à 15:07:37
Reply

Marsh Posté le 24-04-2003 à 15:01:51    

je suis persuadé (enfin quasiement), que si tu compiles les deux routines précédentes, le code machine sera le même.
et ptet même (voir très certainement) si tu fait la même routine sans le mot-clé register.

Reply

Marsh Posté le 24-04-2003 à 15:05:28    

sinon vu que tu sembles être sur un powerpc, codewarrior ne serait-il pas à recommander ?
(en fait je sais pas quels sont les meilleurs compilos pour ppc)

Reply

Marsh Posté le 24-04-2003 à 15:47:14    

Merci bien :D
 
disons que pour l'instant je suis sur un PPC G4 avec Linux dessus (beurk) mais normalement je devrais pouvoir travailler sur un mac OS X tres bientot. Est-ce que Project Builder sera suffisant ?
 
J'ai tester effectivement avec et sans register etc ... et oui le code asm est le même donc ca me rassure.
 
Ensuite, question a deux francs, l'ordre des operations AltiVec est il important ?
 
Style
 

Code :
  1. r1 = vec_ld(0,data);
  2. r2 = vec_ld(0,data);
  3. r3 = vec_ld(0,data);
  4. r4 = vec_ld(0,data);
  5. t1 = vec_add( r1,r3);
  6. t2 = vec_add( r2,r4);


 
ou
 

Code :
  1. r1 = vec_ld(0,data);
  2. r3 = vec_ld(0,data);
  3. t1 = vec_add( r1,r3);
  4. r2 = vec_ld(0,data);
  5. r4 = vec_ld(0,data);
  6. t2 = vec_add( r2,r4);


 
Sinon voila :D merci bien ;)

Reply

Marsh Posté le 24-04-2003 à 15:57:27    

PS: j'ai jamais codé sur ppc, et le 68k c'est scolaire, je transpose donc mes expériences d'optimisation sur pentium en asm et via des compilateurs optimiseurs (watcom rulez à l'époque du pentium 1)...
 
donc je dirais que pour ton exemple, je pense que le compilateur sera capable de réorganiser les instructions pour obtenir quelque chose d'optimal.
 
mais l'ordre en lui même peut avoir une influance sur l'éfficacité des caches et des accès mémoires. notemment en sse sur les x86, il y a des instruction qui permettent des chargement anticipés des éléments suivants.... (et de savoir si il existe des instructions de prefetch forcé)
 
je pense qu'à partir de là il faut se bouffer de la doc sur le cpu et savoir quel séquencement d'accès mémoire te donnera la meilleure efficacité...


Message édité par bjone le 24-04-2003 à 16:03:26
Reply

Marsh Posté le 24-04-2003 à 16:02:36    

maintenant j'ai ptet dit des conneries dans mes posts, c'est pointu de savoir ce que le compilo va faire, et ce qu'il faudrait faire....
 
donc comme j'ai le ppc je le connais pas plus que "ça", mais tout ce que j'ai pu te dire c'est relativement des généralitées...

Reply

Marsh Posté le 24-04-2003 à 17:28:32    

BJOne a écrit :

je suis persuadé (enfin quasiement), que si tu compiles les deux routines précédentes, le code machine sera le même.
et ptet même (voir très certainement) si tu fait la même routine sans le mot-clé register.


Y'as très peu de chances, mettre le mot-clef "register" colle la variable dans un registre, obligeant l'allocateur de registres à tenir compte de la contrainte, il a donc un registre de moins pour travailler. D'après les articles que j'ai lu (je me souviens plus à quelle ocasion, O'caml peut-être), c'est généralement une mauvaise idée car si la variable est active, elle sera naturellement mise en registre, mais si elle est inactive elle sera virée du registre, le rendant dispo pour les autres variables plus actives. Avec "register" elle est scotchée, active ou pas, donc les variables plus actives on moins de place dans les registres.

Reply

Marsh Posté le 24-04-2003 à 17:35:55    

nraynaud a écrit :


Y'as très peu de chances, mettre le mot-clef "register" colle la variable dans un registre, obligeant l'allocateur de registres à tenir compte de la contrainte, il a donc un registre de moins pour travailler. D'après les articles que j'ai lu (je me souviens plus à quelle ocasion, O'caml peut-être), c'est généralement une mauvaise idée car si la variable est active, elle sera naturellement mise en registre, mais si elle est inactive elle sera virée du registre, le rendant dispo pour les autres variables plus actives. Avec "register" elle est scotchée, active ou pas, donc les variables plus actives on moins de place dans les registres.


 
je suis tout à fait d'accord, c'est ce que j'ai voulu exprimer par:
 

Citation :


le mot clé register est souvant un faux-ami, car un bon compilo utilisera automatiquement les registres et ce de manière intelligente & dynamique.  
 
alors que si tu forçes des variables en register, il risque de bloquer un registre pour une variable, alors que le registre aurait été plus utile pour autre chose.  


 
en fait ce que je voulais dire, c'est que vu le peu de variables dans son code altivec, je pensais que register était superflu car le compilo aller prendre les registres automatiquement...

Reply

Marsh Posté le 24-04-2003 à 18:56:53    

nraynaud a *crit :


Y'as tr*s peu de chances, mettre le mot-clef "register" colle la variable dans un registre, obligeant l'allocateur de registres * tenir compte de la contrainte, il a donc un registre de moins pour travailler. D'apr*s les articles que j'ai lu (je me souviens plus * quelle ocasion, O'caml peut-*tre), c'est g*n*ralement une mauvaise id*e car si la variable est active, elle sera naturellement mise en registre, mais si elle est inactive elle sera vir*e du registre, le rendant dispo pour les autres variables plus actives. Avec "register" elle est scotch*e, active ou pas, donc les variables plus actives on moins de place dans les registres.


 
Il me semble de toute facon que la norme prevoit deja d'ignorer completement le mot cle register. En tout cas, gcc le fait.

Reply

Marsh Posté le 24-04-2003 à 18:56:53   

Reply

Marsh Posté le 24-04-2003 à 19:04:15    

Ok odnc, je peut jarter les registers et laissé le compilo faire ce qu'il peut.

Reply

Marsh Posté le 24-04-2003 à 22:31:38    

Joel F a écrit :

Ok odnc, je peut jarter les registers et laissé le compilo faire ce qu'il peut.

surtout qu'il le fera certainement mieux que toi

Reply

Marsh Posté le 24-04-2003 à 23:12:12    

nraynaud a écrit :


Y'as très peu de chances, mettre le mot-clef "register" colle la variable dans un registre, obligeant l'allocateur de registres à tenir compte de la contrainte, il a donc un registre de moins pour travailler. D'après les articles que j'ai lu (je me souviens plus à quelle ocasion, O'caml peut-être), c'est généralement une mauvaise idée car si la variable est active, elle sera naturellement mise en registre, mais si elle est inactive elle sera virée du registre, le rendant dispo pour les autres variables plus actives. Avec "register" elle est scotchée, active ou pas, donc les variables plus actives on moins de place dans les registres.


 
Ca dépends aussi du nombre de registres du CPU. C'est clair qu'un Pentium ça a pas beaucoup de registres et en bloquer un peut avoir des conséquences very nefastes. Mais un PPC je ne sait pas (Je le connait pas). Faut aussi considérer ce point.
Il est probable qu'avec un proco qui ait un tout petit peu plus de registres, la donne change radicalement
 
Le plus simple pour en avoir le coeur net, c'est encore de faire un bench en mettant le truc sous 10.000.000 d'itérations.
 


---------------
TOPIC PERMANENT Matrox Parhelia
Reply

Marsh Posté le 24-04-2003 à 23:19:09    

++Taz a écrit :

surtout qu'il le fera certainement mieux que toi


 
toujours le mot aimable hein (même si ca part d'une bonne intention [:zebra33] )


Message édité par schnapsmann le 24-04-2003 à 23:19:28

---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 24-04-2003 à 23:22:21    

:D

Reply

Marsh Posté le 24-04-2003 à 23:23:54    

Sr16 a écrit :


 
Ca dépends aussi du nombre de registres du CPU. C'est clair qu'un Pentium ça a pas beaucoup de registres et en bloquer un peut avoir des conséquences very nefastes. Mais un PPC je ne sait pas (Je le connait pas). Faut aussi considérer ce point.
Il est probable qu'avec un proco qui ait un tout petit peu plus de registres, la donne change radicalement
 
Le plus simple pour en avoir le coeur net, c'est encore de faire un bench en mettant le truc sous 10.000.000 d'itérations.
 
 


 
un chti itanium  [:the one]  
 
n'empêche les registres booléens de prédication c'est de la baboule quand même :D

Reply

Marsh Posté le 25-04-2003 à 09:09:12    

Le PPC avec extension AltiVec fournit  registres dédiées au calcul vectoriel.
Normalement ca devrait passer.
 
J'ai fait qqs tests et pour des calculs vectoriels "moyen" (moins de 20 sous expressions) ca passe. C'est donc largement suffisant pour mon utilisation.
 
 
Autre question :
 
J'ai une classe de vecteur template dont voila l'intitulé :
 

Code :
  1. template< class Type,int Size > class Vector;

 
 
J'aimerais bien qu'a la compilation, chaque instance de cette classe
se retrouve pourvue d'un ID numerique unique.
 
J'ai donc pensé à :
 

Code :
  1. template< class Type, int Size, int ID > class Vector;

 
 
ca marche, pas de probleme, mais :
 

Code :
  1. Vector< float,256,1> a;
  2. Vector< float,256,2 > b;

 
 
etc ... c'est lourd pour l'utilisateur.
Je pensais donc crée une espece de classe template qui me  
permettrait d'ecrire :
 

Code :
  1. template< class Type, int Size, int ID=IDGenerator() > class Vector;
  2. Vector< float,256 > a;
  3. Vector< float,256 > b;

 
 
et qui donc genererait les ID de maniére automatique à la compilation.
Manque de bol j'ai beau essayé tout et npquoi j'y arrive pas  :??:  
Suis je un boulet ? vais-je guérir ??
 
Merci d 'avance.
 
 [:joel f]

Reply

Marsh Posté le 25-04-2003 à 15:02:07    

mmmm... porké un ID unique :??:

Reply

Marsh Posté le 25-04-2003 à 17:27:56    

c'est pas une id unique par instance que tu voudrais, on est bien d'accord?

Reply

Marsh Posté le 25-04-2003 à 20:35:49    

Joel F a écrit :


Vector< float,256,1> a;
Vector< float,256,2> b;


 
tu as bien conscience que a et b seront de type
different ?
 
Si tu as besoin d'un ID unique par instance
pourquoi ne pas utiliser leur adresse en memoire ?
 
LeGreg

Reply

Marsh Posté le 25-04-2003 à 20:44:43    

à la limite autant faire une template qui reprends ta template Vector (ou la template vector<> de la STL), et de rajouter ton attribut d'ID et de jouer avec le constructeur..
 

Code :
  1. template <class T> class supervector : public vector<T>
  2. {
  3. public:
  4. using vector<T>::vector();
  5.         int ID;
  6.         supervector()
  7.         {
  8.             // gna gna gni gni
  9.         }
  10. };

Reply

Marsh Posté le 25-04-2003 à 21:27:51    

Code :
  1. supervector():// gna gna gni gni
  2.         {}


jouer au bon endroit bien sûr

Reply

Marsh Posté le 25-04-2003 à 22:13:48    

c'est comme vous voulez, c'est vous qui voyez ;)

Reply

Marsh Posté le 25-04-2003 à 22:17:55    

BJOne a écrit :

c'est comme vous voulez, c'est vous qui voyez ;)


c'est pas moi qui veut, c'est le dégarni barbu là -> http://www.research.att.com/~bs/homepage.html

Reply

Marsh Posté le 25-04-2003 à 22:18:45    

wé mais quand je me tires dans le pied, j'aime que la jambe vienne avec  [:the one]

Reply

Marsh Posté le 26-04-2003 à 11:16:04    

certes, l'ID ne semble pas approprié ...
en fait le probléme est tout autre.
 
J'utilisela technique des 'Expressiosn templates' pour  
générer du code AltiVec inline optimisé à partir d'écriture comme :
 

Code :
  1. Vector<float,100> a,b,c;
  2. a = 2*b +c;


 
qui apres 'deroulage' des templates donne un code équivalent à :
 

Code :
  1. a = vec_madd(splat(2),b,c);


 
Mon probleme est que actuellemnt, j'effectue une simple passe sur mes templates lors de l'évaluation de ces résultats.
A la compilation (compile-time), l'expression 2*b+c est decomposé en opérateurs successifs qui chacun générent le petit bout de code necessaire à effectuer le calcul.
 
Mon probleme est que actuellement le chargement de données depuis les Vector vers les __vector AltiVec se font au fur et à mesure :
 

Code :
  1. a = vec_add(vec_ld(0,b),vec_add(vec_ld(0,c),vec_ld(0,d));


 
Ce qui n'est pas efficace du tout vu mes tests.
 
J'aimerais donc que mes templates se dépleint ainsi :
 

Code :
  1. tmp1 = vec_ld(0,b);
  2. tmp2 = vec_ld(0,c);
  3. tmp3 = vec_ld(0,d);
  4. a = vec_add(tmp1,vec_add(tmp2,tmp3));


 
Ce qui me permettrait de profiter du comportement super-scalaire de l'unité de chargement Altivec.
 
Mon idée etait donc de créer une classe template qui contiendrait des memebre statiques correspondant au 32 registres
AltiVec.
 

Code :
  1. template<class T,int ID>
  2. class RegisterPool
  3. {
  4. public:
  5. static TypeInfo<T> temp;
  6. };


 
TypeInfo<T> etant une classe permettant d'effectuer un typedef du style : __vector T. ID etant un int allant de 1 à 32.
 
Cette classe serait accessible pour chaque type AltiVec (char,short,long,float) comme "pool" de registre.
 
Ensuite lors de l'affectation de mes expressions, j'effectuerais deux passes :
 
1. la premiere passe deplierait les templates en utilisant un parcourt de l'arbre des opérateurs pour générer les vec_ld.
Chaque fois que un template arrive sur une feuille de l'arbre,il ecrit :
 

Code :
  1. Register<T,N>::temp = vec_ld(i,data);


 
2. la deuxieme passe deplie la boucle de traitement la ou y a les vec_add etc .... en utilisant non pas les données MAIS les Register<T,N>::temp correspondant.
 

Code :
  1. Register<T,P>::temp = vec_ld(i,a);
  2. Register<T,N>::temp = vec_ld(i,b);
  3. Register<T,M>::temp = vec_ld(i,c);
  4. Register<T,P>::temp = vec_add(Register<T,N>::temp,Register<T,M>::temp);


 
Le probleme est donc de :
- Assigné à un Register<T,N> UNIQUE un donnée UNIQUE.
- De retrouver lors de la deuxiéme passe kel Register<T,N> correspond a une donnée quelconque.
- De ne charger qu'une fois les données même si elles apparaisent dans plusierus feuilles de l'arbre d'expression.
 
D'ou ma premiere idée de fournir à la compilation un ID a chaque  instance de Vector et d'assigner le Register<T,ID> au Vector<T,S,ID>.
 
En clair, je dois refaire l'affectation des données vers des variables temporaires à la compilation ...
 
J'espere avoir été clair ...
Je bute vraiment sur un os là :P
Merci d'avance pour ttes idée/aide etc ..

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed