OVH Cloud OVH Cloud

[valarray] Efiicacite ?

20 réponses
Avatar
delta
Bonjour,

Le conteneur valarray a recemment ete aborde relativement a une classe
Vecteur.
J avais l intention d ecrire un petit algorithme de resolution d edo a 1 pas
(neanmoins, a pas et ordre variables), c est pourquoi l arithmetique du
valarray
m a seduit ...
Cependant, les resultats, en terme de performance, sont catastrophiques : le
temps
de calcul est environ 10 fois plus important lorsque j utilise les
operateurs du
valarray que lorsque j ai recours a une boucle for. J avoue que Stroustrup m
avait
pourtant suffisament alleche, de sorte que je reste sur ma faim (c est le
moins que
je puisse dire).
Par ailleurs, il evoque un principe de "lazy evaluation" mais je n arrive
pas a
combler le code entre les lignes. Ainsi, peut-etre que son sentiment s
appuie sur
une optimisation qui atomise tout ...

En vous remerciant.

PS : au risque que l on m envoie voir ailleurs, j ajoute que je programme a
l aide
de vs .net 7.1 (qui possede une stl raisonnable, d apres la rumeur).

10 réponses

1 2
Avatar
Philippe Guglielmetti
delta" a écrit dans le message de
news:

Cependant, les resultats, en terme de performance, sont catastrophiques :
le temps

de calcul est environ 10 fois plus important lorsque j utilise les
operateurs du valarray que lorsque j ai recours a une boucle for.


C'est étonnant. En principe les méthodes et opérateurs template de valarray
devraient s'instancier en donnant un code approximativement identique.
Il est possible que ça vienne d'options de compilation, en particulier de la
vérification des bornes des indices.
Peux-tu poster le bout de code en question ?
--
Philippe Guglielmetti - www.dynabits.com

Avatar
delta
"Philippe Guglielmetti" a écrit dans le message de
news:3fa74dc9$0$3657$

Bonjour,

merci de ta reponse Philippe, et desole pour le format deplorable
du message.

C'est étonnant. En principe les méthodes et opérateurs template de
valarray devraient s'instancier en donnant un code approximativement
identique. Il est possible que ça vienne d'options de compilation, en
particulier de

la vérification des bornes des indices.
Peux-tu poster le bout de code en question ?


Avec plaisir, car j espere vraiment user incorrectement des valarrays
tant leur confort d ecriture est appreciable. Voici donc qqs extraits de
code. La declaration de la classe ressemble a ceci :

class RKCK_VS_VO: public NumericalMethod {
double rkck12(double a, double h, std::valarray<double> const &ystart);
double rkck23(double a, double h, std::valarray<double> const &ystart);
// ...
std::valarray<double> m_k1, m_k2, m_k3, m_k4, m_y2, m_y5;
public:
// ...
RKCK_VS_VO(VectorField *vectorField = 0, bool deleteVF = false, double
epsilon = 1.e-3,
double Hmin std::numeric_limits<float>::epsilon(), double Hestimate = 1.e-4):
NumericalMethod(vectorField, deleteVF), m_Epsilon(epsilon),
m_Hmin(Hmin), m_Hestimate(Hestimate),
m_Twiddle(3), m_Quit(3) {
m_Name = "RKCK_VS_VO";
if (m_Dimension > 2) {
m_y2.resize(m_Dimension);
m_y5.resize(m_Dimension);
}
else {
m_y2.resize(2);
m_y5.resize(2);
}
}
};


L une des methodes appelee intensivement, est par exemple, la suivante ;
les lignes originales qui calculent en valarray sont commentees et
remplacees
par leur "equivalent" a l aide d une boucle.

double RKCK_VS_VO::rkck12(double a, double h, valarray<double> const
&ystart) {
static double const c2 = 1.0/5.0;
static double const a21 = 1.0/5.0;
static double const b21 = -3.0/2.0, b22 = 5.0/2.0;
static valarray<double> y1(m_Dimension), ytemp(m_Dimension);
#ifdef _MSC_VER
LARGE_INTEGER t0;
QueryPerformanceCounter(&t0);
#endif
//y1 = ystart + h * m_k1;
for (size_t i = 0 ; i< m_Dimension; ++i) y1[i] = ystart[i] + h *
m_k1[i];
//ytemp = ystart + a21 * h * m_k1;
for (size_t i = 0 ; i< m_Dimension; ++i) ytemp[i] = ystart[i] + a21 * h
* m_k1[i];
m_k2 = m_VectorField->m_f(a + c2 * h, ytemp);
//m_y2 = ystart + h * (b21 * m_k1 + b22 * m_k2);
for (size_t i = 0 ; i< m_Dimension; ++i) m_y2[i] = ystart[i] + h * (b21
* m_k1[i] + b22 * m_k2[i]);
//double err1 = sqrt(norm(m_y2 - y1));
double err1 = 0.0;
for (size_t i = 0 ; i< m_Dimension; ++i) {
double xi2 = m_y2[i] - y1[i];
err1 += xi2*xi2;
}
err1 = pow(err1,0.25);
#ifdef _MSC_VER
LARGE_INTEGER t1;
QueryPerformanceCounter(&t1);
m_Time.QuadPart += t1.QuadPart - t0.QuadPart;
#endif
return err1;
}

