Quel conteneur pour mon problème ?

Quel conteneur pour mon problème ? - C++ - Programmation

Marsh Posté le 31-03-2010 à 15:00:51    

Salut à tous,
 
je touche chaque jour un peu plus mes lacunes, et je suis face à un problème de conception sur lequel je voudrais votre avis.
 
Je dispose d'un tableau 1D de la forme
 

Code :
  1. T * tableau[largeur*hauteur];


qui représente une image.
 
Pour chacune de ces cases, je vais faire N calculs, les calculs ne différant que par un jeu de 2 paramètres et renvoyant un seul résultat, en faisant une boucle sur N, puis une boucle sur l'image.
J'ai besoin de garder, pour chaque case de mon tableau la liste des résultats, ainsi que, pour chaque résultat, le jeu de paramètre qui l'a engendré. Quel genre de boîte serait adapté à ce problème?

Reply

Marsh Posté le 31-03-2010 à 15:00:51   

Reply

Marsh Posté le 31-03-2010 à 15:08:22    

C'est très abstrait, mais p'têt un truc du genre une structure rassemblant les paramètres + résultat, et ensuite une map associant une instance de cette structure pour chaque numéro de case sur laquelle un calcul a été effectué ?

Reply

Marsh Posté le 31-03-2010 à 17:26:26    

En gros t'as une image et tu fais des calculs sur chaque pixel dont tu veux conserver chaque résultat ?

Reply

Marsh Posté le 31-03-2010 à 17:49:41    

ca dépend aussi de la manière dont tu voudras utiliser ces résultats associés à ces paramètres.
 
Si c'est pour faire des recherches d'une case donnée régulièrement ou si c'est pour faire toujours des parcours linéaires complets de ta structure, tu vas pas faire le même choix


---------------
last.fm
Reply

Marsh Posté le 31-03-2010 à 19:59:36    

Par la suite, je ferais un parcours régulier sur toute l'image. Concernant les résultats à stocker, j'aurais besoin de faire au moins un tri sur chaque vecteur de résultat. Avant que vous me disiez que je n'ai qu'à garder le premier de chaque vecteur, je précise que je cherche justement à éviter ça.

Reply

Marsh Posté le 31-03-2010 à 20:27:11    

snafu8 a écrit :

Par la suite, je ferais un parcours régulier sur toute l'image. Concernant les résultats à stocker, j'aurais besoin de faire au moins un tri sur chaque vecteur de résultat. Avant que vous me disiez que je n'ai qu'à garder le premier de chaque vecteur, je précise que je cherche justement à éviter ça.


 
Perso vu qu'à priori il n'y a rien de sparse, que tailles sont identiques et que tu ne cherches pas à maintenir une structure triée, mais juste à trier à la fin, je ne vois pas pourquoi ne pas utiliser des vectors.
 

Code :
  1. class Result{
  2. public:
  3.   double result;
  4.   Param parameters;
  5. };
  6. class Pixel : public std::vector<Result>{
  7.   ... // représentation d'un pixel
  8. };
  9. class ImageWithResult : public std::vector<Pixel>{
  10.   // surcharge de l'operateur (i,j) pour implémenter un comportement matriciel  
  11. }


 
Et puis à la fin tu fais un std::sort(pixel.begin(), pixel.end()) pour chaque pixel.
Tu initialises avec les bonnes tailles, tu insères en temps constant au fil de tes calculs et tu tries à la fin chaque pixel en O(nlogn).

Reply

Marsh Posté le 31-03-2010 à 21:17:30    

l'heritage public de vector me fait pleurer du sang.
un héritage privé me semble de meilleur aloi vu que les classes de la stl ne sont pas conçus pour etre hériter publiquement.
 
Sinon ouais

Reply

Marsh Posté le 01-04-2010 à 10:11:00    

Joel F a écrit :

l'heritage public de vector me fait pleurer du sang.
un héritage privé me semble de meilleur aloi vu que les classes de la stl ne sont pas conçus pour etre hériter publiquement.
 
Sinon ouais


 
Comme on m'a appris comme ça en cours, je veux bien que tu développes cette aversion pour l'héritage public des std containers.
C'est parce qu'ils ne présentent pas tous la même interface ? Ou bien il y a une raison plus profonde ?
 
Je suis toujours ouvert pour m'améliorer ;-)

Reply

Marsh Posté le 01-04-2010 à 10:52:34    

Lan Wezel a écrit :


 
Comme on m'a appris comme ça en cours, je veux bien que tu développes cette aversion pour l'héritage public des std containers.
C'est parce qu'ils ne présentent pas tous la même interface ? Ou bien il y a une raison plus profonde ?
 
