Operacje kolektywne MPI

Podobne dokumenty
Operacje grupowego przesyłania komunikatów. Krzysztof Banaś Obliczenia równoległe 1

Programowanie Równoległe Wykład 5. MPI - Message Passing Interface. Maciej Matyka Instytut Fizyki Teoretycznej

Operacje grupowego przesyłania komunikatów

Modele programowania równoległego. Programowanie z przekazywaniem komunikatów Message-Passing Programming Rafał Walkowiak dla PR PP

Modele programowania równoległego. Programowanie z przekazywaniem komunikatów Message-Passing Programming Rafał Walkowiak

Programowanie współbieżne i rozproszone

Programowanie w modelu przesyłania komunikatów specyfikacja MPI. Krzysztof Banaś Obliczenia równoległe 1

Miary Wydajności. Efektywność programu równoległego (E) jest definiowana jako stosunek przyśpieszenia do liczby procesorów

Message Passing Interface

Tryby komunikacji między procesami w standardzie Message Passing Interface. Piotr Stasiak Krzysztof Materla

Architektura sieci połączeń między procesorami, sterowanie komunikacjami, biblioteki komunikacyjne

Programowanie współbieżne Wykład 12 MPI c.d. Rafał Skinderowicz

Przykład MPI: zbiór Mandelbrota

Programowanie Równoległe Wykład 4. MPI - Message Passing Interface. Maciej Matyka Instytut Fizyki Teoretycznej

Programowanie w modelu przesyłania komunikatów specyfikacja MPI, cd. Krzysztof Banaś Obliczenia równoległe 1

Programowanie Współbieżne

Programowanie w modelu przesyłania komunikatów specyfikacja MPI, cd. Krzysztof Banaś Obliczenia równoległe 1

Wprowadzenie do MPI. Interdyscyplinarne Centrum Modelowania Matematycznego i Komputerowego Uniwersytet Warszawski

Język C zajęcia nr 11. Funkcje

Jak wygląda praca na klastrze

Lab 8. Tablice liczbowe cd,. Operacje macierzowo-wektorowe, memcpy, memmove, memset. Wyrażenie warunkowe.

Programowanie Równoległe Wykład 5. MPI - Message Passing Interface (część 3) Maciej Matyka Instytut Fizyki Teoretycznej

51. Metody komunikacji nieblokującej.

Język C, tablice i funkcje (laboratorium)

Programowanie współbieżne... (5)

Rozszerzenia MPI-2 1

Architektury systemów równoległych

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

1 Podstawy c++ w pigułce.

Język C, tablice i funkcje (laboratorium, EE1-DI)

5. Model komunikujących się procesów, komunikaty

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk

Algorytmy równoległe: ocena efektywności prostych algorytmów dla systemów wielokomputerowych

I. Podstawy języka C powtórka

Struktura programu. Projekty złożone składają się zwykłe z różnych plików. Zawartość każdego pliku programista wyznacza zgodnie z jego przeznaczeniem.

Komunikacja kolektywna w środowisku MPI

Algorytmy równoległe: prezentacja i ocena efektywności prostych algorytmów dla systemów równoległych

utworz tworzącą w pamięci dynamicznej tablicę dwuwymiarową liczb rzeczywistych, a następnie zerującą jej wszystkie elementy,

Algorytmy numeryczne 1


Czym jest całka? Całkowanie numeryczne

Algorytmy równoległe: ocena efektywności prostych algorytmów dla systemów wielokomputerowych

Algorytmy sortujące 1

Programowanie w standardzie MPI

Wymiar musi być wyrażeniem stałym typu całkowitego, tzn. takim, które może obliczyć kompilator. Przykłady:

Programowanie współbieżne... (4) Andrzej Baran 2010/11

PARADYGMATY I JĘZYKI PROGRAMOWANIA. Programowanie współbieżne... (w13)

Metody Metody, parametry, zwracanie wartości

Złożoność obliczeniowa zadania, zestaw 2

Programowanie - wykład 4

1 Podstawy c++ w pigułce.

Programowanie w C++ Wykład 3. Katarzyna Grzelak. 12 marca K.Grzelak (Wykład 1) Programowanie w C++ 1 / 35

Optymalizacja komunikacji w systemach rozproszonych i równoległych

Łagodne wprowadzenie do Message Passing Interface (MPI)

Część 4 życie programu

Wykład 1_2 Algorytmy sortowania tablic Sortowanie bąbelkowe

Weryfikacja oprogramowania, korzystajacego z MPI

Interfejs MPI. Maciej Kasperski, Rafał Kozik. 16 kwietnia 2008

Informacje wstępne #include <nazwa> - derektywa procesora umożliwiająca włączenie do programu pliku o podanej nazwie. Typy danych: char, signed char

Zmienne, stałe i operatory

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Ćwiczenie 1. Wprowadzenie do programu Octave

Programowanie aplikacji równoległych i rozproszonych. Wykład 8

Podstawy programowania skrót z wykładów:

Lab 10. Funkcje w argumentach funkcji metoda Newtona. Synonimy nazw typów danych. Struktury. Tablice struktur.

Podstawy algorytmiki i programowania - wykład 2 Tablice dwuwymiarowe cd Funkcje rekurencyjne

Algorytmy równoległe. Rafał Walkowiak Politechnika Poznańska Studia inżynierskie Informatyka 2010

Języki i paradygmaty programowania 1 studia stacjonarne 2018/19. Lab 9. Tablice liczbowe cd,. Operacje na tablicach o dwóch indeksach.

Programowanie współbieżne... (12) Andrzej Baran 2010/11

Język C++ zajęcia nr 2

Wstęp do Programowania, laboratorium 02

Klient-Serwer Komunikacja przy pomocy gniazd

Język ANSI C tablice wielowymiarowe

wykład II uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - funkcje, tablice i wskaźniki wykład II dr Jarosław Mederski Spis

MACIERZE. Sobiesiak Łukasz Wilczyńska Małgorzata

Podstawy Programowania C++

Algorytmy Równoległe i Rozproszone Część V - Model PRAM II

Tablice i struktury. czyli złożone typy danych. Programowanie Proceduralne 1

Równoległy algorytm wyznaczania bloków dla cyklicznego problemu przepływowego z przezbrojeniami

wykład IV uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C, a C++. wykład IV dr Jarosław Mederski Spis Język C++ - wstęp

Rozwiązanie. #include <cstdlib> #include <iostream> using namespace std;

Zygmunt Kubiak Instytut Informatyki Politechnika Poznańska

Zajęcia nr 2 Programowanie strukturalne. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

RPC. Zdalne wywoływanie procedur (ang. Remote Procedure Calls )

PARADYGMATY PROGRAMOWANIA Wykład 3

Podstawy programowania. Wykład 7 Tablice wielowymiarowe, SOA, AOS, itp. Krzysztof Banaś Podstawy programowania 1

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

tablica: dane_liczbowe

Wstęp do informatyki Ćwiczenia. Piotr Fulmański

LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI. Wprowadzenie do środowiska Matlab

Zadeklarowanie tablicy przypomina analogiczną operację dla zwykłych (skalarnych) zmiennych. Może zatem wyglądać na przykład tak:

Pętle i tablice. Spotkanie 3. Pętle: for, while, do while. Tablice. Przykłady

Funkcje. Wprowadzenie. Mirosław Ochodek

W języku C dostępne są trzy instrukcje, umożliwiające tworzenie pętli: for, while oraz do. for (w1;w2;w3) instrukcja

Dla każdej operacji łącznie tworzenia danych i zapisu ich do pliku przeprowadzić pomiar czasu wykonania polecenia. Wyniki przedstawić w tabelce.

2 Przygotował: mgr inż. Maciej Lasota

Wykład 1. Systemy przekazywania wiadomości z założeniem bezbłędności działania

Podstawy Informatyki Elementarne podzespoły komputera

Zaprojektować i zaimplementować algorytm realizujący następujące zadanie.

Transkrypt:

Operacje kolektywne MPI 1

Operacje kolektywne Do tej pory w operacje przesyłania komunikatu miały charakter punkt-punkt (najczęściej pomiędzy nadawcą i odbiorcą). W operacjach grupowych udział biorą wszystkie procesy w komunikatorze; wszystkie muszą wywołać daną funkcję. Jeżeli używamy MPI_COMM_WORLD oznacza to wszystkie procesy aplikacji. Wszystkie operacje grupowe są blokujące. Niektóre są synchronizujące. Komunikaty nie mają etykiet. Procesy odbierające i nadające używają takiej samej długości komunikatu. 2

