2017-07-06 1 views
0

Ich möchte mit OpenMP eine for-Schleife innerhalb einer Funktion, die von der Haupt in C++ aufgerufen wird, parallelisieren.OpenMP langsame private Funktion

Mein Code läuft viel langsamer als im sequentiellen Modus: Die For-Schleife dauert etwa 6,1s (Wall-Clock) ohne OpenMP (nur den Befehl #pragma ... auskommentieren), und 11,8s mit OpenMP.

Meine Maschine verfügt über 8 CPUs und 8183MB physischen Speicher und ist mit einem 64-Bit-Windows 7-Betriebssystem ausgestattet. Ich benutze den Visual Studio Compiler für ein 64x Bit System im Debug Modus.

Ich habe gelesen, dass Leistungseinbußen durch Variablen verursacht werden können, die als privat deklariert werden sollten, aber ich bin nicht sicher, wie dies richtig zu tun ist und welche der Variablen als privat deklariert werden müssen.

Dies ist relevant für-Schleife:

vec DecenterOffsetParallel(const real_1d_array &x22, vec vDistance, double dOffsetXp, double dOffsetYp, double dOffsetXm, double dOffsetYm, double dOffsetXpY, double dOffsetYpX, double dOffsetXmY, double dOffsetYmX, double* dDeltaXp, double* dDeltaYp, double* dDeltaXm, double* dDeltaYm, double* dDeltaXpY, double* dDeltaYpX, double* dDeltaXmY, double* dDeltaYmX, double* delta0, /*local variables for the parallel code: */ const int nRaysn, double PupilDian, mat mRxNn, mat mRyNn, mat mRzNn, mat mRxN1n, mat mRyN1n, mat mRzN1n, mat mRxN2n, mat mRyN2n, mat mRzN2n, mat mRxN3n, mat mRyN3n, mat mRzN3n, mat mRcxNn, mat mRcyNn, mat mRczNn, mat mRcxN1n, mat mRcyN1n, mat mRczN1n, mat mRcxN2n, mat mRcyN2n, mat mRczN2n, mat mRcxN3n, mat mRcyN3n, mat mRczN3n, mat mPathNn, mat mPath1Nn, mat mPath00Nn, mat mPathN1n, mat mPath1N1n, mat mPath00N1n, mat mPathN2n, mat mPath1N2n, mat mPath00N2n, mat mPathN3n, mat mPath1N3n, mat mPath00N3n) 
{ 
#pragma omp parallel for 
for (int xy = 0; xy < nRaysn * nRaysn; xy++){ 
    mat temp = mat(nRaysn, nRaysn); 
    mat mScxn(nRaysn, nRaysn); 
    mat mScyn(nRaysn, nRaysn); 
    mat mSczn(nRaysn, nRaysn); 

    int i = xy/nRaysn; 
    int j = xy % nRaysn; 
    // only rays inside entrance pupil:t 
    if (sqrt(((10.0/nRaysn) * i - 5.0)*((10.0/nRaysn) * i - 5.0) + ((10.0/nRaysn)*j - 5.0) *((10.0/nRaysn)*j - 5.0)) <= PupilDian/2.0){ 
     // Initialize the matrices 
     mRxNn(i, j) = (10.0/nRaysn) * i - 5.0; 
     mRyNn(i, j) = (10.0/nRaysn) * j - 5.0; 
     mRzNn(i, j) = 0.0; 
     //... everything is repeated 3 more times to simulate all in all 4 cases...: mRxNn1(i,j) = (10.0/nRaysn)*i-5.0; and so on... 


     mRcxNn(i, j) = sign(vDistance(0)) *(mRxNn(i, j) - dOffsetYmX)/(sqrt(vDistance(0)*vDistance(0) + (mRxNn(i, j) - dOffsetYmX) * (mRxNn(i, j) - dOffsetYmX) + (mRyNn(i, j) - dOffsetYm) *(mRyNn(i, j) - dOffsetYm))); 
     mRcyNn(i, j) = sign(vDistance(0)) *(mRyNn(i, j) - dOffsetYm)/(sqrt(vDistance(0)*vDistance(0) + (mRxNn(i, j) - dOffsetYmX) * (mRxNn(i, j) - dOffsetYmX) + (mRyNn(i, j) - dOffsetYm) *(mRyNn(i, j) - dOffsetYm))); 
     mRczNn(i, j) = sqrt(1 - mRcxNn(i, j)*mRcxNn(i, j) - mRcyNn(i, j)*mRcyNn(i, j)); 
     mPathNn(i, j) = 0.0; 
     mPath1Nn(i, j) = sign(vDistance(0)) *nAir * vDistance(0)/mRczNn(i, j); 
     mPath00Nn(i, j) = mPath1Nn(i, j); 
     //... everything is repeated 3 more times to simulate 4 different cases... 

     //trace rays through cornea 
     temp(i, j) = RayIntersect(ZernAnt, ZernRadAnt, &mRxNn(i, j), &mRyNn(i, j), P2DAnt, UAnt, VAnt, &mRzNn(i, j), mRcxNn(i, j), mRcyNn(i, j), mRczNn(i, j), &mPathNn(i, j), xNullAnt, yNullAnt, NknotsUAnt, NknotsVAnt); // find the intersection (modifies mRz, mRy, mRx, mPath) 
     mPathNn(i, j) = mPath1Nn(i, j) + nAir*mPathNn(i, j); 
     temp(i, j) = Surface(P2DAnt, UAnt, VAnt, ZernAnt, ZernRadAnt, mRxNn(i, j), mRyNn(i, j), mRzNn(i, j), &mScxn(i, j), &mScyn(i, j), &mSczn(i, j), KnotIntervallSizeAnt, xNullAnt, yNullAnt); 
     // *Ant are identical for all four cases! 
     temp(i, j) = Refract(nAir, nCornea, &mRcxNn(i, j), &mRcyNn(i, j), &mRczNn(i, j), mScxn(i, j), mScyn(i, j), mSczn(i, j)); 
     //... everything is repeated 3 more times to simulate all in all 4 cases... 
    } 
    else{ 
     mRxNn(i, j) = mRyNn(i, j) = mRzNn(i, j) = mRcxNn(i, j) = mRcyNn(i, j) = mRczNn(i, j) = mPathNn(i, j) = mPath1Nn(i, j) = NAN; 
     //... everything is repeated 3 more times to simulate all in all 4 cases... 
    } 
} 
// some other stuff, that is not relevant to the questions... 

}

Kann mir jemand einen Tipp geben, was könnte die Leistungseinbußen führen? Vielen Dank!

PS: Armadillo-Bibliothek wird für die Matrizen und Vektoren verwendet.

+0

'public' oder' private' wird in dieser Hinsicht nichts ändern. –

+1

Willkommen bei SO. Leider liefern Sie keine ausreichenden Informationen, um Ihre Frage richtig zu beantworten. Bitte fügen Sie eine [mcve] ein, beschreiben Sie Ihre Systemkonfiguration (CPU, Speicher, Compiler) und wie messen Sie und Ihre spezifischen Messergebnisse. – Zulan

+0

Ich habe die Systeminformationen hinzugefügt und das vereinfachte Beispiel durch den (leicht gekürzten) Originalcode aus meinem Programm ersetzt. Hoffe das hilft! – Sims

Antwort

0

Sie brauchen keine privaten Variablen im parallelen Konstrukt zu erklären, da alle Variablen entweder schreibgeschützt sind (nS, Dia, etc.) oder müssen geteilt werden (mX, mY, etc.).

Die Frage zur Leistungseinbuße, sollten Sie mehr Informationen wie @Zulan in den Kommentaren erläutert. Eine sehr nützliche Metrik wäre hier, wie oft Ihre Funktion aufgerufen wird und welcher Teil der Gesamtzeit der Anwendung benötigt wird (um zu überprüfen, ob es sich tatsächlich um einen Hotspot handelt). Die Anwendungsausführungszeit und die akkumulierte Funktionszeit wären groß.

Sie können dies mit vielen Tools wie gprof's call graph, aber führen Sie es ohne OpenMP.

+0

nRays * nRays = 10 000 Berechnungen, die völlig unabhängig voneinander sind. Basierend auf anderen Teilen würde ich eine Wanduhrzeit von mindestens 50% für die For-Schleife erwarten. Im sequentiellen Teil macht der Teil des Codes ungefähr 20-30% meiner gesamten Ausführungszeit aus. – Sims