std::vector et performance

std::vector et performance - C++ - Programmation

Marsh Posté le 04-08-2010 à 16:18:24    

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

Reply

Marsh Posté le 04-08-2010 à 16:18:24   

Reply

Marsh Posté le 04-08-2010 à 16:38:36    

- 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)
Reply

Marsh Posté le 04-08-2010 à 16:56:28    

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 ^^

Reply

Marsh Posté le 04-08-2010 à 17:52:17    

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.

Reply

Marsh Posté le 04-08-2010 à 18:02:28    

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)
Reply

Marsh Posté le 04-08-2010 à 19:36:46    

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

Reply

Marsh Posté le 04-08-2010 à 19:54:22    

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

Reply

Marsh Posté le 04-08-2010 à 20:05:06    

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
Reply

Marsh Posté le 04-08-2010 à 20:35:11    

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

Reply

Marsh Posté le 04-08-2010 à 20:48:13    

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
Reply

Marsh Posté le 04-08-2010 à 20:48:13   

Reply

Marsh Posté le 05-08-2010 à 09:32:28    

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).

Reply

Marsh Posté le 05-08-2010 à 10:13:09    

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.
Reply

Marsh Posté le 05-08-2010 à 12:15:18    

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. }

Reply

Marsh Posté le 05-08-2010 à 14:27:18    

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.

Reply

Marsh Posté le 05-08-2010 à 16:00:33    

@ 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;

Reply

Marsh Posté le 05-08-2010 à 16:12:59    

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)

Reply

Marsh Posté le 05-08-2010 à 16:16:53    

Merci infiniment

Reply

Marsh Posté le 05-08-2010 à 16:28:03    

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


---------------
The truth is rarely pure and never simple (Oscar Wilde)
Reply

Marsh Posté le 05-08-2010 à 16:39:13    

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 ...

Reply

Marsh Posté le 05-08-2010 à 17:20:07    

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

Reply

Marsh Posté le 05-08-2010 à 17:22:56    

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.
Reply

Marsh Posté le 05-08-2010 à 17:39:35    

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)
Reply

Marsh Posté le 05-08-2010 à 17:43:46    

@ 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  

Reply

Marsh Posté le 05-08-2010 à 17:45:33    

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

Reply

Marsh Posté le 05-08-2010 à 20:47:38    

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
Reply

Marsh Posté le 06-08-2010 à 10:04:17    

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.

Reply

Marsh Posté le 06-08-2010 à 10:55:14    

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


---------------
Be the one with the flames.
Reply

Marsh Posté le 06-08-2010 à 10:56:38    

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

Reply

Marsh Posté le 06-08-2010 à 14:16:12    

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.
Reply

Marsh Posté le 06-08-2010 à 19:29:07    


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
Reply

Marsh Posté le 06-08-2010 à 20:03:31    

@ 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

Reply

Marsh Posté le 07-08-2010 à 05:07:25    

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
Reply

Marsh Posté le 07-08-2010 à 11:32:01    

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

Reply

Marsh Posté le 07-08-2010 à 11:37:35    

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
Reply

Marsh Posté le 07-08-2010 à 12:42:09    

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

Reply

Marsh Posté le 07-08-2010 à 21:42:44    

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
Reply

Marsh Posté le 07-08-2010 à 23:41:34    

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  
 
 

Reply

Marsh Posté le 08-08-2010 à 00:29:38    

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
Reply

Marsh Posté le 08-08-2010 à 10:52:59    

@ 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

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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