Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1188 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  std::vector et performance

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

std::vector et performance

n°2014227
ilelle
Posté le 04-08-2010 à 16:18:24  profilanswer
 

Bonjour tout le monde,
 
Je suis entrain d'écrire un programme en c++ qui manipule un grand nombre de donnée, j'utilise std::vector pour insérer et supprimer les donnée dynamiquement , mais malheureusement le temps d'exécution et trop lent.
 
Est ce que quelqu'un connais une autre méthode autre que les stl pour améliorer le temps d'exécution ?
 
Merci d'avance

mood
Publicité
Posté le 04-08-2010 à 16:18:24  profilanswer
 

n°2014236
Un Program​meur
Posté le 04-08-2010 à 16:38:36  profilanswer
 

- std::vector n'est pas fait pour avoir des insertions/effacement ailleurs que pour le dernier elements efficacement
- std::deque le permet en tete et en queue
- std::list n'importe ou
 
A part ces generalites, tu donnes tellement peu d'information que t'aiguiller est difficile.


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2014244
ilelle
Posté le 04-08-2010 à 16:56:28  profilanswer
 

Merci  un programmeur pour votre réponse, si j'ai bien compris, en utilisant std::list l'insertion et la suppression des données ira plus vite ^^
 
PS:  j'essaye d'épargner les détailles  et donner juste l'essentiel ^^

n°2014266
gelatine_v​elue
Posté le 04-08-2010 à 17:52:17  profilanswer
 

ilelle a écrit :

Merci  un programmeur pour votre réponse, si j'ai bien compris, en utilisant std::list l'insertion et la suppression des données ira plus vite ^^
 
PS:  j'essaye d'épargner les détailles  et donner juste l'essentiel ^^


 
Si les perfs sont vraiment importantes, il est bien souvent plus performant de coder soi même sa classe comportant moins de fonctionnalités mais n'exécutant que le code nécessaire.

n°2014272
Un Program​meur
Posté le 04-08-2010 à 18:02:28  profilanswer
 

gelatine_velue a écrit :

Si les perfs sont vraiment importantes, il est bien souvent plus performant de coder soi même sa classe comportant moins de fonctionnalités mais n'exécutant que le code nécessaire.


 
Souvent?  Pas d'accord.  Je l'ai deja fait mais c'est quand meme relativement peu frequent (et plus souvent pour des questions d'occupation memoire que de rapidite d'ailleurs).


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2014293
ilelle
Posté le 04-08-2010 à 19:36:46  profilanswer
 

Voila je viens de tester le code avec std::list mais le temps est encore plus long !!  
 
existe t il une autre solution ?

n°2014295
Joel F
Real men use unique_ptr
Posté le 04-08-2010 à 19:54:22  profilanswer
 

vector::reserve par burst popur préallouer la mémoire de std::vector

n°2014296
el muchach​o
Comfortably Numb
Posté le 04-08-2010 à 20:05:06  profilanswer
 

ilelle a écrit :

Voila je viens de tester le code avec std::list mais le temps est encore plus long !!

 

existe t il une autre solution ?


Tu ne dis pas ce que tu fais. Montre du code et dis quelle est la taille de ton vecteur, combien tu insères et tu supprimes chaque seconde, quel est ton hardware, combien de RAM tu as, etc.


Message édité par el muchacho le 04-08-2010 à 20:22:59

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°2014300
ilelle
Posté le 04-08-2010 à 20:35:11  profilanswer
 

@ el muchacho : le code est tellement grand que je ne peux pas le mettre

n°2014303
el muchach​o
Comfortably Numb
Posté le 04-08-2010 à 20:48:13  profilanswer
 

Tu peux pas le réduire au minimum ? En tout cas ça m'étonnerait que ce soit la STL qui soit limitante.
Je viens de faire un test sur mon Core2Duo à 2,13GHz.
std::deque.push_front de 5 000 000 d'int: 281 ms
std::deque.pop_front de 5 000 000 d'int: 17 ms
std::list.push_front de 5 000 000 d'int: 998ms
std::list.pop_front de 5 000 000 d'int: 1130ms


Message édité par el muchacho le 04-08-2010 à 20:57:51

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
mood
Publicité
Posté le 04-08-2010 à 20:48:13  profilanswer
 

n°2014362
gelatine_v​elue
Posté le 05-08-2010 à 09:32:28  profilanswer
 

ilelle a écrit :

@ el muchacho : le code est tellement grand que je ne peux pas le mettre


 
Il serait pertinent que tu donnes la partie du code qui lit et insère les données, et que tu donnes une idée de l avolumétrie des données (nombre/taille).

n°2014379
Xavier_OM
Monarchiste régicide (fr quoi)
Posté le 05-08-2010 à 10:13:09  profilanswer
 

ilelle a écrit :

Bonjour tout le monde,
 
Je suis entrain d'écrire un programme en c++ qui manipule un grand nombre de donnée, j'utilise std::vector pour insérer et supprimer les donnée dynamiquement , mais malheureusement le temps d'exécution et trop lent.
 
Est ce que quelqu'un connais une autre méthode autre que les stl pour améliorer le temps d'exécution ?
 
Merci d'avance


 
D'abord faire tourner un profiler, ça mettra en avant le point faible du code. Il y a pas mal de chances que ça ne soit pas la STL la responsable mais la façon dont tu t'en sers (ou un bout de code purement à toi). Si jamais le profiler indique que c'est vraiment la STL, reviens ici en causer :)


---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
n°2014429
ilelle
Posté le 05-08-2010 à 12:15:18  profilanswer
 

En fait j'ai une matrice de 64800*100 pour chaque élément cells[k][i] de la matrice un tableau lui est associé et à chaque appel de la fonction "Loader::ajour" je cherche dans tout les tableaux si "numFace" (un entier) existe alors je l'écrase.  
Voici la fonction où mon problème ce génère :  
 

Code :
  1. void Loader::ajour(int numface)
  2. {
  3. for(int i=0; i < 64800; i++){
  4.  for(int k = 0; k < 100; k++){
  5.   if(cells[k][i].active == false) continue;
  6.    //Contribution
  7.    int j = 0;
  8.    while(j < cells[k][i].listContribution.size())
  9.    {
  10.     if(cells[k][i].listContribution[j].numFace == numface)
  11.     {
  12.      cells[k][i].densite -= cells[k][i].listContribution[j].area;
  13.      cells[k][i].listContribution.erase(cells[k][i].listContribution.begin()+j);
  14.     }
  15.     else{ j ++; }
  16.    }
  17.    //Penalité
  18.    j = 0;
  19.    while(j < cells[k][i].listPenalite.size())
  20.    {
  21.     if(cells[k][i].listPenalite[j].numFace == numface)
  22.     {
  23.      cells[k][i].densite += pFactor*cells[k][i].listPenalite[j].area;
  24.      cells[k][i].listPenalite.erase(cells[k][i].listPenalite.begin()+j);
  25.     }
  26.     else { j ++; }
  27.    }
  28.   // désactivation de la cellule
  29.   if(cells[k][i].listContribution.size() == 0) cells[k][i].active = false;
  30.  }
  31. }
  32. }

n°2014481
gelatine_v​elue
Posté le 05-08-2010 à 14:27:18  profilanswer
 

Je crois que ça n'a pas de sens de mettre les j++ dans le else.
 
A part ce détail je ne vois pas les types des collections que tu utilises:
 
- pour cells
- pour listContribution
- pour listPenalites.

n°2014542
ilelle
Posté le 05-08-2010 à 16:00:33  profilanswer
 

@ gelatine_velue j'utilise j++ dans un else pour éviter de sauter un élément (exemple : si j'efface l'élément qui se trouve dans la position j = 3 l'élément qui se trouve dans j = 4 prend sa place du coup si je ne met pas j++ dans un else je ne test jamais l'élément qui se trouvait dans la position j = 4)
pour les types :
struct CELL  
{
 float densite;
 bool active;
 listFace listContribution;
 listFace listPenalite;
 CELL(){  
  densite = 0.0;
  active = false;
 }
};
struct ContrPenal
{
 int numFace;
 float area;
};
 