Je suis toujours ouvert pour m'améliorer ;-)


 
ils n'ont pas de destructeur virtuel, ca fait le premier argument lourd en défaveur d'un héritage public


---------------
last.fm
Reply

Marsh Posté le 01-04-2010 à 11:02:16    

Ok, là je veux bien qu'on m'explique le lien entre destructeur virtuel et héritage public.

Reply

Marsh Posté le 01-04-2010 à 11:02:16   

Reply

Marsh Posté le 01-04-2010 à 11:06:16    

Vu que ton image a une taille fixe, pourquoi pas un simple array de struct qui contiennent les infos dont t'as besoin ?

Reply

Marsh Posté le 01-04-2010 à 11:07:56    

Pourquoi pas, je suis pas sectaire, je cherche juste à savoir quelles sont mes options, et, vu ce que je fais, laquelle serait la plus adaptée et la plus performante.

Reply

Marsh Posté le 01-04-2010 à 11:59:46    

snafu8 a écrit :

Ok, là je veux bien qu'on m'explique le lien entre destructeur virtuel et héritage public.


l'héritage public te permet de manipuler directement ton instance sous forme de vector, sauf que, si tu détruits ton instance en la considérant comme un vecteur, tu n'appelleras pas le destructeur de ta classe.
 

Code :
  1. #include <iostream>
  2. #include <vector>
  3. struct A : public std::vector<int>
  4. {
  5. A() { std::cout << "A()" << std::endl; }
  6. ~A() { std::cout << "~A()" << std::endl; }
  7. };
  8. int main()
  9. {
  10.     std::vector<int>* a = new A;
  11. delete a;
  12.     return 0;
  13. }


 
l'execution du prog :

s@s /cygdrive/c
$ ./plop.exe
A()
 
s@s-La /cygdrive/c
$


 
CQFD : le destructeur de A n'a pas été appelé


---------------
last.fm
Reply

Marsh Posté le 01-04-2010 à 12:07:31    

theshockwave a écrit :


si tu détruits ton instance en la considérant comme un vecteur, tu n'appelleras pas le destructeur de ta classe.


 
+1
 
Je n'avais pas pensé à ce problème car quand j'hérite d'un std container, je n'utilise pas de polymorphisme sur cet héritage...
Vous m'embêtez parce j'aime bien ne pas avoir à surcharger explicitement toutes les méthodes membres des containers. Fénéant power !

Reply

Marsh Posté le 01-04-2010 à 12:37:30    

si t'aimes bien faire du caca, c'est ton choix ;)

Message cité 1 fois
Message édité par Joel F le 01-04-2010 à 12:38:23
Reply

Marsh Posté le 01-04-2010 à 12:51:03    

snafu8 a écrit :

Pourquoi pas, je suis pas sectaire, je cherche juste à savoir quelles sont mes options, et, vu ce que je fais, laquelle serait la plus adaptée et la plus performante.

Dans la mesure où la taille de ton image est fixe, que la taille des données à stocker est fixe et déterminée à l'avance, autant faire du tout fixe avec un array de structs, qui t'apportera haute performance niveau accès mémoire et la plus faible utilisation mémoire possible vu que tu stockes le strict minimum.

 

C'est tellement un cas simple et évident que je m'imagine pas utiliser autre chose, c'est carrément un exemple idéal de l'utilisation d'un array et de structs.

Message cité 1 fois
Message édité par Kenelm le 01-04-2010 à 12:52:10
Reply

Marsh Posté le 01-04-2010 à 12:52:45    

Je suis fénéant, mais je suis conscient quand je fais du caca :p.  
Enfin pour le coup du destructeur non virtuel j'y avait pas pensé. lalalala

Reply

Marsh Posté le 01-04-2010 à 13:16:38    

Joel F a écrit :

si t'aimes bien faire du caca, c'est ton choix ;)


 
Ouais enfin c'est un peu [:bidem].
Bon ceci dit ça peut arriver qu'un nigaud détruise l'instance via un ptr sur std::vector<> ou autre truc dangereux, mais bon c'est un nigaud.
 
Moi le caca, je le vois surtout dans la logique du std::vector<> par pixel :D
Surtout qu'à priori ce sera bien le même nombre de paramètres/résultat pour tous les pixels.

Message cité 1 fois
Message édité par bjone le 01-04-2010 à 13:19:00
Reply

Marsh Posté le 01-04-2010 à 13:27:44    

bah, sur un vector, je peux appeler directement std::sort(), ou std::partial_sort(), sur une struct, c'est plus chiant, il faut que je re-fasse un truc idoine.
 
Tant qu'on y est, on écrit fainéant, hein (à moins de l'être vraiment à fond  :heink: )

Reply

Marsh Posté le 01-04-2010 à 13:32:06    

Si c'est une image, pourquoi est-ce que t'aurais à appeler cette fonction ?

Reply

Marsh Posté le 01-04-2010 à 13:45:49    

Lan Wezel a écrit :


 
+1
 
Je n'avais pas pensé à ce problème car quand j'hérite d'un std container, je n'utilise pas de polymorphisme sur cet héritage...
Vous m'embêtez parce j'aime bien ne pas avoir à surcharger explicitement toutes les méthodes membres des containers. Fénéant power !


 
En cas d'héritage privé, tu n'as pas besoin de les surcharger. Tu peux juste publier l'interface qui te convient, et ca prend pas beaucoup de temps, en général


---------------
last.fm
Reply

Marsh Posté le 01-04-2010 à 14:31:50    

Citation :


Tant qu'on y est, on écrit fainéant, hein (à moins de l'être vraiment à fond  :heink: )


Oups   :sweat:  
 

Citation :


Si c'est une image, pourquoi est-ce que t'aurais à appeler cette fonction ?


Le but est pas de l'appeler sur l'image mais sur chaque vector d'expérience si je ne m'abuse.

Reply

Marsh Posté le 01-04-2010 à 16:02:47    

Kenelm a écrit :

Dans la mesure où la taille de ton image est fixe, que la taille des données à stocker est fixe et déterminée à l'avance, autant faire du tout fixe avec un array de structs, qui t'apportera haute performance niveau accès mémoire et la plus faible utilisation mémoire possible vu que tu stockes le strict minimum.


 
BLABLA, std::vector à genre 0.1% d'overhead sur [] versus du pointeur crados, stop le FUD là

Reply

Marsh Posté le 01-04-2010 à 16:04:05    

bjone a écrit :


Ouais enfin c'est un peu [:bidem].
Bon ceci dit ça peut arriver qu'un nigaud détruise l'instance via un ptr sur std::vector<> ou autre truc dangereux, mais bon c'est un nigaud.


 
Je préfére faire le casse burne que laissez passser ça pour en voir 34567890 partotu aprés.
J'ai mon image de  [:joel f:1] à conserver moi monsieur.
 

bjone a écrit :


Moi le caca, je le vois surtout dans la logique du std::vector<> par pixel :D
Surtout qu'à priori ce sera bien le même nombre de paramètres/résultat pour tous les pixels.


 
Deja un boost::multi_array me parait mieux pour l'aspect 2D, donc un truc genre
 
boost::multi_array< boost::array<float,N> >  
 
est peut etre pas mal

Reply

Marsh Posté le 01-04-2010 à 16:16:29    

Citation :

Kenelm a écrit :

Citation :


Dans la mesure où la taille de ton image est fixe, que la taille des données à stocker est fixe et déterminée à l'avance, autant faire du tout fixe avec un array de structs, qui t'apportera haute performance niveau accès mémoire et la plus faible utilisation mémoire possible vu que tu stockes le strict minimum.


 
 
BLABLA, std::vector à genre 0.1% d'overhead sur [] versus du pointeur crados, stop le FUD là


 
Bah nan attends, je stockes 300 000+ octets, je peux pas me permettre de prendre 3 pointeurs en plus pour faire un std::vector
 

Citation :

Deja un boost::multi_array me parait mieux pour l'aspect 2D, donc un truc genre
boost::multi_array< boost::array<float,N> >  
est peut etre pas mal


 
Je vais regarder mais ca me ferais mal que tu gagnes et que tu me fasses faire du boost:: (mauvaise foi inside). Ou alors la prochaine fois que tu passes, tu m'installes boost comme ça j'aurais plus d'excuses...

Reply

Marsh Posté le 01-04-2010 à 16:21:14    

lol arrete:
 
./bootstrap.sh && sudo make install :o

Reply

Marsh Posté le 01-04-2010 à 16:26:04    

Mais quand je tape ça dans Word, y'a rien qui se passe :(

Reply

Marsh Posté le 01-04-2010 à 16:27:39    

snafu8 a écrit :

Mais quand je tape ça dans Word, y'a rien qui se passe :(


 :lol:

Reply

Marsh Posté le 02-04-2010 à 10:29:56    

Joel F a écrit :

BLABLA, std::vector à genre 0.1% d'overhead sur [] versus du pointeur crados, stop le FUD là