Operacja barriery int MPI_Barrier(MPI_Comm com); Jest to operacja tylko synchronizująca. Nie przesyła i nie przetwarza żadnych danych. Przypominam, że muszą wywołać wszystkie procesy w komunikatorze. Definicja jest następująca Proces może opuścić operację MPI_Barrier dopiero gdy wszystkie inne procesy w komunikatorze wywołają tę operację. Była wykorzystana w programie Mandelbrot przy pomiarze czasu. Proces 0 mierzył czas swojej funkcji Master (MPI_Wtime) Ale co się wydarzy gdy proces 0 wystartuje na maszynie jako pierwszy, a pozostałe znacznie później -> do czasu obliczeń zostanie dodany czas oczekiwania na pozostałe procesy (przy pierwszej operacji Send albo Receive). Wyjście: wszystkie procesy aplikacji po zainicjowaniu MPI, przed pomiarem czasu wykonują kod: MPI_Barrier(MPI_COMM_WORLD); 3

Operacja rozgłaszania (ang. broadcast). P 0 P 1 P 2 P 3 1 2 3 1 2 3 1 2 3 1 2 3 Jeden proces (w przykładzie o numerze 1, zwany root proces) przesyła komunikat, który otrzymują pozostałe procesy. int MPI_Bcast( void *buffer, int count, MPI_Datatype datatype, int root,mpi_comm comm). Przypominam, że funkcje muszą wywołać wszystkie procesy w komunikatorze!!! Parametr root, to numer procesu który jest nadawcą, pozostałe są odbiorcami. Wszystkie procesy muszą dostarczyć ten sam numer root. Wszystkie procesy muszą dostarczyć takie same wartości parametrów count oraz datatype. 4

Broadcast złożoność obliczeniowa Najprostsza implementacja operacji broadcast dla p procesów wysyła p komunikatów ze źródła. Złożoność jest O(p). Pseudokod: if (myrank == root) { for (int i=0;i<n;i++) if (i!= myrank) MPI_Send(buf,count,datatype,i,...,comm); } else MPI_Recv(buf, count,datatype, root,...,comm,status); Istnieją lepsze algorytmy, oparte na różnych strukturach drzewiastych. Realna złożoność jest O(log p). 5

Broadcast po drzewie binarnym - demo 2 1 1 2 3 4 3 3 2 6 4 5 5 4 5 5 6 4 4 7 3 8 9 10 11 12 13 14 15 Istnieją jeszcze lepsze algorytmy (np. teraz w krokach >2 proces 1 jest bezczynny) Drzewo rozpinające hipersześcian (4 kroki). Dla wysokiej wydajności sieć połączeń musi wspierać równoległe przesyłanie komunikatów 6

Operacja redukcji (ang. reduce). 1 1 1 2 2 2 3 3 3 P 0 P 1 9 9 9 + P 2 P 3 3 3 3 Wszystkie procesy wykonują przemienną operację na danych (np. Sumowanie) a wynik jest przesyłany do jednego procesu (root) int MPI_Reduce ( void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm ) Proces root, również przesyła dane do redukcji (jest nadawcą i odbiorcą), pozostałe są nadawcami. Operacja redukcji jest odwrotnością operacji rozgłaszania i może być wykonana w czasie O(log p) przy pomocy wydajnych algorytmów drzewiastych. 7

Operacje redukcji Operacja MPI_MAX MPI_MIN MPI_SUM MPI_PROD MPI_LAND MPI_BAND MPI_LOR MPI_BOR MPI_LXOR MPI_BXOR MPI_MAXLOC MPI_MINLOC Znaczenie Maksimum Minimum Suma Iloczyn Logiczne AND Bitowe AND Logiczne OR Bitowe OR Logical XOR Bitowe XOR Lokacja maksimum Lokacja minimum Typy danych C całkowite i zmiennoprzec. C całkowite i zmiennoprzec. C całkowite i zmiennoprzec. C całkowite i zmiennoprzec. C całkowite C całkowite i byte C całkowite C całkowite i byte C całkowite C całkowite i byte Pary danych Pary danych 8

Operacja allreduce. P 0 P 1 3 3 3 P 2 P 3 3 3 3 1 1 1 2 2 2 + 9 9 9 9 9 9 9 9 9 9 9 9 Operacja redukcji, której wynik jest wysyłany wszystkim procesom, a nie tylko jednemu. int MPI_Allreduce ( void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm ) Brak argumentu root, ponieważ wynik otrzymują wszystkie procesy. Operacja allreduce koncepcyjnie jest sekwencją operacji redukcji i operacji rozgłaszania wyniku i może być zaimplementowana w czasie O(log p) przy pomocy wydajnych algorytmów drzewiastych. 9

