C'est vrai que les compilo sont maintenant très très évolués.... Même entre 2 générations proches visual studio 2005 et son prédécesseur. Il y a des différences ! (surtout quand on demande une taille pour l'exe la plus petite possible.)
C'est vrai que les compilo sont maintenant très très évolués.... Même entre 2 générations proches visual studio 2005 et son prédécesseur. Il y a des différences ! (surtout quand on demande une taille pour l'exe la plus petite possible.)
Première grosse démo en construction :
http://bitbucket.org/rafy/exo2/
Et bien, mon compilo ne fait pas de telles optimisations automatiquement. Et c'est pas faute d'avoir essayer.
Mon compilo (Intel C++ compiler sous Windows) est pourtant de loin le meilleur que j'ai trouvé. Mais peut-être que sur ce point précis d'autres compilos feront mieux, mais j'en doute.
Si ça vous intéresse, je veux bien vous montrer le code assembleur généré en mélangeant SSE et mon développement de boucles.
Oui, je ne parlais que des constantes magiques qui n'ont aucun impact sur les perfs, juste la maitenabilité & cie.Envoyé par Charlemagne
(Dans les autres techniques de compil' pour une meilleure utilisation du pipeline, tu as le duff-device aussi -- pour ceux qui veulent s'amuser à faire des comparaisons, tout ça)
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...
Bonjour a tous, je fais du c++ depuis 6 mois, j'ai quelques questions concernant la rapidité du code ( certains points ont déjas étés évoquées, mais les personnes se sont contredites ... ).
Donc selon vous, est ce que ces différentes étapes permettent - ou non - d'augmenter la rapidité du code "dans l'étape finale" ( le plus efficace étant de bien construire les fonctions, et de ne pas faire compliqué ce que l'on peut faire simplement, je vous l'accorde ), et pourquoi ( justifiez un minimum si ca ne vous embête pas trop ? :
- utiliser "const" pour toutes les variables qui ne changeront pas.
- remplacer les int<65000 et quelques ( 4 octets ) par des short ( 2 octet ).
- utiliser les passage par référence au lieu des passages par valeures ( il me semble qu'il n'y a pas de copie de variable dnas ce cas la )
- éviter d'inbriquer les fonctions les unes dans les autres ( c'est le conflit rapidité/lisibilité ).
- et enfin, utiliser des additions au lieu de multiplications. Apparament, une multiplication est plus longue qu'une addition. On peut donc supposer que 2*A est plus long a faire que A+A, A+A+A plus rapide que 3*A ( on "peut supposer" ). Ce raisonnement est il valable, et si oui, jusqu'a ou ?
Là, ça dépend du compilo. C'est généralement plus important pour les pointeurs/références.Envoyé par dekron
Là, j'ai entendu des avis contradictoires: Il parait que les architectures modernes travaillent mieux sous leur type "natif", le reste prenant au contraire du temps supplémentaire (extension de signe, etc).- remplacer les int<65000 et quelques ( 4 octets ) par des short ( 2 octet ).
Pour les gros types uniquement, bien sûr. Ne passe pas un entier par référence.- utiliser les passage par référence au lieu des passages par valeures ( il me semble qu'il n'y a pas de copie de variable dnas ce cas la )
Et surtout, n'oublie jamais const là où il est valable, sinon on ne s'en sort plus.
C'est à cela que sert de déclarer une fonction static inline : S'il elle n'est appelée qu'une seule (ou peu de) fois, et seulement dans le fichier source qui la contient, elle sera directement collée dans le code au lieu d'être appelée.- éviter d'inbriquer les fonctions les unes dans les autres ( c'est le conflit rapidité/lisibilité ).
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
inline sert effectivement a écrire la fonction directement dans le code, pour éviter qu'elle soit appelée. Ce mot clef sert donc principalement pour les petites fonctiosn qui sont tres souvent utilisées non ?
quand je parlais des fonctions les unes dans les autres, je parlais des fonction récursives ( javais oublié le mot ).
Si je prends l'exemple d'un switch a 50 cases ( tooutes fonctionnent sur le meme principe, seule les données modifiées changent ), dont 5 de ces cases sont des fonctions qui sont utilisées dans les 45 autres ( mais la récursion s'arrête la ).
Cela est fait pour éviter de tout le temps faire du recopiage, améliorer la lisibilité.
Au contraire, on pourrait les recopier a chaque fois, voir a l'extreme, faire une fonction pour chaque "case" ... mais bon on perd la notio nde fonction, et ce serait ne pas utiliser les outils qui s'offrent a nous, c'est pas tres malin.
Le probleme est que d'appeler la 50eme case, puis encore faire appel a la fonction doit prendre pas mal de temps.
inline ne sert à rien, c'est un mot-clé qui dit au compil qu'il peut, s'il veut, inliner, mais c'est tout.
Pour les int vs short, si on en fait plusieurs en même temps, des short peuvent être rentable si on a des instructions parallèles, sinon, non.
Si tu as un switch à 50 cas, change ton code, ça vaudra mieux.
Spécifier un variable comme étant const ne va pas permettre au compilateur d'optimiser beaucoup plus. Pourquoi ? Parce que même si un objet est déclaré const, il peut ne pas être constant -> mutable, donc il ne peut rien faire. En revanche, c'est excellent pour le programmeur qui peut optimiser certains cas en surchargeant une fonction.
Je confirme ce que disent Miles et Médinoc.
Je trouve néanmoins les propositions de Dekron négligeable pour l'optimisation (et très incertaines) sauf celle du passage par référence.
Je ne vois effectivement pas comment les compilos pourraient tirer profit du mot réservé "const" pour optimiser la vitesse. "const" est quand même beaucoup trop pratique pour que je puisse dorénavant m'en passer (principalement sur les références).
Je vois néanmoins un genre d'occasion où "const" peut permettre d'optimiser les calculs: sur les fonctions membres optimisées. Par exemple la spécialisation de vector<bool>
donc un "const vector<bool>" sera plus rapide qu'un "vector<bool>"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 template<class A> class vector<bool,A> { typedef pseudo_bool<...> reference; typedef bool const_reference; reference operator[](size_type i) {...} const_reference operator[](size_type i) const {...} };
Tout à fait d'accord, dans certains cas, dans une fonction const, on peut enlever quelques traitements inutiles !
hum ... c'était des questions et pas des propositions ^^Envoyé par Charlemagne
Pouvez vous m'expliquer en détail, en quoi le "const", dans le cas d'un pasage par référence, est "pratique" ou offre un "gain de performances" ( pour moi, déclarer const uen variable, c'est juste pour que le compilo dise non si on lui affecte une autre valeur non ? )
un const & permet de passer juste une référence et empêche la fonction de modifier ce qui n'est pas mutable.
'tschuldigunghum ... c'était des questions et pas des propositions ^^
Justement, ce n'est (a priori) dans l'immense majorité des cas pas plus rapide si la référence est constante. Sauf par exemple dans un cas d'un passage d'un vector<bool>.Pouvez vous m'expliquer en détail, en quoi le "const", dans le cas d'un pasage par référence, est "pratique" ou offre un "gain de performances" ( pour moi, déclarer const uen variable, c'est juste pour que le compilo dise non si on lui affecte une autre valeur non ? )
La référence constante assure à l'utilisateur que la variable ne sera pas (à moins d'un cast) modifiée à l'intérieur même de la fonction, tout en permettant un passage rapide (sans copie).
Code : Sélectionner tout - Visualiser dans une fenêtre à part template<class T,class A> void f(const vector<T,A> &X) {...}
Cela permet aussi d'accepter les temporaires non nommés.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 // code qui ne compilera pas. f(std::string & t) { std::cout << t; } int main() { f("toto"); // KO // pas de conversion implicite possible de const char* à string& std::string toto = "toto"; f(toto); // OK const std::string titi= "titi"; f(titi); // KO; titi est non modifiable f(toto+"toto"); // KO : le résultat de toto+"toto" est une chaine temporaire non nommée }
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...
J'ai l'impression que c'est pas entièrement vrai. C'est effectivement ce que fait GCC. Mais j'ai vu des différences notables entre compilos (VC x, GCC, Intel Compiler) . Je suis toutefois incapable d'en décrire tous les détails.Cela permet aussi d'accepter les temporaires non nommés.
Le comportement de GCC paraît sensé à première vue mais ça m'a joué des tours.
Voici un exemple inspiré d'un de mes cas.
Une fonction 'sub' qui retourne la partie d'un vecteur (en fait une classe proxy SubVector) et une fonction 'f' qui modifie le contenu d'un vecteur.
Et bien l'appel 'f(sub(X,2,5))' ne marche pas avec GCC, mais aucun problème avec ICL. Pour faire plaisir à GCC il faut effectivement supprimer les temporaires
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 template<class Vect> SubVector<Vect> sub(Vect&X, int i, int n) {...} template<class Vect> void f(Vect &X) { X[0]=0; }
Enfin tout ça c'est hors sujet, c'est pas de l'optimisation...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 SubVector<mon_vecteur> subX=sub(X,2,5); f(subX)
Pour clore l'HS.
Alors le comportement d'ICL n'est pas conforme. Beaucoup de vieux compilateurs procédaient également de la sorte.
Ici, ce que tu peux faire, c'est prendre ton objet par copie. Si ce n'est qu'un proxy qui agit comme une vue sur autre chose, ce ne doit pas être un problème, j'imagine que l'objet ne contient qu'un pointeur et une taille, ce qui est tout petit. (ou comment faire semblant de revenir dans le sujet)
Et pour la constance, il n'est pas rare que l'on finisse avec un proxy et un const_proxy dans ces cas là. (C'est la même chose qu'avec les itérateurs)
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...
Peut-être bien, ou bien plus probablement ICL copie le comportement de VCx qui sont (VC8?) loin d'être conformes.Alors le comportement d'ICL n'est pas conforme. Beaucoup de vieux compilateurs procédaient également de la sorte.
En fait dans mon exemple, la classe proxy contiendrait plutôt une référence sur le vecteur, mais c'est pas le propos: elle serait ici effectivement petite.Ici, ce que tu peux faire, c'est prendre ton objet par copie. Si ce n'est qu'un proxy qui agit comme une vue sur autre chose, ce ne doit pas être un problème, j'imagine que l'objet ne contient qu'un pointeur et une taille, ce qui est tout petit. (ou comment faire semblant de revenir dans le sujet)
Cette solution est néanmoins à exlure, car j'ai des quantités de classes proxy (certaines petites en mémoire, d'autres grandes), je veux avoir une seule fonction template par calcul et éviter de faire trop de cas particuliers.
Et donc, que le compilo considère un temporaire comme constant reste une contrainte, même si dans 99% des cas c'est justifié.
Un temporaire constant, c'est pratique pour que les gens comprennent bien que ce n'est qu'un temporaire et que le modifier ne sert à rien
un temporaire constant c'est bien dans la majorité des cas, mais dans le cas de proxis c'est ch..., ça oblige à faire une variable locale temporaire.
Mon exemple revient à dire (en le carricaturant à peine) que
n'est pas (toujours) équivalent pour un compilo à
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 Variable X; { Proxi PX=g(X); f(PX); }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Variable X; f(g(X));
Effectivement, dans ce cas-ci, c'est embêtant.
Un proxy n'étant généralement qu'un intermédiaire vers la véritable donnée, je ne crois pas en avoir manipulé des qui soient lourds.
Sinon, j'avoue que j'ai de moins en moins de temporaires non nommées. J'ai aujourd'hui tendance à déclarer des données temporaires nommées non modifiables. La faute à des core qu'il me faut parfois analyser.
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...
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager