You are on page 1of 35

Obliczenia równoległe dr inż.

Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

OBLICZENIA RÓWNOLEGŁE
Temat 6:

Narzędzia i środowiska
programowania równoległego
Prowadzący: dr inż. Zbigniew TARAPATA
pok.225, tel.: 83-73-38

e-mail: Zbigniew.Tarapata@wat.edu.pl

http:// tarapata.strefa
tarapata.strefa.pl
.pl//p_obliczenia_rownolegle/
p_obliczenia_rownolegle/

3
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Realizacja modelu równoległości danych – High Performance Fortran.

High Performance Fortran jest rozszerzeniem Fortranu 95 –


popularnego języka programowania naukowo-inżynierskiego.
Realizuje on model programowania z równoległością danych, głównie
dla operacji wektorowych i macierzowych. Zawiera rozszerzenia w
postaci dyrektyw kompilatora uzupełniających standardowe instrukcje
Fortranu. Język ten z założenia ma udostępniać model programowania
praktycznie realizowalny, prostszy niż inne i równie efektywny.
W celu zrównoleglenia działania poprzez przypisanie danych
poszczególnym procesom High Performance Fortran udostępnia
dyrektywy określające ułożenie procesorów:

!HPF$ PROCESSORS, DIMENSION(3,4):: P1


!HPF$ PROCESSORS, DIMENSION(2,6):: P2
!HPF$ PROCESSORS, DIMENSION(12):: P3
!HPF$ PROCESSORS, DIMENSION(2,2,3):: P4

W jednym programie może istnieć wiele zdefiniowanych układów


procesorów, wykorzystywanych w różnych miejscach do realizacji
różnych operacji.
Przypisanie (dystrybucja) danych odbywa się za pomocą
dyrektywy DISTRIBUTE, np.:
!HPF$ PROCESSORS, DIMENSION(4):: P
REAL, DIMENSION(10):: T1, T2

4
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

!HPF$ DISTRIBUTE T1(BLOCK) ONTO P


!HPF$ DISTRIBUTE T1(CYCLIC) ONTO P
Określenie BLOCK oznacza podział tablicy na bloki przypisywane
kolejnym procesorom, określenie CYCLIC oznacza przypisywanie
kolejnych wyrazów tablicy kolejnym procesorom z okresowym
zawijaniem.
Wykonanie równoległe odbywa się poprzez:
• realizację standardowych operacji wektorowych Fortranu
95
A+B, A*B, A(B*C) – operacje dozwolone dla macierzy
zgodnych, tj. mających ten sam kształt,
• pętli operujących na wszystkich elementach macierzy:
FORALL ( i=1..n, j=1..m, A[i,j].NE.0 ) A(i,j) = 1/A(i,j)
Równoległość jest uzyskiwana niejawnie – programista nie określa,
które operacje są wykonywane na konkretnym procesorze.

Unified Parallel C.

Unified Parallel C (UPC) to bardzo wygodne w użyciu rozszerzenie


języka C służące do programowania równoległego. Oparte jest ono na
modelu programowania równoległego o pamięci fizycznie
rozproszonej, logicznie współdzielonej. UPC to niewielkie i bardzo
wygodne w użyciu narzędzie pozwalające tworzyć wydajne programy.

5
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Najprostszy program wypisujący komunikaty Hello World z


każdego procesora (wraz z numerami procesów oraz liczbą tych
procesów) wygląda następująco:

#include <upc_relaxed.h>
#include <stdio.h>
void main(){
printf("Hello World from THREAD %d (of %d
THREADS)\n",MYTHREAD,THREADS);
}

Każdy procesor (tutaj nazywany wątkiem - THREAD) uruchamia


równolegle własną kopię powyższego programu. Pierwsza linia kodu,
poprzez dołączenie pliku nagłówkowego upc_relaxed.h,
specyfikuje sposób korzystania z pamięci. W UPC sposoby obsługi
pamięci są dwa:

• upc_relaxed.h - procesy mogą odczytywać zmienne


współdzielone dowolnie w każdej chwili. Korzystanie z tego
sposobu jest preferowane, gdyż umożliwia kompilatorom lepszą
optymalizację.

• upc_strict.h - współdzielone zmienne i dane


synchronizowane są za każdym razem przed dostępem do nich.
Oznacza to, że jeśli współdzielona zmienna jest aktualnie
modyfikowana przez jeden proces, pozostałe procesy będą
czekać aż do synchronizacji przed odczytaniem jej wartości.

6
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Dalsza część powyższego programu jest zwykłym kodem języka C.


Do wypisania komunikatu używamy funkcji printf. Korzystamy
jednak z dwóch zmiennych dostępnych dzięki załączeniu pliku
nagłówkowego UPC:

• THREADS - oznacza liczbę procesów, które uczestniczą w


aktualnym uruchomieniu programu,
• MYTHREAD - oznacza numer procesu aktualnie uruchomionego.

Dla lepszego wyjaśnienia znaczenia zmiennych THREADS i