ou :

inline double norm(valarray<double> const &va) {
double l = (va*va).sum();
return sqrt(l);
}

De plus, 2 autres methodes similaires a rkck12 (donnant cependant
lieu a plus d evalutions du champ de vecteurs) sont potentiellement
appelees des que l erreur de consistance est suffisament petite.

Enfin, les parametres de compilation sont :

/O2 /Op /Ot /GT /G7 /GA /I "../Include" /D "WIN32" /D "NDEBUG" /D "_UNICODE"
/D "UNICODE"
/FD /EHsc /arch:SSE /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /nologo /c /TP

En vous remerciant.

Avatar
Christophe de VIENNE
delta wrote:
//y1 = ystart + h * m_k1;
for (size_t i = 0 ; i< m_Dimension; ++i) y1[i] = ystart[i] + h *
m_k1[i];


Au risque de dire une bêtise, qu'est-ce que ça donne si tu écris :
y1 = m_k1;
y1 *= h;
y1 += ystart;

?

A+

Christophe

Avatar
Christophe Lephay
Christophe de VIENNE wrote:
delta wrote:
//y1 = ystart + h * m_k1;
for (size_t i = 0 ; i< m_Dimension; ++i) y1[i] = ystart[i] + h *
m_k1[i];


Au risque de dire une bêtise, qu'est-ce que ça donne si tu écris :
y1 = m_k1;
y1 *= h;
y1 += ystart;


N'est-ce pas, du reste, l'intérêt des valarray que de permettre de faire ça
(je ne les ai personnellement jamais utilisés) ?

Chris


Avatar
Laurent Deniau
Christophe Lephay wrote:
Christophe de VIENNE wrote:

delta wrote:

//y1 = ystart + h * m_k1;
for (size_t i = 0 ; i< m_Dimension; ++i) y1[i] = ystart[i] + h *
m_k1[i];


Au risque de dire une bêtise, qu'est-ce que ça donne si tu écris :
y1 = m_k1;
y1 *= h;
y1 += ystart;



N'est-ce pas, du reste, l'intérêt des valarray que de permettre de faire ça
(je ne les ai personnellement jamais utilisés) ?


L'interet des valarray est justement d'ecrire

y1 = ystart + h*m_k1;

directement et que ce soit aussi rapide que la boucle proposee...

a+, ld.

--
[ Laurent Deniau -- Scientific Computing & Data Analysis ]
[ CERN -- European Center for Nuclear Research ]
[ - http://cern.ch/Laurent.Deniau ]
[ -- One becomes old when dreams become regrets -- ]



Avatar
Philippe Guglielmetti
"delta" a écrit dans le message de
news:
Enfin, les parametres de compilation sont :

/O2 /Op /Ot /GT /G7 /GA /I "../Include" /D "WIN32" /D "NDEBUG" /D
"_UNICODE"

/D "UNICODE"
/FD /EHsc /arch:SSE /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /nologo /c /TP


essaie d'enlever /Op pour voir... la doc dit:

"A program compiled with /Op may be slower and larger than one compiled
without /Op. Note The /Op option disables inline generation of
floating-point functions. The standard run-time library routines are used
instead. For more information, see the /Oi option."

et comme la STL est faite de plein de petites fonctions que le compilateur a
tendance à mettre inline...
Si j'ai bien compris cette option, elle n'est utile que si tu compares
(intensivement) des nombres, ce qui ne semble pas être ton cas.
Et de toute manière fabs(a-b)<epsilon est toujours préférable à a==b...
--
Philippe Guglielmetti - www.dynabits.com

Avatar
delta
"Christophe Lephay" a écrit dans le message
de news:bo8d9l$mln$
Christophe de VIENNE wrote:
delta wrote:
//y1 = ystart + h * m_k1;
for (size_t i = 0 ; i< m_Dimension; ++i) y1[i] = ystart[i] + h *
m_k1[i];


Au risque de dire une bêtise, qu'est-ce que ça donne si tu écris :
y1 = m_k1;
y1 *= h;
y1 += ystart;


N'est-ce pas, du reste, l'intérêt des valarray que de permettre de faire
ça

(je ne les ai personnellement jamais utilisés) ?


Si c est le cas, je prefere encore une boucle. Honnetement je n ai pas teste
cette ecriture. Imaginons que j ai 3 vecteurs qui s expriment comme
combinaison
lineaire de 7 autres, et ceci dans 3 methodes distinctes ; je fais comment ?



Avatar
delta
"Laurent Deniau" a écrit dans le message de
news:
Christophe Lephay wrote:
Christophe de VIENNE wrote:

delta wrote:

//y1 = ystart + h * m_k1;
for (size_t i = 0 ; i< m_Dimension; ++i) y1[i] = ystart[i] + h *
m_k1[i];


Au risque de dire une bêtise, qu'est-ce que ça donne si tu écris :
y1 = m_k1;
y1 *= h;
y1 += ystart;



N'est-ce pas, du reste, l'intérêt des valarray que de permettre de faire
ça


(je ne les ai personnellement jamais utilisés) ?


L'interet des valarray est justement d'ecrire

y1 = ystart + h*m_k1;

directement et que ce soit aussi rapide que la boucle proposee...


Euh oui, c est bien ce que j en attends :-) D ailleurs, aussi rapide ou
plus rapide ?