Ce genre de chose fait vite une différence sur des larges volumes de données. Et du pointeur crados... aucune différence, le seul truc avec std::vector c'est que c'est aussi crado mais tu le vois pas.

Reply

Marsh Posté le 02-04-2010 à 11:06:08    

Kenelm a écrit :

Ce genre de chose fait vite une différence sur des larges volumes de données. Et du pointeur crados... aucune différence, le seul truc avec std::vector c'est que c'est aussi crado mais tu le vois pas.


 
don't feed the troll.
 
Sinon, t'as des benchs significatifs sur tes "larges volumes de données" (et là, je demande des benchs avec les checks sur les itérateurs et dimensions désactivés) ?
 


---------------
last.fm
Reply

Marsh Posté le 02-04-2010 à 11:17:19    

J'aurais plus fait un truc du genre :

Code :
  1. typedef int result_type;
  2. typedef int param_type;
  3.  
  4. struct computation {
  5.   param_type param1;
  6.   param_type param2;
  7.   std::vector<result_type> result_for_all_pixels; // taille = x*y
  8. };
  9.  
  10. struct computations {
  11.   std::vector<computation> all_results; // taille = N
  12. };


Je préfère avoir N vecteurs de x*y éléments que x*y vecteurs de N éléments, surtout que tu va itérer sur les x*y élements d'un seul set de paramètre quand tu fais ton calcul (donc autant te balader dans un seul tableau linéairement et ne pas fatiguer le cache).

 

[edit]
J'avais pas vu l'histoire du tri sur le vecteur de résultats [:prozac] Ça casse un peu l'histoire du cache, quoique si N est pas trop grand et avec un truc genre merge sort mais avec chaque phase du merge qui tourne sur tout le tableau, ça peut super bien passer en fait...


Message édité par 0x90 le 02-04-2010 à 11:33:20

---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Marsh Posté le 02-04-2010 à 13:08:41    

theshockwave a écrit :

Sinon, t'as des benchs significatifs sur tes "larges volumes de données" (et là, je demande des benchs avec les checks sur les itérateurs et dimensions désactivés) ?

J'ai fait pas mal d'assembleur, et j'ai souvent rencontré ce genre de problème. Et il est tout à fait logique qu'une commande qui prend plus de cycles d'horloge, bien que l'augmentation soit insignifiante, engendre une différence de plus en plus notable avec l'augmentation des itérations. Je vois même pas pourquoi je me casse le cul à expliquer ça d'ailleurs, c'est un fait très largement connu. Tout dépend derrière de la puissance disponible, de ce que tu cherches à faire... mais il y a clairement une différence.

 

Quoi qu'il en soit, si tu penses que tu peux faire plus rapide qu'un accès direct à la mémoire... ben écoute j'attends tes benchs.

Message cité 2 fois
Message édité par Kenelm le 02-04-2010 à 13:09:48
Reply

Marsh Posté le 02-04-2010 à 13:10:18    

Kenelm a écrit :

J'ai fait pas mal d'assembleur, et j'ai souvent rencontré ce genre de problème. Et il est tout à fait logique qu'une commande qui prend plus de cycles d'horloge, bien que l'augmentation soit insignifiante, engendre une différence de plus en plus notable avec l'augmentation des itérations. Je vois même pas pourquoi je me casse le cul à expliquer ça d'ailleurs, c'est un fait très largement connu. Tout dépend derrière de la puissance disponible, de ce que tu cherches à faire... mais il y a clairement une différence.
 
Quoi qu'il en soit, si tu penses que tu peux faire plus rapide qu'un accès direct à la mémoire... ben écoute j'attends tes benchs.


 
Ben un accès préfetché à la mémoire [:spamafote]


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Marsh Posté le 02-04-2010 à 13:29:09    

Kenelm a écrit :

J'ai fait pas mal d'assembleur, et j'ai souvent rencontré ce genre de problème. Et il est tout à fait logique qu'une commande qui prend plus de cycles d'horloge, bien que l'augmentation soit insignifiante, engendre une différence de plus en plus notable avec l'augmentation des itérations. Je vois même pas pourquoi je me casse le cul à expliquer ça d'ailleurs, c'est un fait très largement connu. Tout dépend derrière de la puissance disponible, de ce que tu cherches à faire... mais il y a clairement une différence.


 
Sauf que quand tes volumes de données deviennent grand, c'ets les c ache misses puis les tlb misses qui vont devenir préponderant devant le cycle et demi d'indirection d'adresse.
 