MYTHREAD prześledźmy następujący przykład:

#include <upc_relaxed.h>
#include <stdio.h>

void main(){
if(MYTHREAD==0){
printf("Starting execution at THREAD %d\n",MYTHREAD);
}
printf("Hello World from THREAD %d (of %d
THREADS)\n",MYTHREAD,THREADS);
}

Program ten jest bardzo podobny do wcześniejszego, z tą różnicą,


że warunek zawarty w instrukcji if specyfikuje, iż proces o numerze
0 dodatkowo wywoła funkcję printf wypisując na standardowe
wyjście komunikat "Starting execution at THREAD 0".

7
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Równoległe pętle for - upc_forall.

W UPC mamy możliwość implementacji pętli, których kolejne


iteracje uruchamiane będą przez różne procesy. Struktura wywołania
takiej pętli jest następująca:

upc_forall( wyrażenie; wyrażenie; wyrażenie; wskazanie)

Czwarty parametr pętli upc_forall może być albo liczbą


naturalną tłumaczoną na (liczba % THREADS); lub adresem
który wskazuje na konkretny proces do którego adres ten jest
przypisany. Oto dwa krótkie przykłady użycia upc_forall:

upc_forall(i=0;i<N;i++;i) {
printf("THREAD %d (of %d THREADS) performing iteration
%d\n",MYTHREAD,THREADS,i);
}

Powyższa pętla wypisze numery procesów wraz z liczbą


reprezentującą numer iteracji przez te procesy wykonywanej. Iteracja
o numerze i będzie wykonywana przez proces o numerze i %
THREADS.

8
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

W drugim przykładzie widzimy, iż proces który ma wykonywać


daną iterację może zostać również wskazany przez adres pamięci do
niego przydzielony:

1: #include <upc_relaxed.h>
2: #include <stdio.h>
3: #define N 10
4: shared [2] int arr[10];
5:
6: int main() {
7: int i=0;
8: upc_forall(i=0;i<N;i++;&arr[i]) {
9: printf("THREAD %d (of %d THREADS) performing
iteration %d\n",MYTHREAD,THREADS,i);
10: }
11: return 0;
12: }

Linijka:
4: shared [2] int arr[10];

definiuje tablicę liczb typu integer o wymiarze 10. Pamięć ta


rozdzielona jest pomiędzy procesy, po 2 elementy tablicy dla każdego
procesu cyklicznie. W deklaracji tej tablicy kluczowe jest użycie
słówka shared (opisanego poniżej). Czwarty parametr
pętli upc_forall to adres kolejnych elementów tablicy arr. Adres
ten tłumaczony jest na identyfikator procesu któremu dany adres jest
przypisany. Wybrany proces realizuje następnie kod przypisany dla
danej iteracji. Oznacza to, że iteracja i wykonywana jest przez proces
do którego przypisany jest adres &arr[i].

9
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Zmienne współdzielone - wyrażenie shared.

Aby zrozumieć wszystkie oznaczenia związane z wyrażeniem


shared należy skomentować krótko pomysł, który kryje się za
modelem pamięci fizycznie rozproszonej, logicznie współdzielonej.
Otóż przestrzeń pamięciowa w UPC dzieli się na prywatną i
współdzieloną. Każdy proces ma swoją własną przestrzeń prywatną
oraz porcję przestrzeni współdzielonej. Prywatna pamięć obsługiwana
jest tak jak w zwykłym języku C. Cała przestrzeń współdzielona
podzielona jest na części, z których każda przypisana jest logicznie do
przestrzeni pamięciowej jednego z procesów. Widać to na poniższym
rysunku:

Rysunek A.1. Pamięć współdzielona i prywatna.

Tablice współdzielone logicznie rozdystrybuowane w blokach po


procesorach to tablice widziane przez wszystkie procesy, natomiast
fizycznie przechowywane w pamięci przypisanej do jednego z
procesów. Aby zdefiniować współdzieloną pamięć musimy użyć
słówka kluczowego shared. Mamy do dyspozycji następujące
kombinacje:

10
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

1: int local_counter; //prywatna zmienna


2: shared int global_counter; //współdzielona zmienna
3: shared int array1[N]; //współdzielona tablica
4: shared [N/THREADS] int array2[N]; //współdzielona tablica
5: shared [] int array3[N]; //współdzielona tablica
6: shared int *ptr_a; //prywatny wskaźnik do współdzialonej
pamięci
7: shared int *shared ptr_c; //współdzielony wskaźnik do
współdzielonej pamięci

Komentarza wymaga różnica pomiędzy trzema zdefiniowanymi


tablicami array1, array2, array3. Zwykle polecenie
shared ma następującą formę:

shared [rozmiar_bloku] typ nazwa_zmiennej

Powyższy zapis należy czytać w następujący sposób: zmienna o


nazwie nazwa_zmiennej o typie typ jest współdzielona
pomiędzy wszystkimi procesami i zostaje rozdystrybuowana
cyklicznie pomiędzy wszystkimi procesami w blokach wielkości
rozmiar_bloku. Jeśli wielkość bloku nie jest podana wówczas
przyjmowana jest wielkość 1. Nieskończoną wielkość bloku
oznaczamy []. Na kolejnych trzech rysunkach pokazany jest sposób
rozdystrybuowania pamięci pomiędzy procesami dla tablic array1,
array2, array3.

11
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Rysunek A.2. Rozłożenie elementów tablicy array1 po procesach z


rozmiarem bloku równym 1 dla N=9 oraz THREADS=3.

Rysunek A.3. Rozłożenie elementów tablicy array2 po procesach z


rozmiarem bloku równym N/THREADS dla N=10 oraz
THREADS=3.

Rysunek A.4. Rozłożenie elementów tablicy array3 po procesach z


nieskończonym rozmiarem bloku [] dla N=10 oraz THREADS=3.

12
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Synchronizacja procesów i dostępu do pamięci w UPC.

Bariery upc_barrier.

Polecenie upc_barrier służy do synchronizacji procesów.


Umieszczenie go w kodzie oznacza tak naprawdę postawienie bariery
w kodzie, tzn. żaden proces nie ma prawa przekroczyć bariery (linii w
kodzie) dopóki wszystkie procesy do niej nie dotrą. Bariery
wykorzystywane są najczęściej gdy występuje zależność danych
pomiędzy procesami. Oto prosty przykład:

1: #include <upc_relaxed.h>
2: #include <stdio.h>
3:
4: shared int a=0;
5: int b;
6:
7: int computation(int temp) {
8: return temp+5;
9: }
10:
11: int main(){
12: int result=0, i=0;
13: do {
14: if(MYTHREAD==0) {
15: result=computation(a);
16: a=result*THREADS;
17: }
18: upc_barrier;
19: b=a;
20: printf("THREAD %d: b=%d\n",MYTHREAD,b);
21: i++;
22: } while(i<4);
23: return 0;
24: }

13
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

W linii 16 powyższego kodu procesor o numerze 0 uaktualnia


wartość zmiennej a, współdzielonej przez wszystkie procesy. W linii
19 wszystkie procesy dokonują uaktualnienia swojej prywatnej
zmiennej b przypisując im aktualną wartość zmiennej a. Zauważmy,
że gdybyśmy nie umieścili bariery w linii 18 wówczas nie mielibyśmy
gwarancji, że wszystkie prywatne zmienne b zostały uaktualnione
najnowszą wartością zmiennej a.

Blokowanie dostępu do zmiennej - upc_lock/upc_unlock.

Dzięki użyciu blokad upc_lock/upc_unlock możemy


uzyskać gwarancję, że pewna zmienna nie będzie czytana przez
proces jeśli jest w danej chwili uaktualniana przez inny proces.

Przykład:

Zapoznamy się teraz z implementacją algorytmu obliczającego


1
1
liczbę Pi ze wzoru: Π = 4∫ i całkowania numerycznego metodą
0 1+ x
2

prostokątów.

Wersja szeregowa takiego programu wygląda następująco:

14
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

//Przyklad szeregowy - calkowanie numeryczne


//Obliczanie liczby Pi
#include<math.h>
#define N 1000000
#define f(x) (1.0/(1.0+x*x))
float pi=0.0;
void main(void)
{
int i;

for(i=0;i<N;i++)
pi+=(float) f( (0.5+i)/(N) );
pi*=(float)(4.0/N);

printf("PI=%f\n",pi);
}

15
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Wersja równoległa zaimplementowana przy pomocy UPC wygląda


tak:

//Przyklad UPC - calkowanie numeryczne


//Obliczanie liczby Pi
#include<upc_relaxed.h>
#include<math.h>
#define N 1000000
#define f(x) (1.0/(1.0+x*x))

upc_lock_t *l;
shared float pi=0.0;
void main(void)
{
float local_pi=0.0;
int i;
l=upc_all_lock_alloc();

upc_forall(i=0;i<N;i++;i)
local_pi+=(float) f( (0.5+i)/(N) );
local_pi*=(float)(4.0/N);

upc_lock(l);
pi+=local_pi;
upc_unlock(l);

upc_barrier;
if(MYTHREAD==0) printf("PI=%f\n",pi);
if(MYTHREAD==0) upc_lock_free(l);
}

Przykład ten jest bardzo fajny, gdyż widać tutaj zarówno użycie
bariery upc_barrier jak i zabezpieczenia upc_lock . Przed
równoczesnym dostępem z więcej niż jednego procesora
zabezpieczona jest współdzielona zmienna pi.

16
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Dostępność UPC, wspierane platformy.

UPC jest wspierane przez kompilatory na niektórych komputerach


firmy Cray ale również HP, SGI czy Sun. Dostępne są również pewne
darmowe implementacje, dokumentacje i przykłady:

• Michigan Technological University (http://www.upc.mtu.edu/)


• George Washington University (http://www.gwu.edu/~upc/)
• Berkeley Unified Parallel C (UPC) Project (http://upc.lbl.gov/).

OpenMP.
OpenMP jest to API pozwalające tworzyć kod wykonywany
równolegle w maszynach z pamięcią współdzieloną. Jest to zbiór
rozszerzeń do języków C, C++ i FORTRAN. Składa się ono z trzech
elementów:
• Dyrektyw preprocesora
• Funkcji bibliotecznych
• Zmiennych środowiskowych
Dzięki temu API programiści są w stanie tworzyć aplikacje,
których kod może być wykonywany przez wiele wątków równolegle.
Jak zobaczymy dalej, nie jest konieczna bezpośrednia obsługa wątków
a OpenMP jest niezależne od systemu, na którym kompilujemy kod.
OpenMP jest powszechnie przyjętym standardem i wynikiem wielu
lat badań nad tworzeniem programów wykonywanych równolegle.
Wersja standardu 1.0 ukazała się dla języka FORTRAN w 1997 roku,
a już w 1998 dostępna była dla C/C++. W Visual C++ 2005 do
czynienia mamy z wersją OpenMP 2.0, która ukazała się w 2002 roku.

17
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

OpenMP działa na maszynach z pamięcią współdzieloną. Oznacza


to, że wszystkie procesory mają dostęp przynajmniej do fragmentów
pamięci wpólnej. Dodatkowo system działa na jednej kopii systemu
operacyjnego a komunikacja procesorów polega na zapisie i odczycie
ze wspomnianej wcześniej wspólnej pamięci. Warunki te spełnia
idealnie większość dostępnych obecnie komputerów w tym również
dobrze nam znane komputery klasy PC.
Gdzie zatem warto użyć OpenMP? Zdecydowanie przeznaczone
ono jest do systemów, które potrafią wykonywać kod w wielu
wątkach równolegle oraz wymagają sporej mocy obliczniowej. Mogą
być to aplikacje począwszy od gier, poprzez obróbkę dźwięku i
obrazu a skończywszy na obliczeniach naukowych. Mówi się, że
znajduje ono zastosowanie w małych i średnich aplikacjach
wykonujących intensywne obliczenia a najlepiej jeżeli obliczenia te
wykonywane są w pętlach. Dyrektywy OpenMP bazują na dyrektywie
preprocesora #pragma w C/C++:

#pragma omp dyrektywa [wyrażenie [wyrażenie]…]

Najbardziej podstawowe pragmy omp to parallel, for, sections i


section, np.:
#pragma omp parallel
#pragma omp for
#pragma omp sections
#pragma omp section

18
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

We wstępie przyjrzyjmy się następującej pętli for:

void main()
{
double Table[1000];

for(int i=0;i<1000;i++)
DoSomething(Table[i]);
}
może zostać zrównoleglona w następujący sposób:
void main()
{
double Table[1000];

#pragma omp parallel for


for(int i=0;i<1000;i++)
DoSomething(Table[i]);
}

Zaledwie jedna linia kodu, a dysponując odpowiednim


kompilatorem i opowiednim sprzętem możemy powyższą pętlę
wykonywać równolegle przez wiele wątków.

Wątki a OpenMP
Równoległość wykonywania kodu z wykorzystaniem opisywanego
standardu polega na wykorzystaniu wątków. OpenMP to standard,
który ma być niezależny od platformy, został on zatem
zaprojektowany tak, iż programista nie ma bezpośrednio do czynienia
z tworzeniem, synchronizacją i niszczeniem wątków
charakterystycznych dla danej platformy. Za pomocą pragm OpenMP

19
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

steruje się ilością tworzonych wątków, synchronizacją oraz dostępem


do danych. Działanie programu stworzonego za pomocą tego
standardu dobrze zilustrować może następujący rysunek.

Rysunek A.5. Wątki w OpenMP.

OpenMP działa na zasadzie fork-join. Na samym początku program


startuje z jednym wątkiem, zwanym wątkiem głównym (ang. master
thread). Tuż po starcie znajdujemy się w sekwencyjnym regionie
kodu. W momencie, gdy wejdziemy w region równoległy, zostaje
stworzona odpowiednia pula wątków, do każdego wątku przypisana
zostają odpowiednie dane odpowiednio zainicjalizowane. Każdy
wątek ma określony kod do wykonania. Następuje współbieżne
wykonanie kodu poszczególnych wątków (czyli następuje
rozwidlenie, z ang. fork). Gdy wątek kończy swoją pracę może lub nie
wymagać synchronizacji z pozostałymi wątkami. Po zakończniu pracy
wszystkich wątków dane zostają zsynchronizowane do wątku
głównego i następuje wykonanie kolejnego regionu sekwencyjnego
(następuje „połączenie” wątków, z ang. join).

20
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Wszystkie elementy a mianowicie ilość wątków, kod, zmienne


przypisane do wątków, sposoby synchronizacji określa programista za
pomocą dyrektyw, modyfikatorów dyrektyw i funkcji czasu
wykonania.

PVM (Parallel Virtual Machine)

W skład oprogramowania wchodzi kilka programów i biblioteka


podprogramów pozwalająca na tworzenie aplikacji działających
równolegle na kilku komputerach (nawet o różnych architekturach).

Programista dostaje do ręki narzędzia pozwalające na pisanie


aplikacji, które dzielą problem obliczeniowy na kilka (najczęściej
identycznych, ale mniejszych) zadań, przekazywanie im danych i
synchronizacje ich wykonania.

Wykorzystanie możliwości systemu wymaga (najczęściej) takiego


zaprojektowania algorytmu zadania, aby łatwo dzieliło się na
fragmenty możliwe do równoległego wykonania. Nie mogą to być
zadania zbyt małe, a wymagające przekazywania znacznych ilości
danych gdyż wówczas synchronizacja zadań zużywa znaczną część
przepustowości sieci.

Zaletą systemu jest to, że dostępny jest na wszystkich praktycznie


platformach sprzętowych dostępnych na uczelni (SUN, SGI, IBM,
HP, komputery PC pracujące pod Linuxem).

21
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

PVM tworzony był na University of Tennessee, The Oak Ridge


National Laboratory i Emory University. Jego pierwsza wersja została
napisana w ORNL w 1989 roku. Następnie przepisano ją zupełnie w
University of Tennessee i udostępniono jako wersję drugą w marcu
1991. Wersja trzecia ukazała się w 1993 roku.

Dzisiaj PVM nie jest już aktywnym projektem, ale nadal stosuje się
go w programowaniu równoległym.
Opis działania PVM

PVM jest narzędziem służącym głównie do pośrednictwa w


wymianie informacji pomiędzy procesami uruchomionymi na
oddzielnych maszynach, oraz do zarządzania nimi za pośrednictwem
konsoli pvm. Z punktu widzenia obecnej definicji maszyny wirtualnej,
pvm w sumie nie zasługuje na swoją nazwę, powinien się bardziej
nazywać "zarządca procesów zrównoleglonych", jednakże historia
pvm sięga dawnych czasów, kiedy to nazewnictwo było trochę inaczej
rozumiane.

W dużym uproszczeniu PVM pozwala na "połączenie" większej


ilości komputerów w jeden. Odbywa się to na zasadzie dołączania
kolejnych hostów (komputerów), na których został zainstalowany i
skonfigurowany pvm. Podłączanie hosta jest w uproszczeniu
procedurą połączenia przez rsh, uruchomieniu demona pvm, i
dostarczenia mu informacji o tym kto jest jego "rodzicem" oraz o
parametrach istniejącej sieci.

22
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

W momencie kiedy cała "maszyna wirtualna" już jest


skonfigurowana, rola pvm sprowadza się do stanowienia pomostu
wymiany informacji pomiędzy procesami, które się w pvm
„zarejestrują” oraz umożliwienia administrowana stanem
zarejestrowanych w pvm procesów. Z takiego punktu widzenia pvm
można nazwać raczej „demonem komunikacji międzyprocesowej” i
można to podeprzeć najprostszym argumentem, mianowicie pvm nie
stanowi interfejsu do systemu operacyjnego lub maszyny na której
działa dany proces.

PVM pozwala zautomatyzować proces uruchamiania aplikacji na


innych komputerach. Jeżeli uruchomimy z poziomu normalnej konsoli
program, który następnie zarejestruje się w pvm i użyje funkcji
pvm_spawn(), aby uruchomić dolną ilość procesów, to już rolą PVM
będzie zatroszczenie się, gdzie zostaną one uruchomione, oraz samo
ich uruchomienie (możliwe jest podanie parametru uściślającego
lokalizacje docelową uruchomienia). W przypadkach obliczeń, gdzie
procesy-„dzieci”, rodzą się i umierają w bliżej nieokreślonych
interwałach i te zjawiska się przeplatają, zautomatyzowanie
dostarczane przez PVM okazuje się bardzo pomocne, ponieważ
"odciąża" programistę z potrzeby troski o prawidłowe rozłożenie
obliczeń na hosty.

Identyfikacja w pvm odbywa się przez oddzielne numery


identyfikacyjne przydzielane procesom w momencie rejestrowania się
w pvm. Numery te stanowią zupełną abstrakcję od systemu

23
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

operacyjnego i sprzętu, na którym uruchomiony jest dany proces.


Numer identyfikacyjny jest bardzo istotnym elementem pvm,
ponieważ stanowi on niejako adres danego procesu i jest on
niepowtarzalny w zakresie pojedynczej maszyny pvm. Adres jest
wykorzystywany przy wszystkich procedurach dotyczących innych
procesów, można przesłać informacje pod dany adres, można „zabić”
zdany adres i wiele innych.

Pojęcia „przyłączenie się do pvm” czy też „zarejestrowanie się w


pvm” znaczą dokładnie to samo i oznaczają wywołanie po raz
pierwszy jakiejkolwiek procedury pvm, przez co demon pvm
przydziela danemu procesowi numer identyfikacyjny i zapisuje
informacje o nim w swojej bazie procesów.

Podstawowe cechy środowiska PVM

- zarządzanie zasobami,
- możliwość dodania/usunięcia węzła z komputera wirtualnego,
- zarządzanie procesami,
- dynamiczne uruchamianie/usuwanie procesów,
- komunikacja między procesami na zasadzie wymiany komunikatów
(ang. message passing),
- niezawieszające wysłanie informacji, zawieszające i niezawieszające
odebranie informacji, grupowe operacje komunikacyjne,
- możliwość dynamicznego tworzenia grup procesów (zadań) -
dowolne zadanie może przyłączyć się do grupy lub porzucić ją w

24
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

dowolnym momencie czasu,


- tolerowanie defektów - komputer wirtualny automatycznie wykrywa
defekty, co daje możliwość dostosowania jego funkcjonowania do
aktualnej konfiguracji.

Przykłady dziedzin, w których wykorzystywany jest PVM

- prognoza pogody i modelowanie klimatu,


- biologia molekularna,
- modelowanie procesów spalania,
- rzeczywistość wirtualna,
- chemia kwantowa,
- rozpoznawanie obrazów,
- dynamika płynów,
- algebra liniowa,
- metoda Monte Carlo,
- metoda elementów skończonych,
- optymalizacja kombinatoryczna,
- modelowanie struktury białka,
- modelowanie sekwencji DNA.

Przesyłanie informacji pomiędzy programami.

W pvm wyróżniamy dwa rodzaje wysyłania informacji: blokujące i


nieblokujące. Przesyłanie blokujące to takie, które blokuje program
wysyłający na procedurze wysłania do momentu aż program
odbierający wywoła procedurę otrzymywania informacji i na odwrót,

25
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

blokuje program odbierający na procedurze odbierania do momentu,


aż zostaną mu wysłane jakieś informacje przez program nadający.
Przesyłanie nieblokujące - jak wynika z nazwy - jest pozbawione tych
negatywnych czynników, jednakże wymaga ono nieraz wsparcia przez
„procesy zewnętrzne (proces pvmmsg)”, oraz niejednokrotnie
wymaga synchronizacji procesów w celu ich skomunikowania.
Dlatego dla prostych programów przeważnie wykorzystuje się
przesyłanie blokujące.

Do przesyłania informacji w pvm stosuje się "bufory". Każdy


proces który zarejestruje się w pvm wywołując dowolną jego
procedurę (najczęściej stosuje się wywołanie pvm_mytid()), zostaje
wyposażony w jeden bufor nadawczy i jeden bufor odbiorczy.
Możliwe jest użycie buforów innych niż domyślne, jednakże wymaga
to ich utworzenia.

Procedura przesyłania dzieli się na:

1. Wysłanie informacji przez program „nadający”


1. inicjację bufora wysyłania
2. spakowanie danych do bufora
3. wysłanie wiadomości
2. Odebranie informacji przez programy „odbierające”
1. odebranie wiadomości
2. rozpakowanie informacji z bufora

26
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Do bufora można spakować więcej niż jedną informację w celu


wysłania ich większej ilości na raz, jednakże należy pamiętać o ich
rozpakowaniu z bufora odbiorczego w odpowiedniej kolejności.

Przykładowe procedury przesyłania informacji.

Komunikacja punkt-punkt.

pvm_send
int retval = pvm_send(int tid ,int msgtag);

Parametry

• tid - identyfikator procesu ,do którego ma zostać wysłany


komunikat.
• msgtag - liczba całkowita, definiowana przez użytkownika jako
etykieta komunikatu (powinna być >=0).
• retval - kod statusu zwracany przez funkcję (retval < 0 oznacza
błąd podczas wykonania operacji).

pvm_recv
int retval = pvm_recv(int tid ,int msgtag);

Parametry

• tid - identyfikator procesu ,od którego ma zostać odebrany


komunikat.
• msgtag - liczba całkowita, definiowana przez użytkownika jako
etykieta komunikatu (powinna być >=0).

27
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

• retval - kod statusu zwracany przez funkcję (retval < 0 oznacza


błąd podczas wykonania operacji).

Komunikacja grupowa

pvm_mcast
int retval = pvm_mcast( int *tids, int ntask, int msgtag );

Parametry

• tids - tablica liczb całkowitych o ntask elementach


zawierających identyfikatory zadań procesów, do których ma
zostać wysłany komunikat.
• ntask - ilość procesów, do których będzie wysłany komunikat.
• msgtag - liczba całkowita, definiowana przez użytkownika jako
etykieta komunikatu (powinna być >=0).
• retval - kod statusu zwracany przez funkcję (retval < 0 oznacza
błąd podczas wykonania operacji).

Funkcja wysyła komunikat asynchronicznie do wszystkich


procesów, których identyfikatory zadań są zapamiętane w tablicy tids
z wyjątkiem procesu wysyłającego. Etykieta msgtag jest
wprowadzona dla rozróżniania przesyłanych komunikatów.

Proces odbierający komunikat może zrobić to albo funkcją


pvm_recv(), albo pvm_nrecv().

28
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

MPI (Message Passing Interface)


MPI (ang. Message Passing Interface, Interfejs Transmisji
Wiadomości) - standard przesyłania komunikatów pomiędzy
procesami programów równoległych działających na jednym lub
więcej komputerach. Pierwsza wersja standardu ukazała się w maju
1994 r. Standard MPI implementowany jest najczęściej w postaci
bibliotek, z których można korzystać w programach tworzonych w
różnych językach programowania, np. Fortran, C, C++, Ada.

Opis

MPI jest specyfikacją biblioteki funkcji opartych na modelu


wymiany komunikatów dla potrzeb programowania równoległego.
Transfer danych pomiędzy poszczególnymi procesami programu
wykonywanymi na procesorach maszyn będących węzłami klastra
odbywa się za pośrednictwem sieci.

Program w MPI składa się z niezależnych procesów operujących na


różnych danych (MIMD). Każdy proces wykonuje się we własnej
przestrzeni adresowej, aczkolwiek wykorzystanie pamięci
współdzielonej też jest możliwe.

Główną zaletą standardu jest przenośność. Udostępnia on zbiór


precyzyjnie zdefiniowanych metod, które mogą być efektywnie
zaimplementowane. Stał się on punktem wyjściowym do stworzenia
praktycznego, przenośnego, elastycznego i efektywnego narzędzia do
przesyłania komunikatów (ang. message passing). Standard MPI

29
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

pozwala na jego zastosowanie zarówno w komputerach równoległych,


jak i heterogenicznych sieciach stacji roboczych.

Standard nie zabrania, aby poszczególne procesy były


wielowątkowe. Nie są też udostępnione mechanizmy związane z
rozłożeniem obciążenia pomiędzy poszczególne procesy, z
architekturą rozkładu procesorów, z dynamicznym tworzeniem i
usuwaniem procesów. Procesy są identyfikowane poprzez ich numer
w grupie w zakresie 0 .. groupsize-1.

Główne własności MPI

• umożliwia efektywną komunikację bez obciążania procesora


operacjami kopiowania pamięci,
• udostępnia funkcje dla języków C/C++, Fortan oara Ada,
• specyfikacja udostępnia hermetyczny interfejs programistyczny,
co pozwala na skupienie się na samej komunikacji, bez wnikania
w szczegóły implementacji biblioteki i obsługi błędów,
• definiowany interfejs zbliżony do standardów takich jak: PVM,
NX czy Express,
• udostępnia mechanizmy komunikacji punkt - punkt oraz
grupowej,
• może być używany na wielu platformach, tak równoległych jak i
skalarnych, bez większych zmian w sposobie działania.

30
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Zalety MPI

• dobra efektywność w systemach wieloprocesorowych,


• dobra dokumentacja,
• bogata biblioteka funkcji,
• jest to program public-domain,
• przyjął się jako standard.

Wady MPI

• statyczna konfiguracja jednostek przetwarzających,


• statyczna struktura procesów w trakcie realizacji programu,
• brak wielowątkowości.

Porównanie PVM i MPI.

PVM - standard de facto środowiska do przetwarzania


równoległego i rozproszonego w heterogenicznych sieciach maszyn
sekwencyjnych, równoległych i wektorowych.

MPI - standard biblioteki funkcji opartej na modelu obliczeń


równoległych z wymianą komunikatów.

Osiągnięcie maksymalnej wydajności to główny priorytet


przestrzegany przy opracowaniu standardu MPI i jego
implementacjach dla systemów masywnie równoległych - MPP;

31
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

dlatego dość powszechnie oczekuje się, że MPI będzie w stanie


zapewnić większą wydajność niż PVM dla architektur MPP.

Przenośność a interoperacyjność.

- oba środowiska zapewniają przenośność czyli możliwość realizacji


na różnych platformach,

- tylko PVM zapewnia interoperacyjność czyli możliwość


komunikowania się i współpracy różnych platform,

- zapewnienie interoperacyjności odbija się na wydajności,

- interoperacyjność PVM dotyczy również języków programowania -


bezproblemowe komunikowanie się programów napisanych w
językach C (C++) i Fortran.

PVM opiera się na koncepcji maszyny wirtualnej, która może być


traktowana jako rozproszony system operacyjny, umożliwiający
integrację różnych stacji roboczych, komputerów osobistych i MPP w
jedną całość:

- pozwala to realizować funkcje dynamicznego zarządzania


procesami,

- dopiero standard MPI-2 przewiduje taką możliwość,

32
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

- PVM dostarcza bogate możliwości w zakresie dynamicznego


zarządzania zasobami (dołączanie / odłączanie węzłów), podczas gdy
MPI został zaprojektowany z myślą o środowisku statycznym.

Nie przewidując tworzenia maszyny wirtualnej, standard MPI


realizuje koncepcję topologii wirtualnych, pozwalających
użytkownikowi - programiście w łatwy sposób opisywać strukturę
komunikowania się procesów aplikacji.

W odróżnieniu od MPI, środowisko PVM zapewnia bazowe


mechanizmy tolerowania defektów.

TotalView - debugger do programów równoległych.

Uruchomianie programów - znajdywanie i usuwanie błędów - jest


pracochłonne oraz wymagające dużej ilości czasu. Dobre narzędzia
programistyczne pozwalają uprościć i skrócić ten proces. Dlatego
obecnie stosowane środowiska do tworzenia aplikacji sekwencyjnych,
jak np. MS Visual Studio, czy Borland JBuilder posiadają
zintegrowany debugger.
Programy równoległe cechuje większa złożoność i podatność na
błędy. Niestety, brak jest tu wciąż standardowych pakietów
oferujących zintegrowane środowisko podobne do wyżej
wymienionych. Dlatego stworzono osobny i niezależny debugger,
pozwalający sprawnie uruchamiać programy równoległe. Totalview

33
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

jest najpopularniejszym i jednym z najlepszych programów tego typu.


Jest dostępny na wiele platform systemowych. Można go używać do
uruchamiania programów stworzonych przy pomocy różnych technik
programowania równoległego.

Aplikacja TotalView jest interakcyjnym i symbolicznym


debuggerem. Pozwala na śledzenie wykonywania programu na
poziomie kodu źródłowego, zatrzymywanie testowanego programu
(poprzez określenie punktów kontrolnych) oraz sprawdzanie wartości
zdefiniowanych zmiennych. W każdej chwili użytkownik może
obserwować interesujące go zmienne, moduły i etykiety. Aplikacja
TotalView używana jest w programie wykonywalnym,
skompilowanym za pomocą kompilatorów CAL (Cray Assembly
Language), C++, C, Fortran 77, Fortran 90 lub Pascal.

Uruchomienie.

Użytkownik musi zalogować się na SR2201. Istnieje kilka metod


wystartowania debuggera

• totalview program - działa jak w przypadku klasycznego


debuggera. Uruchamia program (jeden proces) i przejmuje
nad nim kontrolę.
• totalview - uruchamia sam debugger. Korzystając z listy
działających procesów można przejąć kontrolę nad dowolnym
z nich. Możliwość ta jest zresztą zawsze dostępna.

34
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

• totalview core program - do analizy core file


• mpirun <parametry dla MPI> -tv program - inicjalizuje
środowisko MPI, uruchamia równoległe aplikacje i
przekazuje je pod kontrolę Totalview, pozwala zatrzymać
procesy przy MPI_Init()
• totalview -pvm - opcja pozwalająca na współpracę z PVM

Obsługa.

Totalview to program z graficznym interfejsem użytkownika. Jego


obsługa sprowadza się do przełączania pomiędzy oknami,
wskazywania myszą na miejsca w kodzie programu, wyboru opcji z
menu i obsługi okien dialogowych. Zaawansowani użytkownicy mogą
oczywiście używać skrótów klawiszowych.

Totalview może naraz kontrolować wiele programów, każdy


program może składać się z wielu procesów, każdy proces może mieć
wiele wątków. Osobne okno pokazuje listę procesów, nad którymi
Totalview przejął kontrolę. Użytkownik może otworzyć osobne okno
do śledzenia każdego procesu, może też użyć jednego okna i
przełączać się pomiędzy procesami poprzez kliknięcie na odpowiedni
przycisk.

35
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Rysunek A.6. Wygląd TotalView

36
Obliczenia równoległe dr inż. Zbigniew Tarapata
Temat nr 6: Narzędzia i środowiska programowania równoległego

Możliwości.

Debugger wyświetla tekst programu (C, C++, Fortran). Klikając na


wybrane miejsca w programie można ustawić pułapki, wyświetlić
zawartość zmiennej itp. Można przełączyć się na poziom asemblera.
Debugger rozpoznaje typ zmiennych i pokazuje ich wartość w
odpowiedni sposób. Dla zmiennych złożonych (rekordy, tablice)
można żądać wyświetlenia wartości składowych przez kliknięcie na
nie. Wartości wybranych zmiennych można monitorować w sposób
ciągły. Stos procesu (zagnieżdżone wywołania funkcji) jest
uwidoczniony.

Wstawione w kod pułapki mogą dotyczyć pojedynczego procesu,


lub wszystkich procesów wchodzących w skład aplikacji (istotne dla
programów SPMD). Ta druga opcja bardzo ułatwia uruchamianie
programów MPI.

Wbudowany interpreter C, C++, Fortanu pozwala na dołączanie


dodatkowego kodu i jego modyfikacje w trakcie działania programu.
W połączeniu ze specjalnymi instrukcjami w Totalview uzyskujemy
możliwość tworzenia pułapek warunkowych.

37

You might also like