Parallelisieren mit OpenMP
-
Hallo Zusammen,
Ich habe mit OpenMp eine For-Schleife in meinem Programm (=den zeitintensivsten Teil) parallelisiert.
Kompilieren usw. klappt auch alles und wenn ich mir mit htop die Auslastung der beiden CPU-Kerne anschaue, dann sind auch beim Durchlaufen beide und nicht wie vorher nur ein Kern in Benutzung (100%).
Komischerweise läuft das Programm aber nicht schneller durch, es benötigt nach wie vor so etwa 25 minuten.
Hat einer ne Idee woran das liegen könnte? Kann das sein, dass ich in dem parallelen Gebiet keine Funktionen aufrufen darf oder so?Grüße und vielen Dank für jede Hilfe,
Philipp.
-
zeig doch mal code. so kann man nix sagen. vielleicht müssen die threads aufeinander warten?
-
Ich glaub zwar nicht, dass das so wirklich was bringt mit dem Code, aber hier ist der Teil. Das Problem ist ja, dass ich irgendwie nicht verstehe, warum zwar beide CPUs ausgelastet sind, aber es nicht schneller läuft als auf einem...
#pragma omp parallel for shared(H,PerZ,xVerteilungNachher,yVerteilungNachher,zVerteilungNachher,Energieverteilung, Winkelverteilung, flags, DeltaV, deltaE, dt, qMitte, WinkelAufloesung, ergebnis, TeilchenNr) private(E,ni,qIon,EnergieIndex,T,dq,qAlt, vx, vy, vz) for(i=0;i<AnzahlIonen;i++) { if (i%(1000)==0) { TeilchenNr += 1000; printf("Teilchen Nummer %d von %d\n", TeilchenNr, AnzahlIonen); } geschwindigkeit(ergebnis, &vx, &vy, &vz); //Startgeschwindigkeit qIon = IonenQStartOrt(ergebnis, flags); //Start q-Wert (ort) T=(int)(drand48()*(*ergebnis).RFPeriodIntervalNo); //Startzeitpunkt do{ //printf("qIon = %e \n",qIon); ni = qnInterpolation(&qIon,ergebnis); E = qEinterpolation(&qIon,&T,ergebnis); H += Stoss(ergebnis, &vx, &vy, &vz); qIon += vx*dt*(*ergebnis).beta*ni; if(qIon>qMitte) //Spiegelung, falls Teilchen rechts von Mitte { qIon = qMitte - (qIon-qMitte); if(vx>0.0) vx *= -1.0; ni = qnInterpolation(&qIon,ergebnis); E = qEinterpolation(&qIon,&T,ergebnis); } vx += (*ergebnis).beta*E*dt; T++; if(T==(*ergebnis).RFPeriodIntervalNo){ T=0; PerZ++; } } while(qIon>(*ergebnis).qe); dq = vx*dt*(*ergebnis).beta*ni; qAlt = qIon - dq; vx = vx - dq + (*ergebnis).beta*E*dt* ((*ergebnis).qe-qAlt)/dq; if(((int)(fabs(vx/DeltaV)+0.5))<AnzahlKaestchen) xVerteilungNachher[(int)(fabs(vx/DeltaV)+0.5)]++; if(((int)(fabs(vy/DeltaV)+0.5))<AnzahlKaestchen) yVerteilungNachher[(int)(fabs(vy/DeltaV)+0.5)]++; if(((int)(fabs(vz/DeltaV)+0.5))<AnzahlKaestchen) zVerteilungNachher[(int)(fabs(vz/DeltaV)+0.5)]++; //WinkelIndex = ; Winkelverteilung[90-(int)(90*2.0/M_PI*fabs(atan(sqrt(vy*vy+vz*vz)/vx))+0.5)]++; EnergieIndex = (int)((vx*vx+vy*vy+vz*vz)/deltaE+0.5); if(EnergieIndex<((int)((*ergebnis).Emax/(*ergebnis).dE))) Energieverteilung[EnergieIndex]++; }
-
ich schätze mal dass da zu viele abhängigkeiten drin sind^^ die zugriffe auf diese ganzen shared-variablen müssen auch synchronisiert werden, was die threads ständig warten lässt. musste den code wohl irgendwie abändern, damit er besser parallelisierbar wird.
-
Hmm, wie kann ich denn mein struct ergebnis als private sertzen? Wenn ich das bei private reinschreibe, dann setzt der ja nur den Zeiger auf ergebnis als private und macht nen Schreibzugriffsfehler beim Ausführen.
-
frag doch mal da: http://www.openmp.org/forum/
-
Ich fürchte ohne eine Code-Änderung kommst du hier nicht viel weiter. Ein sequentieller Code kann man auf einem Superrechner ausführen und er wird deswegen nicht viel schneller als auf einem normalen PC.
Deswegen meine Frage: Wie sequentiell ist denn überhaupt dein Code ? Oder andersrum gefragt: Wieviele Zeilen kannst du miteinander vertauschen, ohne dass die Ergebnisse sich ändern ?
Kannst du anstatt:
ni = qnInterpolation(&qIon,ergebnis); E = qEinterpolation(&qIon,&T,ergebnis);
auch
E = qEinterpolation(&qIon,&T,ergebnis); ni = qnInterpolation(&qIon,ergebnis);
schreiben, ohne dass sich das Ergebnis ändert ?
Auf dem ersten Blick hat es den Anschein als ob viele Funktionsaufrufe von der Variablen ergebnis anhängen. Dadurch wird der Code sequentialisiert, da die vorherige Codezeile mit der Variablen arbeitet und diese erst fertig rechnen muss damit die nächste Codezeile beginnen, welche auch auf ergebnis zugreift.
Deswegen mein Vorschlag: Versuche die Variable ergebnis und qIon so aufzusplitten dass aufeinanderfolgende Codezeilen soweit wie möglich woneinander unabhängig werden.
tIon* qIon1; tIon* qIon2; qIon1 = *qIon; qIon2 = *qIon; ni = qnInterpolation(qIon1,ergebnis1); // Die folgenden zwei Zeilen könnten so parallel ausgrführt werden E = qEinterpolation(qIon2,&T,ergebnis2); ergebnis = MERGE (ergebnis1, ergebnis2);