Operacja scan. P 0 P 1 3 3 3 P 2 P 3 3 3 3 1 1 1 2 2 2 częściowe 1 1 1 3 3 3 sumy 6 6 6 9 9 9 Jest to częściowa operacja redukcji, w której proces o numerze i otrzymuje w swoim buforze odbiorczym recvbuf redukcję danych wysłanych przez procesy 0,1,...,i. int MPI_Scan ( void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,mpi_op op, MPI_Comm comm ) Brak argumentu root, ponieważ wynik otrzymują wszystkie procesy. Operacja allreduce koncepcyjnie jest sekwencją operacji redukcji i operacji rozgłaszania wyniku i może być zaimplementowana w czasie O(log p) przy pomocy wydajnych algorytmów drzewiastych. 10

Definiowanie własnych operacji Własną operację redukcji możemy zdefiniować przy pomocy funkcji: int MPI_Op_create(MPI_User_function *function,int commute,mpi_op *op ); Parametr commute powinien być równy 1 jeżeli operacja jest przemienna. Pod adresem op zostanie zapisany identyfikator operacji do posłużenia się jako argument operacji redukcji. Parametr function jest adresem funkcji o prototypie: void MPI_User_function( void * a, void * b, int * len, MPI_Datatype *type ); która przeprowadza operację b[i]=a[i] op b[i], dla i=0..len-1. a i b są wektorami wartości typu type o długości len. Stworzoną operację, gdy nie jest już potrzebna należy zwolnić przy pomocy funkcji int MPI_Op_free( MPI_Op *op ) 11

Przykład: całkowanie metodą Monte-Carlo Całka jest przybliżana poprzez losowanie wielokrotne losowanie wartości x r z przedziału [x 1,x 2 ] i sumowanie f(x r ): Zrównoleglenie jest bardzo proste (problem żenująco równoległy ): Niech każdy proces przeprowadza losowanie i oblicza własną sumę wartości funkcji. Następnie proces 0 zsumuje (operacja redukcji) sumy cząstkowe i obliczy wartość całki mnożąc sumę przez (x 2 -x 1 ) i dzieląc przez N. Aby zademonstrować operację rozgłaszania poprosimy użytkownika o podanie liczby prób. Uwaga: należy zadbać aby generator liczb losowych w każdym procesie był zainicjalizowany innym ziarnem. W przeciwnym wypadku każdy proces będzie losowałe te same liczby i wyniki nie będą statystycznie poprawne. Uwaga: istnieją o wiele wydajniejsze algorytmy całkowania! 12

Obliczanie sum cząstkowych int rank,size,n; // N to całkowita liczba prób // Całka tej funkcji na przedziale [0,1] to pi double f(double a) { return (4.0 / (1.0 + a*a)); } double PartialSum() { int Trials=N/size,i; double sum=0.0; // Korekta, aby łączna liczba prób była równa N if (rank<n%size) Trials++; } for(i=0;i<trials;i++) { double x=drand48(); sum+=f(x); } return sum; Www Www Www 13

Funkcja main (1) int main(int argc,char *argv[]) { double t1, t2; double globalsum,sum; const double PI25DT = 3.141592653589793238462643; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&size); MPI_Comm_rank(MPI_COMM_WORLD,&rank); // Inicjalizacja przy pomocy numeru procesu, każdy proces ma inne // ziarno generatora liczb pseudolosowych srand48((rank+1)*111); // Czekamy aż wszystkie wystartują MPI_Barrier(MPI_COMM_WORLD); if (rank == 0) { // Proces 0 pyta o liczbę prób printf("podaj liczbę prób:"); fflush(stdout); scanf("%d",&n); // mierzy czas t1=mpi_wtime(); } // Proces 0 rozgłasza liczbę prób pozostałym procesom. MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD); 14

} Funkcja main (2) // Wszystkie procesy obliczają sumę częściową sum=partialsum(); // sumy częściowe wszystkich procesów są sumowane a wynik // przesyłany do procesu 0 do zmiennej global sum. MPI_Reduce(&sum,&globalsum,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD); // Proces 0 drukuje wyniki if (rank == 0) { printf("pi jest w przybliżeniu %.16f, Błąd %.16f\n", globalsum/n, fabs(globalsum/n - PI25DT)); t2=mpi_wtime(); printf("czas obliczeń = %f\n", t2-t1); } MPI_Finalize(); return 0; Wszystkie procesy (w tym proces o numerze 0) przeprowadzają obliczenia Proces 0 jest wyróżniony poprzez Wczytywanie danych (liczba prób trzeba ją przesłać innym) Drukowanie wyników (trzeba zsumować sumy cząstkowe) Pomiar czasu 15

