Boost::thread => perte de perf

Boost::thread => perte de perf - C++ - Programmation

Marsh Posté le 25-11-2011 à 15:50:40    

Bonjour à tous!
 
Voilà j'ai essayé de paralléliser un petit bout de code tout bête :
 

Code :
  1. template<class T>
  2. void coefficient(vector<T> &v, const vector<T> &up, const int nptot, const double dt)
  3. {
  4. for (int i=0; i<nptot; ++i)
  5.  {
  6.  v[i].x1()=dt*up[i].x1();
  7.  v[i].x2()=dt*up[i].x2();
  8.  }
  9. }


 
Donc il s'agit principalement de remplir un vecteur à partir d'un autre avec un traitement extrêmement simple entre les 2.
Pour paralléliser ça, j'ai fait ça (attention les yeux, je suis pas expert de code parallèles  :D ):
 

Code :
  1. class coeff
  2. {
  3. public:
  4.  coeff(){};
  5.  ~coeff(){};
  6.  template<class T>
  7.  void coefficient(vector<T> &v, const vector<T> &up, const double dt, const int indstart, const int nb_ind)
  8.   {
  9.   const size_t indend=indstart+nb_ind;
  10.   for (size_t i=indstart; i<indend; ++i)
  11.    {
  12.    v[i].x1()=dt*up[i].x1();
  13.    v[i].x2()=dt*up[i].x2();
  14.    }
  15.   }
  16. };
  17. template<class T>
  18. void coeff_parallel(parameters<double> &param, vector<T> &v, const vector<T> &up, const int nptot, const double dt){
  19. int indstart=0;
  20. int nb_ind=nptot;
  21. poscoeff V;
  22. const size_t nb_threads=param.nb_threads;
  23. boost::thread_group threads1;
  24. for (std::size_t n=0; n<nb_threads; ++n)
  25. {
  26. nb_ind=(int)((double)nptot/(double)nb_threads);
  27. if(n<nptot%nb_threads)++nb_ind;
  28. if(n>=nptot%nb_threads)
  29. {
  30. indstart=n*nb_ind+nptot%nb_threads;
  31. }
  32. else
  33. {
  34. indstart=n*nb_ind;
  35. }
  36. threads1.create_thread(boost::bind(&coeff::coefficient<T>, boost::ref(V), boost::ref(v), boost::ref(up), dt, indstart, nb_ind));
  37. }
  38. threads1.join_all();
  39. }


 
Et donc là il s'avère que c'est plus lent que la bête boucle à la ***  :sol:  
Donc je voulais savoir si c'est que j'ai une connerie quelque part ou bien juste qu'ici, comme il s'agit principalement d'accès mémoire, au final ça marche mieux en séquentiel?
 
Merci  :jap:


Message édité par T'CHATTE le 25-11-2011 à 15:52:15
Reply

Marsh Posté le 25-11-2011 à 15:50:40   

Reply

Marsh Posté le 25-11-2011 à 20:19:21    

quelle qté de donnée par thread, cb de thread ? gaffe au false sharing et au acces cache foiruex

Reply

Marsh Posté le 25-11-2011 à 22:56:01    

franchement plus simple en openmp ce cas la.
et sinon un petit tour coté wikipedia pour chercher 'protocole MESI'

Reply

Marsh Posté le 26-11-2011 à 10:53:55    

Joel F a écrit :

quelle qté de donnée par thread, cb de thread ? gaffe au false sharing et au acces cache foiruex


 
Pour l'instant chaque vecteur contient environ 5000 a 10000 doubles mais ensuite il y en aura dans les 100000. Le tout réparti sur 8 threads.
Qu'entends-tu par false sharing et au acces cache foireux?
 

Lightness1024 a écrit :

franchement plus simple en openmp ce cas la.
et sinon un petit tour coté wikipedia pour chercher 'protocole MESI'


 
Disons que comme j'utilise déjà Boost pour d'autres choses, je me suis dit autant continuer avec. Et il me semble que mon code ressemble à la version Static d'une boucle OpenMP non ?
Et pour MESI j'ai moyennement compris le rapport avec le schmilblick.  :??:

Reply

Marsh Posté le 26-11-2011 à 11:07:58    

Je viens de regarder un peu le false sharing (du coup je vois mieux le rapport avec MESI) et donc en fait faire des copies locales pour chaque thread pourrait résoudre le problème apparemment ... mais je trouve que la parallélisation perd de son intérêt dans ce cas. Il n'y a pas de méthode un peu plus jolie pour contourner ca ? Et est ce que OpenMP gère ca tout seul ?

Reply

Marsh Posté le 26-11-2011 à 13:18:13    

T'CHATTE a écrit :


 
Pour l'instant chaque vecteur contient environ 5000 a 10000 doubles mais ensuite il y en aura dans les 100000. Le tout réparti sur 8 threads.


 
Il me semble que tu ne donnes pas grand chose à faire à tes threads.  Mesure une fois le temps qu'il faut pour lancer 8 threads qui retournent immédiatement et puis faire un join dessus...


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

Marsh Posté le 26-11-2011 à 13:24:06    

