Przetwarzanie współbieżne |
---|
Wojciech Kupczyk 94415 |
Cel:
Doskonalenie nabytych umiejętności programowania z wykorzystaniem kolektywnego przesyłania komunikatów MPI.
Zrealizowane zadania: 1-4.
Message Passing Interface (MPI) – protokół komunikacyjny będący standardem przesyłania komunikatów pomiędzy procesami programów równoległych działających na jednym lub więcej komputerach. Celami MPI są wysoka jakość, skalowalność oraz przenośność. MPI jest dominującym modelem wykorzystywanym obecnie w klastrach komputerów oraz superkomputerach.
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.
MPI nie został usankcjonowany przez żaden z głównych standardów; mimo tego został de facto standardem komunikacyjnym pomiędzy procesami w programowaniu równoległym korzystającym z rozproszonego systemu pamięci. Główny model MPI-1 nie wspiera koncepcji współdzielonej pamięci, MPI-2 wspiera (w sposób ograniczony) rozproszony system pamięci dzielonej. Mimo tego programy MPI są bardzo często uruchamiane na komputerach o współdzielonej pamięci. Projektowanie programów zgodnie z modelem MPI posiada zalety architektur NUMA.
Ad. 2. Napisz program, który po sczytaniu wpisanej liczby rozpropaguje ją w konwencji pierścienia. Proces numer i powinien dostawać liczbę i przesyłać do procesu i +1 dopóki ostatni proces nie zostanie osiągnięty. Wartości powinny być sczytywanie dopóki podana wartość nie jest ujemna. Kod programu oraz przykładowy wydruk zamieszczam poniżej.
int main(int argc, char *argv[]) { int rank, wart, size, resultlen; MPI_Status status; char *name; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); do { if (rank == 0) { scanf("%d", &wart); MPI_Send(&wart, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD); MPI_Recv(&wart, 1, MPI_INT, size - 1, 0, MPI_COMM_WORLD, &status); gethostname(name, resultlen); printf( "Proces %d dostal %d od procesu %d na maszynie %s\n", rank, wart, status.MPI_SOURCE, name); } else { MPI_Recv(&wart, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD, &status); if (rank < size - 1) MPI_Send(&wart, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD); gethostname(name, resultlen); printf( "Proces %d dostal %d od procesu %d na maszynie %s\n", rank, wart, status.MPI_SOURCE, name); if(rank== size-1) MPI_Send(&wart, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); } } while (wart > -1); MPI_Finalize(); return 0; } |
---|
Ad. 3. Opracowanie programu obliczającego liczbę Pi z szeregu Leibniza:
Proces o randze 0 powinien pobrać informację o liczbie sumowanych składników (podaną jako parametr przy uruchomieniu programu, z klawiatury itp.).Liczba składników szeregu powinna zostać równo rozdzielona między procesy liczące sumy częściowe (należy rozwiązać problem w przypadku niepodzielności liczby składników przez liczbę procesów liczących). Kod programu oraz przykładowy wydruk zamieszczam poniżej.
#include "mpi.h" #include <stdio.h> #include <math.h> int main(int argc, char *argv[]) { int n, rank, size, i; double pi_cz, pi, h, suma, x; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&size); MPI_Comm_rank(MPI_COMM_WORLD,&rank); while (1) { if (rank == 0) { printf("Wprowadź liczbę wyrazów szeregu: (0 aby wyjść\n"); scanf("%d",&n); } MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); if (n == 0) break; else { h = 1.0 / (double) n; suma = 0.0; for (i = rank + 1; i <= n; i += size) { x = h * ((double)i - 0.5); suma += (4.0 / (1.0 + x*x)); } pi_cz = h * suma; MPI_Reduce(&pi_cz, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (rank == 0) printf("Suma: %.20f\nBłąd: %.20f\n\n", pi, fabs(pi - M_PI)); } } MPI_Finalize(); return 0; } |
---|
Wnioski:
umożliwia efektywną komunikację bez obciążania procesora operacjami kopiowania pamięci
pozwala na skupienie się na samej komunikacji bez wnikania w szczegóły. Błędy są obsługiwane wewnątrz systemu
udostępnia mechanizmy komunikacji punkt - punkt oraz zbiorowej (grupy procesów)
Deklaracje funkcji są w standardzie ANSI C. Wszystkie nazwy mają przedrostek MPI_, predefiniowane stałe są zapisywane wielkimi literami, natomiast nazwy typów i funkcji mają jedną wielką literę po przedrostku. W programie nie należy deklarować funkcji ani zmiennych o nazwie rozpoczynającej się od MPI_.
Prawie wszystkie funkcje zwracają kod błędu. W przypadku sukcesu jest to MPI_SUCCESS, pozostałe kody błędu są zależne od implementacji.
Definicje funkcji, stałych i typów powinny być zawarte w pliku mpi.h.