Operacja scatter sendcnt=recvcnt=2 P 0 P 1 P 2 1 2 1 2 3 3 4 4 5 6 5 6 Jest wykonywana przy pomocy funkcji int MPI_Scatter(void *sendbuf,int sendcnt,mpi_datatype sendtype, void *recvbuf,int recvcnt,mpi_datatype recvtype,int root,mpi_comm comm); Proces źródłowy root wysyła innym procesom (i sobie) części wektora o adresie sendbuf i o długości sendcnt każda. Każdy proces otrzymuje tyle samo (recvcnt) elementów do bufora odbiorczego pod adresem recvbuf. Wszystkie procesy muszą dostarczyć identyczną wartość recvcnt. Proces o numerze i odbiera elementy począwszy od numeru i*sendcnt. 16

Operacja gather sendcnt=recvcnt=2 P 0 P 1 P 2 1 2 1 2 3 3 4 4 5 6 5 6 Odwrotność operacji scatter. Jest wykonywana przy pomocy funkcji int MPI_Gather(void *sendbuf,int sendcnt,mpi_datatype sendtype, void *recvbuf,int recvcnt,mpi_datatype recvtype,int root,mpi_comm comm); Proces źródłowy root odbiera od każdego innego procesu (i od siebie) wektor o adresie sendbuf i o długości sendcnt każda. Argument recvcnt specyfikuje liczbę elementów odebranych od pojedynczego nadawcy a nie całkowitą liczbę odebranych elementów. Elementy zostaną zapisane do bufora odbiorczego pod adresem recvbuf. Wszystkie procesy muszą dostarczyć identyczną wartość recvcnt. Proces o numerze i odbiera elementy począwszy od numeru i*sendcnt. 17

Operacja allgather sendcnt=recvcnt=2 P 0 P 1 P 2 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 Jest to operacja gather, której wynik przesyłany jest wszystkim procesom brak procesu źródłowego root. int MPI_Allgather(void *sendbuf,int sendcnt,mpi_datatype sendtype, void *recvbuf,int recvcnt,mpi_datatype recvtype,mpi_comm comm); Proces źródłowy root odbiera od każdego innego procesu (i od siebie) wektor o adresie sendbuf i o długości sendcnt każda. Argument recvcnt specyfikuje liczbę elementów odebranych od pojedynczego nadawcy a nie całkowitą liczbę odebranych elementów. Elementy zostaną zapisane do bufora odbiorczego pod adresem recvbuf. Wszystkie procesy muszą dostarczyć identyczną wartość recvcnt. Proces o numerze i odbiera elementy począwszy od numeru i*sendcnt. 18

Operacje gather i scatter ze zmienną liczbą elementów. Do tej pory zakładaliśmy, że każdy proces wysyła identyczną liczbę elementów. MPI dostarcza również operacje, w których możemy podać różną liczbę elementów dla różnych procesów. Ma ona prototyp: int MPI_Gatherv (void *sendbuf, int sendcnt,mpi_datatype sendtype, void *recvbuf, int *recvcnts, int *displs, MPI_Datatype recvtype,int root, MPI_Comm comm) Liczba wysyłanych elementów przez proces i to parametry sendcount oraz recvcnts[i] (tablica!!!). Mogą one być różne dla różnych procesów. Wartość displs[i] (tablica!!!) oznacza miejsce, w które w buforze recvbuf będą zapisane elementy wysłane przez proces i. Dostępna jest również operacja MPI_Allgatherv dla operacji allgather oraz operacja MPI_Scatterv o prototypie: int MPI_Scatterv (void *sendbuf,int *sendcnts,int *displs, MPI_Datatype sendtype,void *recvbuf,int recvcnt, MPI_Datatype recvtype, int root,mpi_comm comm ) 19

Operacja reduce-scatter 1 1 1 1 1 1 2 2 3 3 4 4 3 3 3 3 3 3 6 6 7 7 8 8 6 6 7 7 8 8 + recvcnts[0]=recvcnts[1]= =recvcnts[2]=2 Połączenie funkcji MPI_Reduce z MPI_Scatterv. Jest wykonywana przy pomocy funkcji: int MPI_Reduce_scatter ( void *sendbuf, void *recvbuf, int *recvcnts, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm ) Operacja redukcji jest wykonywana na buforze o liczbie elementów równej sumie liczb z tablicy recvcnts. Proces i otrzymuje recvcnts[i] elementów. Wszystkie procesy muszą dostarczyć te same wartości parametrów datatype, op, comm oraz identyczną tablicę recvcnts. 20