typedef vector <ContrPenal> listFace;

n°2014548
gelatine_v​elue
Posté le 05-08-2010 à 16:12:59  profilanswer
 

Ok merci de ces précisions je crois qu'on a ce qu'il faut pour se pencher sur ton cas :)
 
Je regarderai ce soir chez moi (peux pas faire de C++ la tt de suite)

n°2014551
ilelle
Posté le 05-08-2010 à 16:16:53  profilanswer
 

Merci infiniment

n°2014563
Un Program​meur
Posté le 05-08-2010 à 16:28:03  profilanswer
 

Elles font quelle taille tes listFace?
 
Est-ce que l'ordre y est important?


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2014572
Joel F
Real men use unique_ptr
Posté le 05-08-2010 à 16:39:13  profilanswer
 

On apprend plus ce qu'est un cache dans les écoles:
 
 for(int i=0; i < 64800; i++){
 for(int k = 0; k < 100; k++){
  if(cells[k][i].active == false) continue;
 
change tes cell[k][i) en cell[i][k] et tu evitera de faire des accés avec des strides de 64800 elements par lignes de caches ...

n°2014592
ilelle
Posté le 05-08-2010 à 17:20:07  profilanswer
 

@ Un Programmeur : les listFace sont dynamique  je ne connais pas leur taille au préalable

n°2014594
Xavier_OM
Monarchiste régicide (fr quoi)
Posté le 05-08-2010 à 17:22:56  profilanswer
 

Joel F a écrit :

On apprend plus ce qu'est un cache dans les écoles:

 

for(int i=0; i < 64800; i++){
 for(int k = 0; k < 100; k++){
  if(cells[k][i].active == false) continue;

 

change tes cell[k][i) en cell[i][k] et tu evitera de faire des accés avec des strides de 64800 elements par lignes de caches ...

 


Yep.

 

ilelle tu ne dois pas oublier qu'en interne ton tableau est à une dimension, ton
    cells[row][col]
est un accès dans un tableau à une dimension, à la case
    col + row * maxcols

 

En faisant cells[k][i] à chaque k++ tu avances violemment dans ce tableau à une dimension
En faisant cells[i][k] à chaque k++ tu avances juste jusqu'au prochain 'word' en mémoire.

 

Le 2ème cas est beaucoup plus intéressant pour toi car les données sont déjà en cache prêtes à l'emploi.
Dans le 1er cas des données sont mises en cache pour rien, vu qu'à chaque itération tu vas voir ailleurs (bien trop loin)

 

Je sais pas si je suis clair.
edit : http://igoro.com/archive/gallery-o [...] e-effects/


Message édité par Xavier_OM le 05-08-2010 à 17:58:23

---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
n°2014598
Un Program​meur
Posté le 05-08-2010 à 17:39:35  profilanswer
 

ilelle a écrit :

@ Un Programmeur : les listFace sont dynamique  je ne connais pas leur taille au préalable


 
Meme si elles sont dynamiques, tu dois avoir une idee du nombre d'elements possibles dedans


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2014601
ilelle
Posté le 05-08-2010 à 17:43:46  profilanswer
 

@ Xavier_OM et Joel F : je vient de faire le test avec cells[i][k] au lieu de cells[k][i] mais le résultat est le même  

n°2014602
ilelle
Posté le 05-08-2010 à 17:45:33  profilanswer
 

@ Un Programmeur : ah d'accord pour le nombre max c'est 21000

n°2014630
el muchach​o
Comfortably Numb
Posté le 05-08-2010 à 20:47:38  profilanswer
 

ilelle a écrit :

@ Xavier_OM et Joel F : je vient de faire le test avec cells[i][k] au lieu de cells[k][i] mais le résultat est le même  


Si je ne m'abuse cells[i][k] est un invariant de ta double boucle externe. Je pense que la moindre des choses est d'utiliser un pointeur dessus, histoire de pas avoir à faire le calcul d'adressage 15000 fois comme tu le fais ici. Certains me diront p-ê  que le compilateur sait faire ça quand il optimise (au fait, as-tu mis toutes les options d'optimisation ?), mais au moins c'est plus lisible.

 

Donc dans ta double boucle, tu mets un
Cell *cell = &cells[i][k];
et ensuite tu accèdes à tout avec ->
 
Ensuite listContribution et listPenalite, c'est quoi comme structure de donnée ?
Tu as un soucis parce que ton algo fait à la fois de l'accès direct ET de la suppression sur ces structures. Or il n'y a pas de structure simple performante dans ces deux secteurs à la fois, à part un arbre AVL ou red-black (std::map ou std::set ou Boost). Si le test (cell.listPenalite[j].numFace == numface) est souvent positif, tu as pratiquement du O(n), et tu as intérêt à passer sur une structure d'arbre. Si ce test est rarement positif, tu as intérêt à garder un vector, surtout si leur taille n'est pas trop grande.
Mais de toute façon, ici je pense que tu devrais utiliser un iterator plutôt que j++ (s'il est pas invalidé par erase), voire à modifier ton algo, p-ê en mettant un booleen que tu testes plutôt que de faire un erase, par ex.

 

Xavier_OM: merci pour cette page [:bien]

Message cité 1 fois
Message édité par el muchacho le 06-08-2010 à 07:40:54

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°2014700
gelatine_v​elue
Posté le 06-08-2010 à 10:04:17  profilanswer
 

el muchacho a écrit :


Si je ne m'abuse cells[i][k] est un invariant de ta double boucle externe. Je pense que la moindre des choses est d'utiliser un pointeur dessus, histoire de pas avoir à faire le calcul d'adressage 15000 fois comme tu le fais ici. Certains me diront p-ê  que le compilateur sait faire ça quand il optimise (au fait, as-tu mis toutes les options d'optimisation ?), mais au moins c'est plus lisible.
 
Donc dans ta double boucle, tu mets un  
Cell *cell = &cells[i][k];
et ensuite tu accèdes à tout avec ->
 
Ensuite listContribution et listPenalite, c'est quoi comme structure de donnée ?  
Tu as un soucis parce que ton algo fait à la fois de l'accès direct ET de la suppression sur ces structures. Or il n'y a pas de structure simple performante dans ces deux secteurs à la fois, à part un arbre AVL ou red-black (std::map ou std::set ou Boost). Si le test (cell.listPenalite[j].numFace == numface) est souvent positif, tu as pratiquement du O(n), et tu as intérêt à passer sur une structure d'arbre. Si ce test est rarement positif, tu as intérêt à garder un vector, surtout si leur taille n'est pas trop grande.
Mais de toute façon, ici je pense que tu devrais utiliser un iterator plutôt que j++ (s'il est pas invalidé par erase), voire à modifier ton algo, p-ê en mettant un booleen que tu testes plutôt que de faire un erase, par ex.
 
Xavier_OM: merci pour cette page [:bien]


 
Pas mieux.

n°2014748
Riot
Buy me a riot
Posté le 06-08-2010 à 10:55:14  profilanswer
 

Très intéressant ton lien, Xavier_OM :jap:


---------------
Be the one with the flames.
n°2014751
Joel F
Real men use unique_ptr
Posté le 06-08-2010 à 10:56:38  profilanswer
 

il serait parfait si il comptait en cycle/element et non en temps/element :ð

n°2014837
Xavier_OM
Monarchiste régicide (fr quoi)
Posté le 06-08-2010 à 14:16:12  profilanswer
 

de rien les gens  :o


---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
n°2015018
el muchach​o
Comfortably Numb
Posté le 06-08-2010 à 19:29:07  profilanswer
 


Ce qu'il y a de bien, c'est les gens qui disent "j'ai un pb" mais à qui il faut tirer les vers du nez pour obtenir la moindre information pertinente, et puis qui disparaissent sans dire merci quand on prend la peine de leur fournir une réponse un tant soit peu argumentée. :sarcastic:


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°2015031
ilelle
Posté le 06-08-2010 à 20:03:31  profilanswer
 

@ el muchacho je n'ai pas disparu mais justement j'était entrain d'essayer les différentes solution que vous m'avez proposé, et d'ailleurs j'ai ouvert ce forum pour remercier toute personne  qui a contribué à résoudre mon problème (je suis pas ingrate comme même) grâce à vous (tout particulièrement les solutions de : Joel F, el muchacho, Xavier_OM) j'ai pu diminuer le temps d'exécution même s'il reste comme un peut long
Merci encore à toutes et à tous

n°2015068
el muchach​o
Comfortably Numb
Posté le 07-08-2010 à 05:07:25  profilanswer
 

J'ai deux ruses qui peuvent aider si tu gardes un vector pour listPenalite et listContribution:

 

1. parcourir le vector dans le sens end() -> begin(): si tu supprimes bcp d'éléments, ça fait déjà ça en moins à déplacer en mémoire à chaque fois. Encore une fois, c'est à comparer avec des structures d'arbre.

 

2. si l'ordre des éléments dans  listPenalite  n'a pas d'importance, tu appliques 1 et tu remplaces chaque élément à supprimer par le dernier élément du tableau et tu supprimes ce dernier.
  std::swap(listPenalite[j], listPenalite.back());
  listPenalite.pop_back();
Tu perds l'ordre du tableau, mais tu auras par contre une performance optimale.

 

(au passage, ça devrait marcher aussi en Java et en C#)


Message édité par el muchacho le 07-08-2010 à 08:59:23

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°2015076
ilelle
Posté le 07-08-2010 à 11:32:01  profilanswer
 

Merci el muchacho je vais essayer cette solution et je vous rends la réponse

n°2015077
el muchach​o
Comfortably Numb
Posté le 07-08-2010 à 11:37:35  profilanswer
 

Je pense que les intervenants seraient intéressés par le gain cumulé par chacune des améliorations proposées, pas juste une réponse binaire du style "c'est mieux" ou "c'est pas mieux". Mesurer est la base de l'optimisation.


Message édité par el muchacho le 07-08-2010 à 11:38:33

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°2015082
ilelle
Posté le 07-08-2010 à 12:42:09  profilanswer
 

Alors voila :
pour une itération de 62 qui fait appel à la fonction ajour j'aurai un temps d'exécution de 18563 ms.  
 

n°2015142
el muchach​o
Comfortably Numb
Posté le 07-08-2010 à 21:42:44  profilanswer
 

Par pitié, et par respect pour tes interlocuteurs, ne donne pas "juste l'essentiel" comme tu dis, mais élabore un minimum tes réponses.

 

62, ça veut dire quoi ? C'est la valeur de numFace ?
Et ça prenait combien de temps (à peu près) avant les optims ? Quelles optims as-tu implémentées ?
Au final, vu la teneur de ta réponse, on ne sait tjrs pas si la durée actuelle est satisfaisante ou pas. J'ai répondu à tes questions, merci de répondre au miennes. C'est le minimum que l'on peut attendre.


Message édité par el muchacho le 07-08-2010 à 22:25:13

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°2015165
ilelle
Posté le 07-08-2010 à 23:41:34  profilanswer
 

Je suis vraiment désolée de vous avoir dérangé et surtout mal exprimé( en fin j'ai l'habitude de ne pas trop parler  :whistle:  )  
bon 62 c'est le nombre d'appel de la fonction ajour avec un numFace quelqu'on que.
 
Je vient de changer l'insertion des données dans listContribution et listPenalite d'une façon que les données seront trié et j'ai changé le code de la fonction ajour comme suit :
void Loader::ajour(int numface)
{
 for(int k = minRho; k < maxRho; k++){
  for(int i=0; i < gridSize; i++){
   CELL *cell = &cells[i][k];
   
   if(cell->active == false) continue;
 
    int j = 0;
    while(j < cell->listContribution.size())
    {
     if(cell->listContribution[j].numFace > numface) break;
     if(cell->listContribution[j].numFace == numface)
     {
      cell->densite = cell->densite - cell->listContribution[j].area;
      cell->listContribution.erase(cell->listContribution.begin()+j);
      break;
     }
              j ++ ;
    }
 
    //Penalité
    j = 0;
    while(j < cell->listPenalite.size())
    {
     if(cell->listPenalite[j].numFace > numface) break;
     if(cell->listPenalite[j].numFace == numface)
     {
      cell->densite = cell->densite + pFactor*cell->listPenalite[j].area;
      cell->listPenalite.erase(cell->listPenalite.begin()+j);
      break;
     }
     j ++ ;
    }
   // désactivation de la cellule
   if(cell->listContribution.size() == 0) cell->active = false;
   
  }
 }
}
 
et Cette fois ci pour un nombre d'appel de la fonction ajour égale à 62 j'aurai un temps d'exécution = 7969 ms  
Je suis satisfaite de ce dernier résultat je crois que je vais me contenter de ça pour pouvoir continuer le reste de l'algorithme.
 
Je tiens à remercier tout le monde pour le temps et l'intérêt que vous avez porté à mon problème
Merci  
 
 

n°2015169
el muchach​o
Comfortably Numb
Posté le 08-08-2010 à 00:29:38  profilanswer
 

Allez, hop, c'est gratuit:
2 changements rapides:
1.le parcours dans le sens inverse, potentiellement plus rapide, et plus besoin de break;
2.contrib invariant de boucle --> variable.

 
Code :
  1. void Loader::ajour(int numface)
  2. {
  3.      for(int k = minRho; k < maxRho; k++){
  4.       for(int i=0; i < gridSize; i++){
  5.            CELL *cell = &cells[i][k];
  6.          
  7.            if(cell->active) {
  8.                 int j = cell->listContribution.size() - 1;
  9.                 while(j > 0)
  10.                 {
  11.                  Contribution contrib = cell->listContribution[j];
  12.                  if(contrib.numFace > numface) break;
  13.                  if(contrib.numFace == numface)
  14.                  {
  15.                   cell->densite -= contrib.area;
  16.                   cell->listContribution.erase(cell->listContribution.begin()+j);
  17.                  }
  18.                  j--;
  19.                 }
  20.                // désactivation de la cellule
  21.                if(cell->listContribution.size() == 0) cell->active = false;
  22.            
  23.                 //Penalité
  24.                 j = cell->listPenalite.size() - 1;
  25.                 while(j > 0)
  26.                 {
  27.                  Penalite penal = cell->listPenalite[j];
  28.                  if(penal.numFace > numface) break;
  29.                  if(penal.numFace == numface)
  30.                  {
  31.                   cell->densite += pFactor * penal.area;
  32.                   cell->listPenalite.erase(cell->listPenalite.begin()+j);
  33.                  }
  34.                  j--;
  35.                 }
  36.             }
  37.       }
  38.      }
  39. }


Message édité par el muchacho le 12-08-2010 à 14:28:39

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°2015183
ilelle
Posté le 08-08-2010 à 10:52:59  profilanswer
 

@ el muchacho c'est supère pour un nombre d'appel de la fonction ajour égale à 62 j'aurai un temps d'exécution = 3188 ms au lieu de 7969 ms  
Merci infiniment

mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  std::vector et performance

 

Sujets relatifs
Utiliser un iterator sur un vector à 2 dimensions - positionremplissage d'un vector - perfs
Vector et pointeurvector iterators incompatible
push_back(new maClasse) dans un vector de vectorPerformance des boucles for avec la STL
[Crypto] TripleDES - Initialization vectorPerformance d'un applet Java?
vector et thread safevector libération mémoire
Plus de sujets relatifs à : std::vector et performance


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR