Enfin merci beaucoup Ehonn il faudra activer les optimisations :ccool:
Version imprimable
Enfin merci beaucoup Ehonn il faudra activer les optimisations :ccool:
Bonjour,
Vis à vis des grosses différences de performance, et vu que tu sembles utiliser Visual Studio 2010, j'ai peut-être une idée du problème.
Dans la configuration par défaut du mode Debug, il y a l'option "Basic Runtime Check" (dans les options de compilation C/C++ => Code Generation) qui semble ralentir énormément les objets de type class quand il n'est pas mis sur Default.
J'ai remarqué ça quand j'ai fait un simple wrapper autour de l'API random du système (méthode Rand() qui appel la fonction rand() du système). En mode Release, les temps étaient sensiblement semblable, mais en Debug, ils étaient juste beaucoup trop éloignés.
Sans l'option de compilation modifiée : API C : 16s, wrapper class : 25s
Avec l'option de compilation modifiée : API C : 17s, wrapper class : 19s
Et sinon vu qu'on travaille en taille fixe, on peut aller chercher std::array dans C++11 ou Boost.
J'ai éxécuter une partie du code la ou le problème ce pose, sans changer cette option de compilation j'ai eu les résultats suivant
Allocation dynamique: 14 s; class std::vector 97 s
En changeant cette option
Allocation dynamique: 14 s; class std::vector 52 s
en activant de plus les optimisation (/O2; /Ot)
Allocation dynamique: 13 s; class std::vector 30 s
En faisant l'éxécution du programme en entier avec des données de taille moyenne (n=30) avec activation des optimisations (/O2, /Ot) mettre l'option 'Basic Runtime Checks' à 'Default' et l'option 'Debug Information format' à 'C7 compatible (/Z7)' car /ZI n'est pas compatible avec /O2, j'ai eu les résultats suivants:
Allocation dynamique
Debug:76s ; Release:33s
std::Vector
Debug:175s ; Release:32s
Donc voilà, il faudra exécuter en mode Release :ccool: ; reste à voir C++11 :roll:
+1000
Ceci aussi aide un peu à retirer des casseroles inutiles sous VS:
_SECURE_SCL=0
J'use et abuse de std::vector<> dans mes prg.
Je n'ai jamais fait de resize() et n'ai jamais initialisé un vector à une taille donnée, la plupart du temps c'est inutile et contreproductif.
Par contre les méthodes reserve() et capacity() sont utiles et importantes.
Voici un exemple de bon usage:
Voici un exemple catastrophique :aie:Code:
1
2
3
4 std::vector<int> v; v.reserve(1000); for (int i=0; i<1000; ++i) v.push_back(i);
Code:
1
2
3
4
5
6 std::vector<int> v; for (int i=0; i<1000; ++i) { v.reserve(v.capacity()+1); v.push_back(i); }
Dans le traitement d'image, tu connais la taille de l'image avant de déclarer ton vector donc tu peux l'initialiser directement à la bonne taille. Tu ne peux pas utiliser std::array (ou un tableau à la C) car cette taille n'est connu qu'à l'exécution (et que tu ne peux pas t'assurer que ton image tienne dans la pile). Utiliser reserve ici serait inutile et contre productif.
Pour ton exemple, je pense que ceci est plus rapide si l'initialisation est plus rapide que le surcoût dû au push_back (même sans réallocation) (à tester) (mais c'est pas toujours possible j'en conviens).
Code:
1
2
3
4
5 std::vector<int> v(1000); for (std::size_t i = 0; i < v.size(); ++i) { v[i] = i; }
Le traitement d'image ne fait pas exception.
As-tu une quelconque utilité à initialiser les élément de ton vector à une valeur donnée ? Je n'en ai jamais eu besoin en faisait du traitement d'image.
Le vector sert à stocker les pixels, on sait combien on veut en stocker, initialiser notre stockage par un pixel/une couleur par défaut à chaque emplacement/pixel ne sert à rien. On réserve la taille nécessaire, puis on lit/écrit/stocke chacun des pixels.
Etant donné l'appel au constructeur par défaut *1000 avant, non.Code:
1
2
3
4
5 std::vector<int> v(1000); for (std::size_t i = 0; i < v.size(); ++i) { v[i] = i; }
Le push_back ne coûte rien tant qu'il ne doit pas faire une réallocation.
L'opérateur[] utilise le constructeur par copie, tout comme le push_back.
Je trouve qu'il est plus simple (et plus court) d'utiliser la size du vector.
push_back fait un if que operator[] ne fait pas, l'operator[] est donc potentiellement plus rapide.
Il me semble qu'on est assez souvent amené à devoir utiliser des bibliothèques C, auquel cas on est obligé de faire un resize pour à la fois allouer la mémoire et dire au std::vector qu'il contient quelque chose. Même si l'initialisation des valeurs est effectivement inutile dans ce cas.
Salut,Ben, j'ai presque envie de dire que, dans ce cas là, on disposer d'un constructeur particulièrement sympa...
Au sortir d'une bibliothèque C, on aura sans doute soit un char * soit un void * (soit même un UnType * qui correspond à la structure C en question), mais on aura, aussi, une indication du nombre d'éléments que l'on doit s'attendre à y trouver.
Une fois la conversion (si nécessaire) effectuée du char * ou en void * en un UnType*, tu devrait pouvoir utiliser le constructeur prenant les deux itérateurs, sous la forme de
Il me sembleque ce constructeur commence par calculer la taille requise (std::distance) et par faire un reserve avant de faire l'équivalent d'un grand memcpy global ;)Code:std::vector<UnType> tab(ptr, ptr+size);
je pense qu'en parlant de retour par copie il parle de ce sujet
http://stackoverflow.com/questions/1...nt-copy-values
http://en.wikipedia.org/wiki/Return_value_optimization
cela peut couter cher un retour par copie ou pas…
Cela peut aussi coûter moins cher :
Want speed ? Pass by value