oui le tout est de juger l'overhead. tu peux aussi faire l'essai en charge pleine (avec 100000) et mesurer le temps pris avec une boucle sans thread, par rapport a ta version 8 threads.
aussi, openmp ne fera pas de copies automatiques pour eviter les synchro de lignes de cache. tu ne gagnes rien par rapport a ton code, et oui, tu as raison ce que tu as fait correspond a un parrallel for a schedule static.
je le préconisait juste parce que ca réduit quand même de moitié le nombre de lignes :)


---------------
http://projets.6mablog.com/
Reply

Marsh Posté le 28-11-2011 à 10:37:54    

Bon je viens de tester quelques trucs (copie locale, utilisation d'itérateurs, ordre de parcours des vecteurs, ...) mais rien y fait : je pers toujours du temps quand j'augmente le nb de threads ...
J'imagine qu'il n'est pas possible de paralléliser un traitement aussi simple qui se résume essentiellement à des accès mémoire. Dommage :)
 
Merci pour votre aide en tout cas :jap:
A+! :hello:

Reply

Marsh Posté le 28-11-2011 à 10:50:12    

Tu as combien de core? Avoir plus d'une thread par core n'a aucune chance d'etre interessant.


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

Marsh Posté le 28-11-2011 à 12:49:53    

sachant qu'il a aussi raison, a partir du moment où le jeu de donnée dépasse le cache L2 des coeurs, il faut aussi que le bus soit accessible en parallele. ce qui n'est pas le cas sur les quad core Qxxxx par exemple. mais seulement sur les Xeon et les core i7. chez AMD ca l'a toujours été par contre, c'est la raison de la grande adoption des opterons sur les serveurs.
 
si je ne dis pas de bêtises.


---------------
http://projets.6mablog.com/
Reply

Marsh Posté le 28-11-2011 à 12:49:53   

Reply

Marsh Posté le 05-12-2011 à 17:20:46    

Désolé je n'avais pas vu les réponses :jap:
 
J'ai 8 cores disponibles avec 16Go de RAM partagée. Donc j'ai déjà parallélisé pas mal de choses dans mon code et ça va beaucoup plus vite. Je me demandai juste s'il était aussi possible de gagner quelque chose sur ce genre d'opération très simple mais apparemment non.
 
Et le type de processeur est Intel Xeon X5472. Donc les Xeon n'ont pas l'air d'avoir l'accès parallèle non plus :P (ou alors ca ne suffit pas pour ce que je veux faire :??: )

Reply

Marsh Posté le 21-12-2011 à 11:50:10    

En fait comment est ce que tu mesures que c'est plus lent ?

Reply

Marsh Posté le 21-12-2011 à 14:30:08    

Avec time. Les tests que j'ai fait duraient une 12-aine de minutes et j'avais environ 35 - 40s d'écart (tout à fait reproductible, à 5s près) quand je faisais avec ou sans thread.

Reply

Marsh Posté le 21-12-2011 à 23:53:51    

gaffe à ne pas créer tes threads et les détruire àchaque fois que tu en as besoin. Si ca entre dans ta mesure, tu dois pouvoir te débrouiller avec un pool de threads.
 
Ca peut être pas mal de considérer que tu as un pool de jobs à faire, tous ayant le même code, ,mais des datas différentes à faire
et d'utiliser un nombre de thread correspondant à ce que ton matériel te propose.
 
Surcharger une machine de threads n'est pas une bonne idée. Les créer à chaque utilisation non plus. Ce sont les deux grosses guidelines que je peux donner à ce sujet.
 
edit : pour clarifier : si tu as une machine avec 8 threads hardware, ca peut être une bonne idée de créer 8 threads et de leur faire traiter tes 200 jobs au fur et à mesure qu'ils achèvent le boulot plutôt que de créer en frontal 200 jobs et laisser l'OS se démerder.


Message édité par theshockwave le 22-12-2011 à 00:03:07

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

Marsh Posté le 22-12-2011 à 00:45:03    

oui j'ai fait attention à ça. Ailleurs dans mon code j'ai imposé la condition :
 

Code :
  1. if(params.nb_threads>boost::thread::hardware_concurrency())
  2. {
  3. params.nb_threads=boost::thread::hardware_concurrency();
  4. }


Je ne l'avais pas mis dans le code que j'ai posté car c'est ailleurs dans mon code mais c'est bien présent :)
Et dans le oute j'avai essayé d'imposer plusieurs nombres, de 1 à 32 (alors que je n'ai que 8 cores) et dés qu'il y en a plus de 1 je pers du temps. Et plus j'ajoute des threads plus je pers du temps...

Reply

Marsh Posté le 22-12-2011 à 02:58:41    

mmh, c'est sympa de te plaindre de la lenteur de tes threads dans un contexte différent de celui que tu nous présente. Dans ma boule de cristal, je ne vois pas plus de choses que ce que j'ai dit plus haut.
 
Si tu ne veux pas donner le code qui te pose vraiment problème, fais du profiling.
Mesure en terme de proporition le temps que tu passes dans des appels systèmes pour créer les threads et le temps que tu passes à exécuter chaque thread. regarde si les ordres de grandeurs sont proches, parce que je soupçonne que ce sera le cas.


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

Sujets relatifs:

Leave a Replay

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