Et si t'en ai encore à te toucher la nouille à faire de l'assembleur, j'ai une mauvaise nouvelle pour toi, les compilos font mieux que toi depuis bientot 5 ans.
 
alors,on est en C++, donc on utilise vector, multi_array et conseour. Sinon, t'as la catégorie C à coté. Merci d'être passé.
 

Spoiler :

:o vendredi toussa

Reply

Marsh Posté le 02-04-2010 à 14:10:41    

Joel F a écrit :

Sauf que quand tes volumes de données deviennent grand, c'ets les c ache misses puis les tlb misses qui vont devenir préponderant devant le cycle et demi d'indirection d'adresse.

Si c'est mal codé, forcément...
 

Joel F a écrit :

Et si t'en ai encore à te toucher la nouille à faire de l'assembleur, j'ai une mauvaise nouvelle pour toi, les compilos font mieux que toi depuis bientot 5 ans.

Un compilateur va plus vite, mais j'ai encore du mal à trouver un compilateur qui fasse mieux qu'un être humain. Coder des goulots d'engorgement à la main peut faire gagner des grosses perfs. On gagne toujours à concevoir ses propres solutions.
 

Joel F a écrit :

alors,on est en C++, donc on utilise vector, multi_array et conseour. Sinon, t'as la catégorie C à coté. Merci d'être passé.

Me semble que la question de base c'était "c'est quoi le mieux ?" :o
Et vu l'époque à laquelle on vit, j'ai de plus en plus de mal à comprendre le sectarisme C/C++.
 

Joel F a écrit :

Spoiler :

:o vendredi toussa


Excuse rejetée :o

Reply

Marsh Posté le 02-04-2010 à 14:20:51    

Euh, on est bien entrain de parler de operator[] sur un vector versus operator[] sur de la mémoire là ? Genre le truc ou le code du premier est exactement le même que le second ? Le truc ou il faut vraiment insister et désactiver les variables d'induction et l'inlining pour que ça fasse une différence une fois compilé ?


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Marsh Posté le 02-04-2010 à 14:55:24    

0x90 a écrit :

Euh, on est bien entrain de parler de operator[] sur un vector versus operator[] sur de la mémoire là ? Genre le truc ou le code du premier est exactement le même que le second ? Le truc ou il faut vraiment insister et désactiver les variables d'induction et l'inlining pour que ça fasse une différence une fois compilé ?


 
je plussoie, le code généré avec optimisation du compilo est identique, d'où mon insistance pour les benchs, je ne sais pas d'où sortiraient ces miraculeuses instructions supplémentaires


---------------
last.fm
Reply

Marsh Posté le 02-04-2010 à 14:56:25    

theshockwave a écrit :


 
je plussoie, le code généré avec optimisation du compilo est identique, d'où mon insistance pour les benchs, je ne sais pas d'où sortiraient ces miraculeuses instructions supplémentaires


 
du vilain compilo c++ qui fait qu'a faire du code lent bien évidemment :o

Reply

Marsh Posté le 02-04-2010 à 14:57:33    

Kenelm a écrit :

Si c'est mal codé, forcément...


5% des gens savent ce qu'ai une TLB et 1% un cache. A part qqs experts, tout le monde code mal selon toi ?
 

Kenelm a écrit :

Un compilateur va plus vite, mais j'ai encore du mal à trouver un compilateur qui fasse mieux qu'un être humain. Coder des goulots d'engorgement à la main peut faire gagner des grosses perfs. On gagne toujours à concevoir ses propres solutions.


je te parlais de micro optimisation à la ouanagéne.
 

Kenelm a écrit :

Me semble que la question de base c'était "c'est quoi le mieux ?" :o
Et vu l'époque à laquelle on vit, j'ai de plus en plus de mal à comprendre le sectarisme C/C++.


Le C, c'ets 1492, le C++ c'ets 2011 c'est tout.

Reply

Marsh Posté le 02-04-2010 à 15:25:58    

Joel F a écrit :

5% des gens savent ce qu'ai une TLB et 1% un cache. A part qqs experts, tout le monde code mal selon toi ?

Si on peut faire mieux, c'est que c'est mal foutu, non ?

Joel F a écrit :

je te parlais de micro optimisation à la ouanagéne.

Ah bah oui je me doute bien, mais moi aussi je parle d'optimisation :o
J'ai autre chose à foutre que coder des applis complètes en assembleur :o

Joel F a écrit :

Le C, c'ets 1492, le C++ c'ets 2011 c'est tout.

Ça sera 1492 le jour où on sera pas obligé de passer par le C pour gagner en perfs :miam:

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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