OpenMP - Zrównoleglenie zagnieżdżonej pętli

OpenMP - Zrównoleglenie zagnieżdżonej pętli
G8
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:5
0

Witam.

Próbuję zrównoleglić taką oto pętlę:

Kopiuj
 for (j=0; j < n; j++)   
	for (i=0; i < j; i++)
            for (k=0; k < n; k++)
				 R[i][j] = R[i][j] + A[k][j]*Q[k][i];

poprzez dodanie dyrektywy:

Kopiuj
#pragma omp parallel for private(j, i, k) shared (A, Q, R)
 

A, Q oraz R to macierze (tablice typu double).
Niestety operacja zrównoleglona daje bezsensowne wyniki. Patrzę na to i ciągle nie widzę dlaczego...
dodam, że jestem początkujący w OpenMP - może ktoś mógłby mnie oświecić w czym jest problem ?

Pozdrawiam.

vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

Serwis Wróżka.pl podpowiada, że w ww poście może brakować szczegółów opisu błędu.

0
Giewont88 napisał(a):

...

Błaszczyk czy Karbowski?

xxx_xx_x
  • Rejestracja:około 13 lat
  • Ostatnio:9 dni
  • Postów:365
0

spróbuj tak:

Kopiuj
 

#pragma omp parallel private(i,k) 
 {
#pragma omp for 
for (j=0; j < n; j++)   
        for (i=0; i < j; i++)
            for (k=0; k < n; k++)
                                 R[i][j] += A[k][j]*Q[k][i];
}
 
edytowany 1x, ostatnio: xxx_xx_x
_13th_Dragon
A nie: private(j,i) ?
xxx_xx_x
j będzie private ze względu na for, trzeba ustawić i oraz k jako private. Btw. uruchomiłem jego i swój kod na testowych danych i oba działały. podejrzewam że nie wyzerował tablicy R. jak wiadomo przez warunek i<j nigdy nie machnie ostatniego wiersza (zakładając że ostatni wiersz ma nr n-1)
_13th_Dragon
A czy takie zrównoleglenie: #pragma omp parallel for private(j, i) nie będzie lepsze ze względu że wątki będą zupełnie niezależne?
xxx_xx_x
z tego co pamiętam parallel for zrównolegla jedynie pierwszą pętle do której jest przyłożony(openmp 3.0+ dodaje jeszcze jakaś dyrektywe umozliwiającą automatyczne zrównoleglanie wewnętrznych pętli), więc zmiana "private" niewiele wnosi. Oznacza jedynie że wątki mają trzymać własne kopie wybranych zmiennych. Jeżeli do takiego zapisu nie dodamy private(k) to będą go współdzielić, i szczerze mówiąc nie wiem co się w takiej sytuacji wydarzy.
G8
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 12 lat
  • Postów:5
0

Przebudowałem trochę potrzebny mi algorytm (chodzi o operacje na macierzach), teraz całość wygląda w ten sposób (poprzednio podawałem tylko najistotniejszy fragment):

Kopiuj
    #pragma omp parallel for private(k, i, j) shared(a, q, r, n)
    for (k=0; k<n; k++)
    {
          r[k][k]=0;
          for (i=0; i<n; i++)
              r[k][k] = r[k][k] + a[i][k] * a[i][k];
          r[k][k] = sqrt(r[k][k]);  // ||a||
         
         for (i=0; i<n; i++)
          {   
              q[i][k] = a[i][k]/r[k][k];
          }   

         for(j=k+1; j<n; j++)
         {
            r[k][j]=0;
            for(i=0; i<n; i++)
             r[k][j] += q[i][k] * a[i][j];
            for (i=0; i<n; i++)
             a[i][j] = a[i][j] - r[k][j]*q[i][k];
          }
    }

Niestety wersja zrównoleglona nadal działa źle - wyniki są liczbowo zupełnie inne niż w wersji sekwencyjnej (która na pewno liczy poprawnie).
Udało mi się "wyłapać", że problematycznym fragmentem jest:

Kopiuj
    for (i=0; i<n; i++)
    {   
              q[i][k] = a[i][k]/r[k][k];
    }

Jeśli ktoś rozumie w czym tkwi błąd i potrafi mi to wyjaśnić / poprawić kod to bardzo proszę o pomoc.

vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0
  • podaj więcej kodu (np. deklaracje tablic)
  • jak na dłoni widać że czytasz a[0][0] przed wypełnieniem tego elementu
  • jeśli chcesz usunąć wszystkie tego rodzaju błędy to zrób przed wszystkimi pętlami:
Kopiuj
#define HEX_WATCHDOG 0xffaa

#ifdef _DEBUG
#define ARR_CHECK(v,a,b) assert(v[a][b] != HEX_WATCHDOG)
#else
#define ARR_CHECK(v,a,b)
#endif

for(int i=0; i < n ; i++)
  for(int j=0; j < n; j++)
  {
     a[i][j] = r[i][j] = q[i][j] = HEX_WATCHDOG;  
  }

a potem wewnątrz każdej pętli:

zamiast:

Kopiuj
for(i=0; i<n; i++)
             r[k][j] += q[i][k] * a[i][j];

napisz sprawdzania dla wszystkich odczytów:

Kopiuj
for(i=0; i<n; i++) {
  ARR_CHECK(q,i,k);
  ARR_CHECK(a,i,j);
  r[k][j] += q[i][k] * a[i][j];
}

Ten test powinien wywalić błędy także w wersji sekwencyjnej.

Uwaga: wartość 0xffaa powinna być dobrana tak, żebyś był pewien że normalnie w tablicach nie występuje.

edytowany 1x, ostatnio: vpiotr

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.