Operacja All-to-All P 0 : A 0 B 0 C 0 P 0 : A 0 A 1 A 2 P 1 : A 1 B 1 C 1 MPI_Alltoall P 1 : B 0 B 1 B 2 P 2 : A 2 B 2 C 2 P 2 : C 0 C 1 C 2 Każdy proces wykonuje jednocześnie operacje scatter/gather wysyłając części swojego bufora nadawczego sendbuf innym procesom i odbierając do bufora odbiorczego recvbuf części wysłane przez inne procesy. int MPI_Alltoall( void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcnt, MPI_Datatype recvtype,mpi_comm comm ) W powyższym przykładzie sendcount=recvcnt=1. Istnieje wersja (MPI_Alltoallv) pozwalająca na wysłanie różnej liczby elementów różnym procesom. 21

Przykład: mnożenie macierzy i wektora Kwadratowa macierz double A[N][N], Wektory double x[n], y[n]. Operacja macierzowa y=a*x; Kod szeregowy: for(int i=0;i<n;i++) { y[i]=0; for(int j=0;j<n;j++) y[i]=y[i]+a[i][j]*x[j]; } i - ty element wektora y to wynik przemnożenia i-tego wiersza macierzy A przez wektor x. y = A * x 22

Dystrybucja wierszami Każdy proces otrzymuje i przechowuje N/p (p jest liczbą procesów) wierszy macierzy A. Ponadto każdy proces otrzymuje N/p elementów wektora x oraz odpowiada za obliczenie N/p elementów wektora wynikowego y; Dystrybucja danych i wyników dla 3 procesów. y = A * x P 0 P 1 P 2 Proces P1 mógłby obliczyć wartość swoich (niebieskich) elementów wektora y, ale potrzebuje do tego całego wektora x. Podobnie w przypadku procesów P 0 oraz P 2. Idea: skorzystać z operacji MPI_Allgather, umożliwiając zgromadzenie przez wszystkie procesy całego wektora x. 23

Reprezentacja macierzy A w pamięci Pamięć jest tablicą jednowymiarową, zaś macierz A tablicą dwuwymiarową. Jak odwzorować ją w jednowymiarowej pamięci? A A 0,0 A 0,1 A 0,2 A 1,0 A 1,1 A 1,2 A 0,0 A 0,1 A 0,2 A 1,0 A 1,1 A 1,2 A 2,0 A 2,1 A 2,2 A 2,0 A 2,1 A 2,2 Deklaracja macierzy A: double *A; Alokacja pamięci macierzy NxN: A=malloc(sizeof(double)*N*N); Adresowanie elementu A i,j : (numeracja indeksów od 0) A[i*N+j] 24

Kod funkcji mnożącej (Grama i wsp.) void MultiplyRowwise(int N, double *A,double *x,double *y) // A część macierzy przechowywana przez proces // x oraz y części wektorów int np; // liczba procesów double fullx[n]; // pełny wektor x; rozszerzenie gnu języka C i C++ MPI_Comm_size(MPI_COMM_WORLD,&npes); // Liczba wierszy macierzy A oraz elementów wektorów x i y // przechowywanych przez proces int nlocal=n/np; // Zakładamy, że N dzieli się przez np // Gromadzimy wszyskie elementy wektora x w fullx; MPI_Allgather(x,nlocal,MPI_DOUBLE,fullx,nlocal,MPI_DOUBLE, MPI_COMM_WORLD); // Obliczamy elementy wektora y za które odpowiada proces for(int i=0;i<nlocal;i++) { y[i]=0.0; for(int j=0;j<n;j++) y[i]+=a[i*n+j]*fullx[j]; } } 25

Alternatywna dystrybucja macierzy kolumnami Każdy proces otrzymuje N/p kolumn macierzy A i odpowiada za N/p elementów wektorów x oraz y. y = A * x P 0 P 0 P 1 P 1 P 2 P 2 P 0 P 1 P 2 Każdy proces oblicza częściowy iloczyn skalarny dla swoich kolumn macierzy A. Częściowe iloczyny skalarne są sumowane funkcją MPI_Reduce dając wektor y Wektor y jest rozpraszany pomiędzy procesy funkcją MPI_Scatter. Kod zostawiam jako pracę domową. 26