Ok, effectivement on dirait qu'OpenMP est bien activé. Bizarre...
Ok, effectivement on dirait qu'OpenMP est bien activé. Bizarre...
flute j'avais loupe l'init du t0
en corrigeant tous ca j'obtiens:
number max of threads:4
C =10000000: 1.094s
OpenMP=10000000: 0.625s
STL =10000000: 0.625s
a priori un benchmark comme cela ne montre pas vraiment la superiorité du MT...
il faut charger la mule pour le voir...
juste en mettant: sum+=cos(X[j]/(double)i);
j'obtiens:
C =0: 37.813s
OpenMP=0: 15.25s
et en STL ?
Le mystère est (en bonne partie) résolu.
J'ai l'impression que c'est à cause d'une histoire de fonctions non inlinées correctement. Ce qui corrobore ma première impression sur OpenMP sur le fait que c'est trop "C" et pas assez "C++".
En utilisant un pointeur plutôt qu'un std::vector j'obtiens les résultats suivant.
C++ : 0.797s
OpenMP: 0.61s
STL : 0.765s
(Ma lib: 0.532s)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 #include <vector> #include <numeric> #include <iostream> #include <ctime> #include <omp.h> using namespace std; inline double get_time() { return double(clock())/CLOCKS_PER_SEC; } int main() { typedef int value_type; vector<value_type> X(10000000,1); value_type *pX=&X[0]; double t0=0; value_type *psum = new value_type; // alloué dynamiquement pour tromper l'optimisation d'ICL t0=get_time(); for (int i=0; i<50; ++i) { value_type sum=0; int imax=X.size(); for (int i=0; i<imax; ++i) sum+=pX[i]; *psum=sum; } cout << "C =" << *psum << ": " << get_time()-t0 << "s" << endl; t0=get_time(); for (int j=0; j<50; ++j) { value_type sum=0; int imax=X.size(); //#pragma omp parallel for schedule(static) reduction(+:sum) #pragma omp parallel for schedule(dynamic,100000) reduction(+:sum) for (int i=0; i<imax; ++i) sum+=pX[i]; *psum=sum; } cout << "OpenMP=" << *psum << ": " << get_time()-t0 << "s" << endl; t0=get_time(); for (int i=0; i<50; ++i) *psum=accumulate(X.begin(),X.end(),0); cout << "STL =" << *psum << ": " << get_time()-t0 << "s" << endl; }
il faudrait vraiment faire plus qu'une addition dans cette boucle ...
une expression mathematique ? un cos tan etc..
pourquoi pas, mais le hic c'est que ça ne serait plus vraiment comparable avec l'un des très peu nombreux algos mathématiques de la STL. Peut-être un produit scalaire (inner_product).
Quoiqu'il en soit je pourrai bientôt reposter un nouveau bench FFT.
... j'attends tres impatiemment le nouveau bench ....
Résultats de cpuid :
Résultats de CPU-Z : <piece jointe>Envoyé par cpuid
Résultats des benchs sur un Intel x2 : <pieces jointes>
Benchmark FFT 64 SSE2.txt
Benchmark FFT 64 SSE2 MT2.txt
Benchmark FFT 64 SSE2 OpenMP2.txt
je ne pense pas que l'addition soit representatif pour un benchmark. Regarde le mien quand j'ai utilisé un cos ... OpenMP etait plus de 2 fois plus rapide...Envoyé par Charlemagne
... j'adore OpenMP
Merci mchk0123
C'est vraiment 2 processeurs P4 HT ????!!! C'est bizarre parce que mon programme ainsi qu'OpenMP ne reconnaissent qu'un seul processeur. CPUZ ne semble pas faire mention d'un 2ème processeur également.
Et comme l'hyper-threading n'apporte malheureusement rien à ma FFT, c'est pas meilleur que le single-thread.
ok c'est normal tu fais moins appel aux accès mémoires et donc tu te rapproches du gain théorique de x2.Envoyé par epsilon68
Finalement le seul benchmark qui compte, c'est celui du programme qui répond au problème propre à chacun.
Je travaille encore sur ma FFT, les prochains benchs ne sont pas encore près...
(Faut dire qu'au départ je n'avais pas prévu les comparer avec OpenMP)
@Charlemagne, je pensais vraiment que c'était un bi-core car j'ai une double courbe sur le gestionnaire de tâches et l'exe systeminfo me donne les résultats suivants :
systeminfo.txt
En revanche CPU-Z et cpuid, comme tu l'as dit, ne semblent détecter qu'un seul core ... Qui est dans le vrai ?
c'est l'hyperthreading si je ne m'abuse...
Je confirme c'est l'hyper-threading, moi aussi j'ai 2 courbes dans le gestionnaire de tâches.
(je suis rassuré, mon programme fonctionne!)
Voici le nouveau bench (comme avant il suffit d'exécuter le fichier '.bat' et de me rendre les 3 fichiers textes) Merci d'avance.
http://www.ient.rwth-aachen.de/team/...ads/Benchs.zip
J'ai pas réussi à rendre le coût de synchronisation négligeable, et donc les perfs pour les petites matrices sont de l'ordre de 10-20% moins bonnes par rapport au single-thread. Mais en tout cas mon implémentation s'en sort beaucoup mieux qu'OpenMP malgré sa clause 'if' (pour dire en deçà de quelle valeur il n'y a pas de multi-threading) qui l'améliore mais pas suffisamment.
J'espère que c'est le dernier bench pour les matrices complexes, mais attendez vous en tout cas à un bench pour la généralisation du multi-threading aux matrices réelles.
ca me surprend quand meme drolement que OpenMP est plus lent que ta solution ... ca peut pas venir d'autre chose ?
Y'a un problème auquel j'avais pas pensé.
En fait j'avais demandé à mon programme de ne pas tenir compte de l'hyper-threading (pas efficace pour ma FFT), donc il ne crée que 2 threads (et non 4 comme OpenMP) sur ton 2x Xeon HT.
Le problème c'est que mon programme multi-thread n'est pas plus rapide que le single-thread de référence. Je suppose donc que le 2ème thread a été affecté à un CPU "virtuel". C'était pas le cas dans ton bench précédent, j'imagine que c'est une question de "chance".
En bref: l'hyper-threading c'est ici la merde. Je ne vois pas quoi faire pour imposer un thread à un processeur précis.
Voici un bench qui tiendra compte de l'hyper-threading (seul le programme Benchmark_FFT_64_SSE2_MT.exe a changé, pas la peine pour Epsilon68 d'exécuter les autres)
http://www.ient.rwth-aachen.de/team/...ads/Benchs.zip
Pour les petites matrices tu veux dire? (car pour les grandes à cause du problème ci-dessus c'est pas le cas).Envoyé par epsilon68
je sais en tout cas que j'ai eu du mal a réduire le temps de synchonisation sur mon implémentation. Essaye d'en juger par toi-même pour OpenMP dans les fonctions parrallel_for et parallel_reduce à la fin de ce fichier. Je vois pas comment faire mieux.
A la réflexion je ne vois rien à faire pour améliorer cette "latence" d'OpenMP pour les petites matrices.
Tu te rappelles de mon premier bench FFT avec OpenMP? J'avais mentionné que c'était vite fait bien fait: j'avais parallélisé les 2-3 boucles directement dans mon implémentation de la FFT, alors que les benchmarks actuels utilisent la fonction parallel_for réécrite avec OpenMP.
Eh bien, j'avais déjà remarqué ce temps de latence prééminent pour OpenMP.
La clause 'if' permet de rattraper ce retard en partie mais pas assez pour rendre l'utilisation d'OpenMP transparente sur des petites boucles.
PS: En tout cas sur l'implémentation d'OpenMP que j'utilise
j'ai un doute sur:
je ne comprends pas le schedule(dynamic,1)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 #pragma omp parallel if (nchunks>1) firstprivate(func) { #pragma omp for schedule(dynamic,1) for (int i=0; i<nchunks; ++i) { int d=i*grain; RanIt it=begin+d; func(it,it+__min(n-d,grain)); } #pragma omp critical f.join(func); }
et je l'aurais surement ecrit en boucle for normal.
j'aurais au préalable declaré un tableau de taille avec le max processor
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 #pragma omp for for( i=0; i<end-begin; i++)
puis j'aurais appliquer le reduce sur ce nombre d'element (sans openmp donc).
Qu'en penses-tu ?
il faut que je creuse plus ton code de toute facon, c'est tres interessant.
Merci, les benchs sont meilleurs.
Mais j'arrive pas à avoir des gains en multi-threading faramineux sur ton 2x Xeon HT, OpenMP non plus d'ailleurs. J'obtiens des gains de l'ordre de x1.2 à x1.4 pour les matrices de grande taille. Ca varie mais ma librairie se tient dans les mêmes eaux qu'OpenMP.
Il faudrait que quelqu'un fasse le dernier bench (pour rappel http://www.ient.rwth-aachen.de/team/...ads/Benchs.zip) sur un CPU multi-core pour que je me fasse une opinion sur ce style de processeurs.
Avis aux volontaires: HanLee, Laurent...?
Je me doutais que t'allais poser la question. La fonction-objet passée en paramètre prend un intervalle en paramètre (avec 2 itérateurs), donc que le découpage vu par OpenMP soit de 1 n'est pas génant.Envoyé par epsilon68
J'avais certes pensé à changer la syntaxe de la fonction-objet pour qu'elle ne prenne qu'un paramètre:
-mais il aurait fallu changer les appels à parallel_for dans ma librairie
-je ne veux pas renoncer à une programmation dans le style de la STL avec des itérateurs
Pour l'instant je ne vois pas meilleur compromis, et je t'assure que ça n'a pas d'incidence sur la vitesse (j'ai comparé avec la FFT "vite fait bien fait" avec OpenMP)
Je crois pas car il faut absolument que la réduction soit faite dans une section critique à cause de la modification d'une variable partagée. Avec ma syntaxe je ne peux/veux pas imposer les mêmes restrictions qu'OpenMP aux réductions (opérations atomiques). Et si je renonce d'une manière ou d'une autre à utiliser OpenMP, il faut que j'utilise les mutex de ma librairie (ce qui n'a plus de sens si on s'impose l'utilisation d'OpenMP).Envoyé par epsilon68
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager