2016-11-16 4 views
8

Ich bin neu in OpenMP und ich versuche folgenden Code OpenMP zu paralelize:OpenMP paralelization hemmt Vektorisierung

#pragma omp parallel for 
for(int k=0;k<m;k++) 
{ 
    for(int j=n-1;j>=0;j--) 
    { 
     outX[k+j*m] = inB2[j+n * k]/inA2[j*n + j]; 

     for(int i=0;i<j;i++) 
     { 
      inB2[k*n+i] -= inA2[i+n * j] * outX[k + m*j]; 
     } 
    } 
} 

Paralelize der äußere Zyklus ist ziemlich geradlinig, aber es zu optimieren, wollte ich das paralelize innerster Zyklus (der iterating über i) auch. Aber wenn ich versuche, dass wie dies zu tun:

#pragma omp parallel for 
for(int i=0;i<j;i++) 
{ 
    inB2[k*n+i] -= inA2[i+n * j] * outX[k + m*j]; 
} 

die Compiler vektorisiert nicht den inneren Zyklus („Schleife für die Vektorisierung versioniert wegen möglichen Aliasing“), die es langsamer laufen läßt. Ich kompilierte es mit gcc -ffast-math -std=c++11 -fopenmp -O3 -msse2 -funroll-loops -g -fopt-info-vec prog.cpp

Vielen Dank für jede Beratung!

EDIT: Ich verwende __restrict Schlüsselwort für die Arrays.

EDIT2: Interessant ist, dass, wenn ich nur das Pragma im inneren Zyklus behalte und es vom Äußeren entferne, gcc es vektorisieren wird. Das Problem tritt also nur dann auf, wenn ich versuche, beide Zyklen zu paralelisieren.

EDIT3: Der Compiler wird die Schleife vektorisieren, wenn ich #pragma omp parallel für simd verwende. Aber es ist immer noch langsamer als ohne die innere Schleife überhaupt zu parallelisieren.

+0

Es ist einfacher, manuell zu vektorisieren, als parallelisieren. Warum nicht einfach? (und automatische Parallelisierung beibehalten) –

Antwort

1

Vielen Dank für die Antworten. Ich habe es geschafft, die innere Schleife mit #pragma omp parallel for simd zu vektorisieren, aber das Programm war langsamer als ohne Parallelisierung. Ich fand schließlich einen etwas anderen Algorithmus, um das Problem zu lösen, das viel schneller ist. Danke für Ihre Hilfe Jungs!

+1

Die "VIPO" (Vectorize Inner, Parallel Outer) ist normalerweise am besten.Also reines SIMD auf der inneren Schleife (Nein 'parallel für'), und dann, ob Parallelisierung der äußeren Schleife hilft oder nicht, ist normalerweise ein Test-es-n-sehen-Ende. Bei bandbreitenbeschränkten Situationen hilft manchmal Prefetch, aber Cache-Misses können viele Kerne haben, die wenig echte Arbeit leisten, während ein einzelner Kern Daten ungehindert streamen kann. Es ist selten leicht zu erraten. – Holmz

1

Meine Schätzung ist, dass, nachdem Sie die innere Schleife parallelisiert haben, der Compiler die Spur inA2, inB2 und outX verloren. Standardmäßig wird davon ausgegangen, dass alle Speicherbereiche, auf die Zeiger zeigen, sich gegenseitig überlappen können. In der Sprache C hat der C99-Standard das Schlüsselwort restrict eingeführt, das den Compiler informiert, dass ein Zeiger auf einen Speicherblock zeigt, auf den kein anderer Zeiger zeigt. C++ hat kein solches Schlüsselwort, aber zum Glück hat g++ eine entsprechende Erweiterung. Versuchen Sie daher, den Deklarationen der Zeiger, die von der Schleife berührt werden, __restrict hinzuzufügen. Ersetzen Sie beispielsweise

double* outX; 

mit

double* __restrict outX; 
+0

Leider ist dies nicht der Fall. Ich benutze __restrict. Guter Punkt, aber ich werde es dem OP hinzufügen. –

1

Haben Sie versucht, die innere Schleife machen vecotorzed zuerst? und dann den parallelen Teil (der in geringerer Leistung je nach Cache-Misses führen könnte)

#pragma omp parallel for 
for(int k=0;k<m;k++) 
{ 
    for(int j=n-1;j>=0;j--) 
    { 
     outX[k+j*m] = inB2[j+n * k]/inA2[j*n + j]; 
Q1 = k*n 
Q2 = n*j 
Q3 = m*j + k 
#pragma omp declare simd private(i,j,k,m,Q1,Q2,Q3) linear(i) uniform(outX,inA2,inB2) shared(inB2,inA2,outX) 
     for(int i=0;i<j;i++) 
     { 
      inB2[Q1+i] -= inA2[Q2+i] * outX[Q3]; 
     } 
    } 
} 

Es ist immer nimmt mir etwas Zeit bekommt die Pragma direkt mit dem gemeinsamen, öffentlichen etc ... Und ich habe nicht testen Dies.

+0

Danke für die Idee. Wie ich bereits in EDIT3 erwähnt habe, habe ich es mit #pragma omp parallel für simd vektorisiert. Aber es ist immer noch langsamer als ohne die innere Schleife zu paralelisieren. –

+0

Das könnte darauf hinweisen, dass es eher bandbreitenbegrenzt als rechnerisch begrenzt ist. – Holmz