Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
OpublikowałBożena Janowska Został zmieniony 9 lat temu
1
1 An Introduction to MPI Parallel Programming with the Message Passing Interface William Gropp Ewing Lusk Argonne National Laboratory Wprowdzenie do MPI na podstawie: oraz własnych rozważań, programów i błędów
2
2 Gdzie szukać informacji ? Oficjalna dokumentacja standardów MPI http://www.mpi-forum.org/docs/docs.html http://www.mpi-forum.org/docs/docs.html Strona implementacji MPICH http://www-unix.mcs.anl.gov/mpi/mpich/ http://www-unix.mcs.anl.gov/mpi/mpich/ Google
3
3 Model przesyłania komunikatów (message passing) Proces posiada indywidualny licznik programu i indywidualną przestrzeń danych Procesy mogą być zbudowane z wielu wątków (threads) (posiadających swoje liczniki programu oraz stos) dzielących jedną przestrzeń adresową MPI służy do komunikacji pomiędzy procesami posiadającymi odrębne przestrzenie adresów Komunikacja pomiędzy procesami składa się z: –synchronizacji –Przesłania danych z jednej przestrzeni adresów do innej
4
4 Kooperatywne operacje komunikacji Przesyłanie komunikatu zawierającego dane wymaga działania kooperatywnego Dane są wysyłane przez jeden z procesów i pobierane przez inny Zmiana pamięci procesu odbierającego jest możliwa tylko poprzez jawne uczestnictwo procesu (wywołanie odpowiedniej funkcji) Komunikacja oraz synchronizacja są wykonywane wspólnie Proces 0 Proces 1 Send(data) Wyślij dane Receive(data) Odbierz dane
5
5 Jednostronne operacje komunikacji Jednostronne operacje obejmują dostęp do zdalenj pamięci w celu jej odczytu lub zapisu Wystarczy partycypacja tylko jedenego z procesów Komunikacja oraz synchronizacja są rozdzielone Ten tym komunikacji występuje w standardzie MPI-2. Proces 0 Proces 1 Put(data) Wstaw daną (memory) pamięć (memory) pamięć Get(data) Pobież daną
6
6 Czym jest MPI? Specyfikacja biblioteki do przesyłania komunikatów –rozszerzony model komunikacji za pomocą przesyłania komunikatów –nie definiuje nowych języków ani poleceń kompilatora –Nie jest związane z konkretną implementacją ani produktem Stworzona dla równoległych komputerów, klastrów i heterogenicznych sieci komputerów Zawiera pełen zestaw funkcji potrzebnych do p.k. Pozwala na dostęp do zaawansowanych zasobów: –użytkownikom końcowym –programistom opracowującym nowe biblioteki –programistom nowych narzędzi
7
7 Dlaczego używać MPI? MPI udostępnia potężne, wydajne i przenośne funkcje pozwalające tworzyć programy równoległe MPI zostało stworzone w celu użycia jako biblioteka i fragment innych bibliotek… … pozwala to na użycie MPI posiadając o nim niewielką lub brak wiedzy
8
8 Najkrótszy program z użyciem MPI 1 #include 2 #include 3 4 int main( int argc, char *argv[] ) 5 { 6 MPI_Init( &argc, &argv ); 7 printf( "Hello, world!\n" ); 8 MPI_Finalize(); 9 return 0; 10 }
9
9 Pobieranie informacji o otoczeniu Dwa podstawowe pytania pojawiające się podczas wykonywania programu równoległego: –Ile procesów bierze udział w obliczeniach? –Który z nich to ja? MPI dostarcza funkcje odpowiadające na te pytania: –MPI_Comm_size podaje size -liczbę procesów. –MPI_Comm_rank podaje rank-rangę, liczbę pomiędzy 0 oraz size-1, identyfikującą wywołujący funkcję proces
10
10 Lepsza wersja Hello 1 #include 2 #include //lub #include 3 4 int main( int argc, char *argv[] ) 5 { 6 int rank, size; 7 MPI_Init( &argc, &argv ); 8 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 9 MPI_Comm_size( MPI_COMM_WORLD, &size ); 10 printf( "I am %d of %d\n", rank, size ); 11 //lub: cout<<"I am"<<rank<<" of "<<size<<endl; 12 MPI_Finalize(); 13 return 0; 14 }
11
11 Jak uruchomić ten program ? Dołączyć scieżki do biblioteki i plików nagłówkowych w kompilatorze (library, include) Wykorzystać skrypt dostarczany z MPI: mpicc lub mpiCC (dla UNIX, IRIX, AIX, Linux,*BSD) Uruchomić poprzez mpiexec lub mpirun Podczas uruchamiania podaje się liczbę procesów Szczegóły -> laboratorium
12
12 MPI podstawowe wysyłanie/odbiór komunikatów Musimy określić szczegóły dla: Parametry do określenia: –Jak dane-“data” będą opisane ? –Jak proces zostanie zidentyfikowany ? –Jak odbiorca rozpozna/przejrzy wiadomość ? –W jaki sposób określić że operacja została wykonana ? Proces 0 Proces 1 Send(data) Wyślij dane Receive(data) Odbierz dane
13
13 W jaki sposób przesłać komunikat ? Transfer danych +synchronizacja Wymaga kooperacji między wysyłającym i odbierającym procesem Kooperacja nie zawsze widoczna w kodzie Dana Proces 0 Proces 1 Mogę wysyłac? Tak Data Dana Czas
14
14 Podstawowe zasady Procesy mogą być łączone w grupy Każda wiadomość jest wysłana z użyciem pewnego kontekstu i musi zostać odebrana używając tego samego kontekstu Groupa oraz kontekst tworzą razem komunikator (communicator). Proces jest identyfikowany przez rangę-rank w grupie powiązanej z komunikatorem Domyślnie istnieje komunikator, którego grupa zawiera wszystkie początkowe procesy, jego nazwa: MPI_COMM_WORLD.
15
15 Typy danych MPI Dane wysyłane i odbierane są określane przez trzy parametry (adres w pamięci, liczba, typ_danych): typ_danych MPI jest zdefiniowany jako: –predefiniowany, związany z typami danych języków programowania (np. MPI_INT, MPI_DOUBLE) –tablica danych typ_danych MPI –dowolna struktura typów danych MPI posiada funkcje pozwalające tworzyć nowe typy danych
16
16 MPIMPI_CHARMPI_INTMPI_FLOATMPI_DOUBLEMPI_SHORTMPI_LONGMPI_BYTEMPI_PACKED Wybrane typy danych MPI_Datatype język C charintfloatdouble short int long int ciąg bajtów wewnętrzny typ MPI
17
17 Znaczniki (stemple) MPI (tag) Wiadomości są wysyłane ze zdefiniowanym przez użytkownika znacznikiem (liczba naturalna) tag w celu jednoznacznej identyfikacji wiadomości przez proces odbierający Wiadomości odbierane mogą być weryfikowane poprzez użycie odpowiedniego znacznika lub przyjmowane z dowolnym znacznikiem podając wartość znacznika jako MPI_ANY_TAG
18
18 MPI podstawowe (blokujące) wysyłanie komunikatu MPI_SEND (start, count, datatype, dest, tag, comm) MPI_SEND (adres w pamięci danej/danych, liczba danych, typ danych, docelowy proces, znacznik, komunikator) W języku C/C++: int MPI_Send( void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm ) Wiadomość –bufor -określona przez ( start, count, datatype ). Docelowy proces definiowany przez dest, który jest rangą procesu w komunikatorze określonym przez comm. Po powrocie z tej funkcji, komunikat jest wysłany do systemu i można zmieniać zawartość bufora. Wiadomość mogła jeszcze nie dotrzeć do odbiorcy.
19
19 MPI podstawowe (blokujące) odebranie wiadomości MPI_RECV(start, count, datatype, source, tag, comm, status) MPI_RECV(adres w pamięci, liczba danych, typ danych, źrodłowy proces, tag, komunikator, status wiadomości) int MPI_Recv( void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status ) Czeka dopóki pasująca ( source i tag – źródło i znacznik ) wiadomość zostanie otrzymana z systemu i wstawiona do bufora source jest rangą procesu wysyłającego komunikat w komunikatorze comm, lub MPI_ANY_SOURCE (dowolne proces wysyłający komunikat) status zawiera dodatkowe informacje (następny slajd) Pobranie mniejszej niż count liczby wiadomości typu datatype jest prawidłowe ale pobranie większej liczby powoduje wystąpienie błędu
20
20 Pobieranie dodatkowych informacji na temat otrzymanej wiadomości status jest strukturą która wcześniej musi zostać zdefiniowana w programie użytkownika recvd_tag – znacznik wiadomości recvd_from – ranga procesu który wysłał w. recvd_count – liczba danych otrzymanych int recvd_tag, recvd_from, recvd_count; MPI_Status status; MPI_Recv(..., MPI_ANY_SOURCE, MPI_ANY_TAG,..., &status ) recvd_tag = status.MPI_TAG; recvd_from = status.MPI_SOURCE; MPI_Get_count( &status, datatype, &recvd_count );
21
21 Przykładowy program Dwa procesy, pierwszy obsługiwany przez funkcję ProcA(), wywoływany dla procesu z rangą =0, drugi ProcB() dla rangi=1 ProcB() wysyła dwie wartości do ProcA() ProcA() odczytuje je
22
22 1 #include 2 #include 3 #include 4 5 #define MY_TAG1 1 6 #define MY_TAG2 2 7 #define MASTER 0 8 9 MPI_Status* status; 10 11 void procA() 12 { 13 double wart1,wart2; 14 MPI_Recv(&wart2, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MY_TAG2,MPI_COMM_WORLD, status); 15 printf("procA: otrzymano wartosc 2 : %f\n",wart2); 16 MPI_Recv(&wart1, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MY_TAG1,MPI_COMM_WORLD, status); 17 printf("procA: otrzymano wartosc 1 : %f\n",wart1); 18 } 19 20 void procB() 21 { 22 double wart; 23 wart=100; 24 printf("procB: wysylam wartosc 1\n"); 25 MPI_Send(&wart, 1, MPI_DOUBLE, MASTER, MY_TAG1, MPI_COMM_WORLD); 26 wart=200; 27 printf("procB: wysylam wartosc 2\n"); 28 MPI_Send(&wart, 1, MPI_DOUBLE, MASTER, MY_TAG2, MPI_COMM_WORLD); 29 }
23
23 30 int main(int argc, char* argv[]) 31 { 32 int rank; 33 34 if(MPI_Init(&argc, &argv) != MPI_SUCCESS) 35 { 36 printf("MPI initialization error\n"); 37 exit(1); 38 } 39 40 MPI_Comm_rank(MPI_COMM_WORLD, &rank); 41 42 if (rank==0) procA(); 43 if (rank==1) procB(); 44 45 MPI_Finalize(); 46 47 return 0; 48 }
24
24 Wstęp do operacji kolektywnych w MPI Operacje kolektywne są wywoływane przrz wszystkie procesy w komunikatorze MPI_BCAST rozsyła dane z jednego procesu (ranga=0) to wszystkich pozostałych w komunikatorze MPI_REDUCE przetwarza dane ze wszystkich procesów w komunikatorze i wynik zwraca w jednym z procesów W wielu programach funkcje SEND/RECEIVE mogą być zamienione przez BCAST/REDUCE, powodując wzrost przejrzystości i wydajności programu
25
25 Redukcja int ierr= MPI_Reduce((void *)&sendbuf, (void *)&recvbuf, int count, MPI_Datatype type, MPI_Op op, int root,MPI_Comm comm); Obliczenie funkcji z wykorzystaniem danych wszystkich procesów w grupie comm np. suma, iloczyn itp. wartości. int ierr= MPI_Reduce((void *)&sendbuf, (void *)&recvbuf, int count, MPI_Datatype type, MPI_Op op, int root,MPI_Comm comm); W wyniku wywołania tej funkcji przez wszystkie procesy proces root otrzymuje w recvbuf wartość operacji. Rodzaj operacji zdefiniowany jest przez op, typ danych type, liczba danych count. Wartość przekazywana jest przez sendbuf.
26
26 Predefiniowane operacje MPI MPI_MAX MPI_MIN MPI_SUM MPI_PROD MPI_LAND MPI_BAND... operacjamaksimumminimumsumailoczyn Logiczna AND Bitowe AND
27
27 Przykład: obliczenie PI #include int main(int argc, char *argv[]) { int done = 0, n, myid, numprocs, i, rc; double PI25DT = 3.141592653589793238462643; double mypi, pi, h, sum, x, a; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myid); while (!done) { if (myid == 0) { printf("Enter the number of intervals: (0 quits) "); scanf("%d",&n); } MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); if (n == 0) break;
28
28 h = 1.0 / (double) n; sum = 0.0; for (i = myid + 1; i <= n; i += numprocs) { x = h * ((double)i - 0.5); sum += 4.0 / (1.0 + x*x); } mypi = h * sum; MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (myid == 0) printf("pi is approximately %.16f, Error is %.16f\n", pi, fabs(pi - PI25DT)); } MPI_Finalize(); return 0; }
29
29 Wysyłanie dużych wiadomości z procesu 0 do procesu 1 –Jeśli nie ma wystarczającego miejsca do przechowania informacji, wysyłający musi zaczekać do momentu gdy zostanie przydzielona odpowiednia ilość pamięci w procesie odbierającym (podczas instrukcji odbioru) Przykład Przyczyny zakleszczeń (deadlocks) Proces 0 Send(1) Recv(1) Proces 1 Send(0) Recv(0) Powyższy przykład jest niebezpieczny ponieważ jego prawidłowe wykonanie zależy od dostępności buforów w systemach
30
30 Przykładowe rozwiązania niebezpiecznych programów Zmiana kolejności rozkazów: Proces 0 Send(1) Recv(1) Proces 1 Recv(0) Send(0) Użycie nie-blokujących operacji: Proces 0 Isend(1) Irecv(1) Waitall Proces 1 Isend(0) Irecv(0) Waitall
31
31 Bariery Utworzenie bariery – oczekiwanie aż pozostałe procesy w grupie comm również utworzą barierę. int ierr= MPI_Barrier(MPI_Comm comm);
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.