Sauf si l'on prend en compte qu'avec certains compilateurs, une affectation est de type void.Citation:
Envoyé par Médinoc
Version imprimable
Sauf si l'on prend en compte qu'avec certains compilateurs, une affectation est de type void.Citation:
Envoyé par Médinoc
Tu as une référence?Citation:
Envoyé par Miles
Est-ce que ce sont des compilateurs C? Si oui, signale leur le bug.Citation:
Envoyé par spidermario
Je n'ai pas vu de compilateur dans ce cas, j'ai simplement lu qu'il y en avait :?
Peut-être que c'est faux, j'en sais rien :roll:
Où, qu'on déconseille cette source?Citation:
Envoyé par spidermario
Bonjour,
Avant d'optimiser les performances d'execution, il faut d'abord penser a optimiser le code en lecture, i.e. ecrire du code lisible pour les humains.
On ne le repetera jamais assez, les programmes sont d'abord fait pour les humains et ensuite pour les machines.
Pense au programmeur qui reprend le code apres toi et qui passe des heures a comprendre pourquoi l'idiot precedent n'a pas voulu ecrire un code clair, tout ca pour gagner une instruction parmi des millions...
Bonjour,
les trie de la STL utilise pas mal la fonction template std::swap. Il est donc préférable que les class, possedant des variable dynamique(tableau, string, vector ...) stockées dans un contenaire implémente un swap pour optimiser les trie. Cela permet de remplacer un swap constitué de 3 operation égale( donc trois recopie de mémoire) à un échange de memoire
En posant :Code:
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 #include <algorithm> #include <iostream> #include <vector> #include <string> //class qui contient la fonction swap pour éviter des recopie de memoire class A { public : A(int a,std::string s) :myString(s),nb(a){ }; const std::string &GetString() {return myString;} bool operator<(const A& a)const {return nb<a.nb;} A& operator=(const A& a) { static int nbegale(0); std::cout<<"= : "<<++nbegale<<std::endl; nb=a.nb; myString=a.myString; return (*this); } void swap(A& a) { static int nbswap(0); std::cout<<"swap : "<<++nbswap<<std::endl; std::swap(nb,a.nb); myString.swap(a.myString); }; private: //varible qui "prend du temps" lors d'une recopie std::string myString; int nb; }; //specialisation de la fonction std::swap pour la class A namespace std { template<> inline void swap<A> ( A& a, A& b ) { a.swap(b); }; } int main(int argc, char** argv) { //mon vecteur a trier std::vector<A> vect; //on remplie de n'importe quoi //le but etant quil y en ai assez pour que swap soit appelé vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(2,"deux")); vect.push_back(A(15,"quinze")); vect.push_back(A(10,"dix")); vect.push_back(A(5,"cinq")); vect.push_back(A(1,"un")); vect.push_back(A(30,"trente")); vect.push_back(A(30,"trente")); vect.push_back(A(30,"trente")); vect.push_back(A(30,"trente")); vect.push_back(A(30,"trente")); vect.push_back(A(30,"trente")); //on fait le trie std::sort(vect.begin(),vect.end()); return 0; }
- duré d'un égale = 1s
- durée d'un swap = .5s (echange de la mémoire, donc peut de recopie)
Les résultats que j'obtiens sous visual 20005 sont :
- sans le swap : 234 operation egale = 234s
- avec le swap : 74 operation swap et 72 operation egale = 109 s
Les résultats que j'obtiens avec GCC sous ubuntu sont :
- sans le swap : 361 operation egale = 361s
- avec le swap : 88 operation swap et 185 operation egale = 229 s
voici un lien qui explique un peu :
http://www.tantalon.com/pete/cppopt/...l.htm#Swapping
J'ai une petite question, qu'est ce qui est le plus rapide :
code 1 :code 2:Code:
1
2 for(int i=0;i<vec.size();i++) vec[i]->unBool = false;
Je me doute bien que si "unBool" est 99% du temps à "true", le premier code sera plus rapide. Mais à partir de quel pourcentage le code numéro 2 sera plus rapide ?Code:
1
2
3 for(int i=0;i<vec.size();i++) if(vec[i]->unBool = true) vec[i]->unBool = false;
Merci d'avance
Déjà, fais attention au test que tu excécute...
En effet, si tu fais un test du genre de
tu commence par assigner true à test[i]->unBool... et donc, le test sera toujours vrai...Code:if(test[i]->unBool = true)
Pour que ce soit réellement un test, ce serait
En outre, il serait peut-être préférable de déclarer i comme étant un size_t, ce qui est le type renvoyé par size ;)Code:if(test[i]->unBool == true)
Ceci dit, il faut savoir que, si tu fais un test de manière inopportune, ce sera toujours plus lent que si tu ne le fais pas.
Il n'y a rien à faire, un test demande un certain nombre de cycle d'horloge processeur, et donc, fatalement, cela "ralenti" un peu le code :P
Pour qu'il présente un avantage, il faudrait que les instructions à effectuer dans le cas où le test est vérifié soient plus nombreuses, de manière, justement, à éviter d'effectuer le nombre d'exécutions quand elles ne sont pas nécessaire.
Ainsi, il devient opportun de placer le test si ton code doit se présenter sous une forme proche de
Code:
1
2
3
4
5
6
7
8
9
10 for(size_t i=0;i<test.size();++i) { if(test[i]->unBool == true) { /* une série d'instructions potentiellement "longue" à l'exécution * mais, en tout cas, plus importante que la simple assignation * d'un type primitif */ } }
La version avec le if sera probablement plus longue, parce que les branchements empêchent la prédiction d'instruction de fonctionner (ainsi que la vectorisation automatique).
Ma petit pierre a l'édifice :
Pour ceux qui trouvent que gcc est long a compiler (ce qui est vrai tout de même), il est important de savoir que par defaut, il le fait sur un seul thread. En utilisant l'option j, on peut augmenter le nombre de thread et profiter a fond de notre beau dual/quad core ;)
c'est pas plutot make qui a cette option ? et scons ?
GCC aussi la possède.
C'est moi qui suis distrait ou je ne la vois pas ici:
http://gcc.gnu.org/onlinedocs/gcc-4....n-Summary.html
Ou alors c'est moi qui ai fumé quelque chose de nocif pour la mémoire. Toutes mes excuses :)
de toute facon la compilation est quelque chose de sequentiel, pas vraiment beaucoup de place pour le multi core. En revanche, make a une vue d'ensemble qui permet de decouper les taches en sequences indépendantes.
La ou GCC est lent, c'est que c'est souvent utilisé en simple fichier :
alors que sous visual, en general c'est une seule instance du compilo qui fait tous les fichiers. en utilisant gcc de la meme facon, il est sensiblement plus rapide.Code:
1
2
3
4
5 gcc -c file1.cpp -o file1.obj gcc -c file2.cpp -o file2.obj gcc -c file3.cpp -o file3.obj gcc -c file4.cpp -o file4.obj gcc -c file5.cpp -o file5.obj
Depuis les derniers messages, on en sait plus sur C++0x, on a des nouvelles versions de compilos, etc.
Vous avez d'autres conseils pour ceux qui voudraient accélérer leur code ?
Par ailleurs, êtes-vous tous d'accord pour dire que C++ va rester parmi les plus rapides, devant Java et les langages .NET par exemple ? Malgré leur VM, ils obtiennent parfois de bonnes performances, mais a priori rien ne va ralentir le C++. Il est toutefois à la charge des programmeurs C++ de connaître les trucs & astuces pour avoir un code performant et bien pensé :)
C'est le vieux débat entre langages compilés et interprétés... Au fur et à mesure que la puissance de calcul augmente, les interpréteurs vont plus vite, mais les processeurs aussi quand ils exécutent un code compilé. C'est pareil pour les progrès théoriques : meilleurs interpréteurs, meilleurs compilateurs.
En ce sens, C++ conservera sa longueur d'avance. Ma seule réserve est la tendance au développement des librairies annexes. Ce n'est pas un mal en soi, mais cela transforme parfois le C++, à l'origine rapide parce que compilé et "proche de la machine" (une instruction C++=peu d'instructions machine), en un autre langage de haut niveau. Il appartient aux programmeurs C++ de savoir quand *ne pas* utiliser telle ou telle librairie ultrapuissante, dont ils n'ont pas besoin...
Mes petits conseils d'optimisation
1- ne pas trop s'inquiéter des multiplications, des floats et des doubles, des pré et post incrémentations sur types de base, le compilateur fait ça mieux que nous (et ce n'est pas du tout intuitif)...
2- se méfier comme de la peste des "bonnes idées" d'optimisation quand on fait des calculs numériques, une simplification mal à propos donne souvent des calculs très très faux. Les algorithmes mathématiques, les prendre dans des livres et des librairies spécialisées, plutôt que dans ses souvenirs de terminale (ou de prépa).
3- évaluer la volumétrie de ses programmes avant de les écrire : il ne sert à rien d'utiliser des moyens importants pour gérer efficacement une structure que comprend très peu d'objets, en revanche, savoir à l'avance qu'un petit tableau à l'air innocent contiendra probablement 1 000 000 d'objets, et pas 1000 comme on se disait au début, permet de partir sur de bonnes bases
4- quand on travaille sur de grosses données externes, se poser dès le début la question de l'ordre dans lequel on va les utiliser. Trier ses données dans le bon ordre, avant l'exécution, permet souvent de gagner sur plusieurs tableaux (mémoire et vitesse)
5- utiliser un profileur, tout le temps, presque dès le début, pas pour optimiser, mais pour savoir où le temps est passé. Généralement savoir où est le problème c'est presque le résoudre
6- résister aux sirènes des bibliothèques ultra avancées : si j'ai une date à gérer, dans un très gros tableau, il n'est pas certain que la bibliothèque dates de la mort qui tue (même du standard) me serve, peut être que juste prétendre que c'est un entier...
7- quand on optimise (à la fin) procéder en deux temps. D'abord, avec un profileur, rechercher les "erreurs bêtes", les quelques instructions ou fonctions qui perdent un temps fou et qu'on peut remplacer (généralement, des fonctions haut niveau mal à propos). Ensuite, et si nécessaire, regarder les parties du programme où le temps est passé, et y réfléchir en termes d'algorithmes ou de données...
Francois
( 8- Choisir, si possible, avec qui on travaille. )
Attention, quand on parle de Java et de .Net, on ne parle pas d'interprété versus compilé. Dans les deux cas, il y a compilations en bytecode et compilation à la volée à l'exécution. Donc potentiellement lus adapté à ta machine que C/C+.
J'ajouterai que tes conseils fonctionnent pour tout langage :D
Ces langages devraient alors produire des codes plus rapides, non? ;)
Sérieusement, je ne suis pas certain qu'il y ait une telle différence entre "compilation juste à temps" (c'est à dire transformation d'un code intermédiaire en un code machine à l'exécution) et interprétation (qui veut dire, transformation d'un code en instructions machine à l'exécution).
Les bytecodes, le JIT, ou les VM c'est un raffinement des interpréteurs d'autrefois (même si des langages très anciens, comme APL ou LISP utilisaient parfois des représentations intermédiaires).
Mais ce qui fait la force des langages compilés, ca reste la capacité donnée au compilateur d'optimiser à l'avance, sur un programme complet, dans un temps non limité, et pour une machine précise, un code qu'elle exécutera directement. Je ne pense pas que ce soit "battable".
Pour tout langage compilé et d'assez bas niveau (et de bonne qualité), et sur des machines de type PC...Citation:
J'ajouterai que tes conseils fonctionnent pour tout langage :D
Dans un langage comme l'Action Script d'Adobe, la recommandation 1 est suicidaire, dans d'autres systèmes, en particulier certain langages interprétés (allez je vais reciter l'APL...) la 6 n'est pas une bonne idée.
Mais oui, l'optimisation c'est plus des principes sains que des astuces propres au langage ou au système...
Francois
en théorie, le code compilé apres profiling (profile guided optimization sous msvc, gcc et intel ont la meme chose) est ausi rapide que le code instrumentalisé et compilé par une VM mais la VM ajoute le code pour l'instrumentalisation, plus le code pour la generation de code (quelques "if"), plus la recompilation dynamique qui n'est pas gratuite.
Globalement, rien ne peut battre le C++ complètement optimisé mais une VM automatise et rend plus simple beaucoup de ces taches
enfin, moi perso j'attends toujours un programme de grande envergure avec une VM qui ne "rame" pas. car au dela de l'aspect theorique, dans la pratique, les programmes codés dans un langage de plus haut niveau ont toujours été plus lents que leurs equivalents compilés (je ne veux pas commencer un troll, il s'agit de la pratique c'est tout)
J'utilise sans vergogne dans mon projet libre les fonctionnalités de C++0x implémentées dans GCC 4.4.
Je pense que la nouvelle fonctionnalité la plus encline à accélérer le code est la sémantique de mouvement. À niveau d'abstraction égal, on se retrouve avec un code plus rapide car beaucoup de copies vont se changer en déplacements.
De plus, j'utilise désormais sans scrupule des objets (par opposition aux pointeurs nus/intelligents) pour les compositions ET pour les agrégations non-polymorphes.
J'en suis même à me demander si les collections de pointeurs servent encore à quelque chose.
Donc en ce qui me concerne, le conseil serait : implémentez le constructeur et l'assignation par mouvement !
Toutes ces affirmations sont bien entendu ouvertes au débat ;)
Je pense être dans une large mesure d'accord avec toi. La sémantique de mouvement va jouer un rôle capital. Pouvoir transférer une ressource sans mal va apporter beaucoup ! Le seul soucis est que certains vont s'emmêler les pinceaux, surtout quand ils vont jouer avec les primitives de multithreading de la bibliothèque standard de C++0X.... (il y a un bouquin qui est en train d'être écrit sur le sujet, et il utilise les lambdas et la sémantique de mouvement, j'ai peur pour ceux qui prendront std::move pour une fonction qui ne fait rien :aie:)
C'est vrai que ça s'ancre bien dans le C++ moderne cette histoire de move semantics.
Seulement quant à l'utilitasion dès maintenant y'a juste quelques petites réserves, d'un c'est pas encore très bien documenté et de deux c'est sujets à des modifications assez importante. (je crois que c'est dans un de tes topics qu'on avait parlé d'un changement ).
Oui, on avait parlé de cette histoire de « dégradation ». D'ailleurs j'aimerais bien être fixé avec assurance sur ce point.
J'utilise C++0x dès maintenant car il s'agit d'un projet libre. Les linuxiens seront les plus enclins à y contribuer dans un premier temps.
Et une fois que le projet aura atteint la maturité nécessaire à une plus large distribution, j'imagine que davantage de compilateurs auront implémenté ces fonctionnalités.
Pour un projet en entreprise, je ne me serais pas permis !
Malheureusement, je ne connais pas assez bien les membres du comité, et ma boule de crystal est en panne pour l'instant :aie:
Et je crains que ce ne soit le cas de la plupart des gens d'ici :D:dehors:
Peut être trouvera tu quelqu'un qui "a une idée plus ou moins précise" de ce qui sera en définitive décidé par le comité, mais, tant que la norme n'est pas officiellement parue, il y a effectivement risque de modifications...
Je *présumes* que, la deadline approchant, nous risquons encore de voir des décisions non finalisées être abandonnées par manque de temps pour leur intégration :aie:
Mais il y a, me semble-t-il, sur le site même du comité une liste des propositions et leur état d'intégration dans la norme...
Tu peux peut être déjà te baser sur celles qui ont été totalement intégrées ;)
Je précise que quand je dis « j'aimerais bien être fixé avec assurance sur ce point », je veux dire que j'aimerais bien savoir si le mécanisme de « dégradation » évoqué dans ce topic : http://www.developpez.net/forums/d73...antics-p-nrvo/ a bien été supprimé dans les derniers drafts.
Je suis bien conscient que le standard n'est pas finalisé et que nul ne peut prétendre savoir ce que contiendra précisément la version finale ;)
Oui, tout peut se trouver à partir de cette page : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/Citation:
Mais il y a, me semble-t-il, sur le site même du comité une liste des propositions et leur état d'intégration dans la norme...
Plus particulièrement, la liste actuellement la plus à jour est ici : http://www.open-std.org/jtc1/sc22/wg...009/n2869.html
Enfin, nous sommes légèrement hors-sujet :roll:
Le papier 2831, qui propose une solution au problème, en question a été discuté lors de la dernière réunion du comité, sachant qu'une contre proposition existe (2835). Je n'étais pas à cette réunion, New Jersey, c'est un peu loin, et il n'y a pas eu de vote sur son inclusion dans le standard. Je ne sais pas pour quelle raison. Et j'avoue ne pas trop avoir suivi ce sujet.
D'accord, cela n'est donc pas assuré non plus.
Merci pour l'info ;)