Avatar
delta
"Philippe Guglielmetti" a écrit dans le message de
news:3fa7ca02$0$3654$
"delta" a écrit dans le message de
news:
Enfin, les parametres de compilation sont :

/O2 /Op /Ot /GT /G7 /GA /I "../Include" /D "WIN32" /D "NDEBUG" /D
"_UNICODE"

/D "UNICODE"
/FD /EHsc /arch:SSE /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /nologo /c
/TP



essaie d'enlever /Op pour voir... la doc dit:

"A program compiled with /Op may be slower and larger than one compiled
without /Op. Note The /Op option disables inline generation of
floating-point functions. The standard run-time library routines are used
instead. For more information, see the /Oi option."

et comme la STL est faite de plein de petites fonctions que le compilateur
a

tendance à mettre inline...


Ok, j ai apercu une lueur d espoir mais ca ne suffit pas. Le gain n est pas
significatif (incomparable en regard du gain obtenu en remplacant par une
boucle ;
je ne comprends pas d ailleurs, comment c est possible).
Commencons par le commencement peut-etre.
Le code que j ai poste (la version valarray donc, qui est commentee ds
le message precedent) montre t il des lacunes evidentes en terme de rapidite
?
Un piege classique du c++ a l affut du programmeur debutant que je suis ?
Qqchose ayant trait a la construction des objets ?


Si j'ai bien compris cette option, elle n'est utile que si tu compares
(intensivement) des nombres, ce qui ne semble pas être ton cas.
Et de toute manière fabs(a-b)<epsilon est toujours préférable à a==b...


J evite de tester l egalite de 2 reels, effectivement ... :-)


Avatar
Laurent Deniau
delta wrote:
"Laurent Deniau" a écrit dans le message de
news:

Christophe Lephay wrote:

Christophe de VIENNE wrote:


delta wrote:


//y1 = ystart + h * m_k1;
for (size_t i = 0 ; i< m_Dimension; ++i) y1[i] = ystart[i] + h *
m_k1[i];


Au risque de dire une bêtise, qu'est-ce que ça donne si tu écris :
y1 = m_k1;
y1 *= h;
y1 += ystart;



N'est-ce pas, du reste, l'intérêt des valarray que de permettre de faire


ça


(je ne les ai personnellement jamais utilisés) ?


L'interet des valarray est justement d'ecrire

y1 = ystart + h*m_k1;

directement et que ce soit aussi rapide que la boucle proposee...



Euh oui, c est bien ce que j en attends :-) D ailleurs, aussi rapide ou
plus rapide ?


Ca peut etre plus rapide mais pas de beaucoup (max 5-10%) ce que je considere
comme negligeable. Ca peut aussi etre plus lent du meme ordre de grandeur. Pour
les valarray de GCC 3.0+, Gaby te donnera surement plus d'info, c'est lui qui
les a ecrit et si je me souviens bien il s'est bien casse la tete sur les benchs
pour que soit au moins aussi rapide :-)

a+, ld.

--
[ Laurent Deniau -- Scientific Computing & Data Analysis ]
[ CERN -- European Center for Nuclear Research ]
[ - http://cern.ch/Laurent.Deniau ]
[ -- One becomes old when dreams become regrets -- ]





1 2