PRiR dla maszyn DM i sieci komputerowych. (PRiR, wykład 5)

Podobne dokumenty
51. Metody komunikacji nieblokującej.

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

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

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

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

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

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

Klient-Serwer Komunikacja przy pomocy gniazd

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

Kolejne funkcje MPI 1

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

Programowanie w standardzie MPI

Literatura uzupełniająca: W. Richard Stevens, Programowanie zastosowań sieciowych w systemie Unix WNT 1998

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

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

Iteracyjny serwer TCP i aplikacja UDP

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

Gniazda BSD. komunikacja bezpołączeniowa

61 Topologie wirtualne

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

Gniazda UDP. Bartłomiej Świercz. Łódź, 3 kwietnia Katedra Mikroelektroniki i Technik Informatycznych. Bartłomiej Świercz Gniazda UDP

Rozszerzenia MPI-2 1

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

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

Programowanie przy użyciu gniazdek

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

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

Komunikacja międzyprocesowa. Krzysztof Banaś Systemy rozproszone 1

Programowanie sieciowe

IPC: Kolejki komunikatów

Programowanie Sieciowe 1

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

Message Passing Interface

Jak wygląda praca na klastrze

Operacje grupowego przesyłania komunikatów

Podstawowe typy serwerów

Łagodne wprowadzenie do Message Passing Interface (MPI)

Tryb bezpołączeniowy (datagramowy)

Programowanie równoległe i rozproszone. Praca zbiorowa pod redakcją Andrzeja Karbowskiego i Ewy Niewiadomskiej-Szynkiewicz

Laboratorium Systemów Operacyjnych. Ćwiczenie 4. Operacje na plikach

Komunikacja sieciowa - interfejs gniazd

Oprogramowanie komunikacyjne dla Internetu rzeczy Laboratorium nr 4 komunikacja unicastowa IPv6

Aplikacja Sieciowa wątki po stronie klienta

Gniazda BSD implementacja w C#

Gniazda surowe. Bartłomiej Świercz. Łódź,9maja2006. Katedra Mikroelektroniki i Technik Informatycznych. Bartłomiej Świercz Gniazda surowe

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

Architektura typu klient serwer: przesyłanie pliku tekstowo oraz logowania do serwera za pomocą szyfrowanego hasła

Zwielokrotnianie wejścia wyjścia

Mechanizmy pracy równoległej. Jarosław Kuchta

Aplikacja Sieciowa. Najpierw tworzymy nowy projekt, tym razem pracować będziemy w konsoli, a zatem: File->New- >Project

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

Zdalne wywoływanie procedur RPC

Zdalne wywoływanie procedur RPC

Instytut Teleinformatyki

Zdalne wywoływanie procedur RPC. Dariusz Wawrzyniak 1

Opis protokołu RPC. Grzegorz Maj nr indeksu:

Zdalne wywoływanie procedur RPC 27. października Dariusz Wawrzyniak (IIPP) 1

S Instrukcje programowania instrukcje obsługi Ethernetu

Zdalne wywoływanie procedur RPC 27. października 2010

Gniazda BSD. Procesy w środowisku sieciowym. Gniazda podstawowe funkcje dla serwera. Gniazda podstawowe funkcje dla klienta

Wywoływanie procedur zdalnych

Sieci komputerowe. Wykład 7: Transport: protokół TCP. Marcin Bieńkowski. Instytut Informatyki Uniwersytet Wrocławski

Obliczenia równoległe i rozproszone. Praca zbiorowa pod redakcją Andrzeja Karbowskiego i Ewy Niewiadomskiej-Szynkiewicz

Pliki. Funkcje tworzące pliki i operujące na nich opisane są w części 2 pomocy systemowej. Tworzenie i otwieranie plików:

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

3. Identyfikacja. SKŁADNIA #include <sys/socket.h> int getpeername(int socket, struct sockaddr *addr, int *addrlen);

Wywoływanie procedur zdalnych

Programowanie współbieżne i rozproszone

Szablony klas, zastosowanie szablonów w programach

Obsługa plików. Systemy Operacyjne 2 laboratorium. Mateusz Hołenko. 25 września 2011

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

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

SYSTEMY CZASU RZECZYWISTEGO - VxWorks

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

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Wywoływanie procedur zdalnych

TCP - receive buffer (queue), send buffer (queue)

Działanie systemu operacyjnego

Kolejki FIFO (łącza nazwane)

Krótkie wprowadzenie do korzystania z OpenSSL

Przesyłania danych przez protokół TCP/IP

Wstęp do Programowania, laboratorium 02

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

Politechnika Łódzka. Instytut Systemów Inżynierii Elektrycznej

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

Działanie systemu operacyjnego

ARP Address Resolution Protocol (RFC 826)

Tworzenie aplikacji rozproszonej w Sun RPC

Lab 9 Podstawy Programowania

Działanie systemu operacyjnego

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).


4. Procesy pojęcia podstawowe

Instrukcja do laboratorium Systemów Operacyjnych. (semestr drugi)

Programowanie współbieżne Wykład 11 Wprowdzenie do MPI. Rafał Skinderowicz

Zadanie 2: transakcyjny protokół SKJ (2015)

Weryfikacja oprogramowania, korzystajacego z MPI

Instrukcja do laboratorium Systemów Operacyjnych (semestr drugi)

4. Procesy pojęcia podstawowe

Transkrypt:

PRiR dla maszyn DM i sieci komputerowych (PRiR, wykład 5) 1

Program na dziś (?) Wprowadzenie Mechanizm gniazdek Interfejs MPI Koncepcja i zasady Komunikatory i grupy Tryby komunikacji Własne typy danych Topologie wirtualne 2

Wprowadzenie Jawne przekazywanie danych między nadawcą i odbiorcą. Brak konieczności synchronizowania dostępu do danych. Przekazywanie komunikatów Wywołanie zdalnej procedury Rozproszona baza danych (przestrzeń krotek) 3

Mechanizm gniazdek Sockets Interfejs do przekazywania danych między procesami działającymi na różnych komputerach. Komunikacja dwoma sposobami: z tworzeniem połączenia i bezpołączeniowo: rozstrzygnięcie w momencie tworzenia gniazdka. Przed wysłaniem danych należy: utworzyć gniazdko, przydzielić mu numer portu, utworzyć połączenie (jeśli tryb połączeniowy). 4

Tworzenie gniazdek #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); type: SOCK_STREAM - połączeniowe SOCK_DGRAM - pakietowe (bezpołączeniowe) SOCK_RDM - j/w, ale bezpieczne, ale bez gwar. kolejności SOCK_SEQPACKET - j/w ale kolejność, pakiety o stałej długości SOCK_RAW - jasne SOCK_PACKET - przestarzałe domain: PF_UNIX, PF_LOCAL PF_INET PF_INET6 PF_IPX PF_NETLINK PF_X25 PF_AX25 PF_ATMPVC PF_APPLETALK PF_PACKET Local communication IPv4 Internet protocols IPv6 Internet protocols IPX - Novell protocols Kernel user interface device ITU-T X.25 / ISO-8208 protocol Amateur radio AX.25 protocol Access to raw ATM PVCs Appletalk Low level packet interface protocol: - Zwykle 0 == domyślny protokół dla danej kombinacji domain/type Zwraca nr gniazdka w razie sukcesu i -1 w razie porażki (wtedy zapala też errno) Identyfikator gniazdka jest traktowany jak deskryptor pliku (funkcje open, read, write, close). Mogą występować różnice związane z wersją sytemu UNIX. 5

Przesyłanie bezpołączeniowe #include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen); Związanie gniazdka z portem funkcja bind: wiąże gniazdko socketfd z adresem lokalnym wskazywanym przez my_addr, faktyczny typ my_addr zależy od rodzaju gniazdka strukturę właściwą dla danej formy adresowej należy wypełnić i podać wskazanie na nią funkcji bind (po przerzutowaniu na strukturę sockaddr), argument addrlen określa rozmiar aktualnej struktury zawierającej adres. 6

Struktura opisująca adresy gniazdek struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address }; // IPv4 AF_INET sockets: struct sockaddr_in { short sin_family; // e.g. AF_INET, AF_INET6 unsigned short sin_port; // e.g. htons(3490) struct in_addr sin_addr; // see struct in_addr, below char sin_zero[8]; // zero this if you want to }; struct in_addr { unsigned long s_addr; }; // load with inet_pton() 7

Wysyłanie #include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); Funkcja sendto: wysyła z gniazdka s len bajtów z bufora pod adresem buf do gniazdka związanego z adresem wskazanym przez to, argument to powinien wskazywać na strukturę odpowiadającą właściwej formie adresowej, tolen długość tej struktury, funkcja zwraca liczbę wysyłanych bajtów, argument flags (np. MSG_DONTROUTE) zwykle jest równy 0. 8

Odbieranie #include <sys/types.h> #include <sys/socket.h> ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); Funkcja recvfrom: funkcja wypełnia strukturę from adresem nadawcy danych, pierwszy pakiet z kolejki jest wpisywany pod adres buf, len długość tego bufora, dane nadmiarowe (>len) są gubione, funkcja zwraca liczbę odebranych bajtów, pod fromlen wpisywana jest długość struktury z adresem nadawcy, określa ona też długość bufora na ten adres przeznaczonego, jeśli kolejka jest pusta funkcja czeka (domyślnie). 9

Ograniczenia komunikacji bezpołączeniowej Transmisja protokołem UDP. Kontrola poprawności należy do aplikacji. Ograniczony rozmiar porcji danych, limitowany własnościami protokołu i sieci. 10

Komunikacja połączeniowa Operacja asymetryczna - utworzenie połączenia między dwoma gniazdkami: jeden proces (serwer) wykonuje funkcję listen czeka na połączenie, drugi proces (klient) nawiązuje połączenie przez wywołanie funkcji connect, serwer tworzy połączenie funkcja accept Symetryczna wymiana danych send recv 11

Krok 1 (Serwer) #include <sys/socket.h> int listen(int sockfd, int backlog); gniazdko sockfd będzie przechowywać backlog żądań utworzenia połączenia, sockfd musi być typu SOCK_STREAM lub SOCK_SEQPACKET Jeżeli kolejka się przepełni klient dostanie błąd (ERRCONREFUSED) lub jeśli używany protokół umożliwia retransmisję żądanie będzie zignorowane 12

Krok 2 (Klient) #include <sys/types.h> #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen); wysyła do gniazdka o adresie określonym przez serv_addr żądanie utworzenia połączenia i czeka na potwierdzenie, gniazdko klienta sockfd może nie być związane z żadnym adresem przydzieli go funkcja connect. 13

Krok 3 (Serwer) #include <sys/types.h> #include <sys/socket.h> int accept(int s, struct sockaddr *addr, socklen_t *addrlen); tworzy połączenie zwracając nowy deskryptor pliku na podstawie s, zgłoszonego przez listen, funkcja czeka na żądanie, pobiera je z kolejki, tworzy połączenie i pod adres addr wpisuje adres klienta, informując aplikację, który klient został podłączony, następnie wysyła klientowi potwierdzenie i kończy działanie zwracając nowe połączone gniazdko, stare gniazdko s nadal przyjmuje żądania utworzenia kolejnych połączeń z klientami. 14

Krok 4 (symetryczne przesyłanie danych) Funkcje send i recv działają podobnie do sendto i recvfrom, ale nie wymagają podawania adresów. #include <sys/types.h> #include <sys/socket.h> ssize_t send(int s, const void *buf, size_t len, int flags); #include <sys/types.h> #include <sys/socket.h> ssize_t recv(int s, const void *buf, size_t len, int flags); 15

Przykład Tu pokazać przykład tcpclient.c tcpserver.c 16

Obsługa wielu gniazdek jednocześnie Odczytywanie połączeń w nie narzuconej z góry kolejności można zrealizować przez: przepytywanie, funkcję select, użycie wielu procesów lub wątków, komunikację asynchroniczną. 17

Przepytywanie Polling okresowe sprawdzanie stanu połączeń i w chwili wykrycia odpowiedniego stanu podjęcie działania (obciąża procesor). Sprawdzanie można zrealizować przez: wykonanie próby nie blokującego odczytu; najpierw gniazdko należy przestawić w tryb nie blokujący funkcją ioctl z komendą FIONBIO, sprawdzenie liczby danych dostępnych do odczytu z gniazdka bez blokowania; za pomocą funkcji ioctl z komendą FIONREAD. 18

Funkcja select Umożliwia bierne oczekiwanie przez zadany czas na wystąpienie jednej z poniższych sytuacji (należy podać 3 zbiory gniazdek): pojawienie się danych wejściowych w jednym z gniazdek pierwszego zbioru, pojawienie się miejsca w buforach wyjściowych w jednym z gniazdek drugiego zbioru, wystąpienie sytuacji wyjątkowej (np. danych pilnych, zamknięcia drugiego końca połączenia) w jednym z gniazdek trzeciego zbioru, upłynięcie podanego czasu oczekiwania. Funkcja pozostawia w zbiorach deskryptory tych gniazdek, dla których występują sytuacje powodujące jej zakończenie. Funkcja zwraca sumę ilości gniazdek pozostałych we wszystkich zbiorach (0 gdy upłynął czas). Czas oczekiwania: -1 funkcja czeka w nieskończoność. 19

select /* Zgodnie z POSIX 1003.1-2001 */ #include <sys/select.h> /* Zgodnie z wcześniejszymi standardami */ #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int select(int nfds, /* max fds + 1 */ fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 20

Przykład 21

Użycie wielu procesów lub wątków Utworzenie dodatkowego procesu lub wątku, kopiującego dane z obiektu (np. gniazdka), na które czekamy do nowego gniazdka: pozwala to obsługiwać nie tylko deskryptory gniazdek, ale także stan np. semaforów, kolejek komunikatów, funkcja select może już oczekiwać na dane z tego gniazdka. Wada zużywanie znacznych zasobów pamięci. 22

Komunikacja asynchroniczna Pozwala procesowi reagować na nową sytuację przerywając aktualnie wykonywane zadanie. W systemie UNIX realizowane za pomocą sygnałów: należy ustawić procedurę obsługi sygnału SIGPOLL (SIGIO) za pomocą funkcji signal, przełączyć interesujące gniazdka na tryb nie blokujący, ustawić proces odbierający sygnał dla tych gniazdek, ustalić, jakie zdarzenia chcemy obsługiwać w tych gniazdkach. Gdy w jednym z podanych gniazdek wystąpi wybrana sytuacja, zostanie wywołana procedura obsługi sygnału, która wykona odpowiednie czynności. 23

Komunikacja asynchroniczna wątki Proces tworzy nowy wątek, a sam kontynuuje główne zadanie. Wątek czeka (blokująco) na wybraną sytuację na jednym z gniazdek, używając funkcji select. Po wystąpieniu zdarzenia wątek obsługuje go. Pozwala to na ochronę danych sekcją krytyczną stosowanie sygnałów na to nie pozwala (procedura obsługi nie czeka na zwolnienie zasobów przez przerwane zadanie.) 24

Interfejs MPI Message Passing Interface opracowany przez MPI Forum (1994) standard interfejsu do przesyłania komunikatów w rzeczywistych i wirtualnych maszynach równoległych z pamięcią rozproszoną (DM). Biblioteka procedur i funkcji wywoływanych z programów napisanych w językach Fortran, C/C++ służących do obsługi komunikatów i synchronizacji zadań wykonujących najczęściej ten sam program (SPMD). http://www.mpi-forum.org/ 25

Protoplaści i historia MPI 1992 Supercomputing 92 1994 MPI-1 1998 MPI-2 2002 pierwsza pełna implementacja MPI-2 2008 (wrzesień) MPI 1.3 i MPI-2.1 26

Implementacje MPI Istniejące standardy: MPI-1 (1.3) przekazywanie komunikatów, statyczne środowisko MPI-2 (2.1) równoległe we/wy, zarządzanie procesami, zdalne operacje na pamięci Obecnie funkcjonują implementacje realizują wersję 1.2 standardu MPI np. MPICH. Ale istnieją także implementacje standardu 2.0 np. OpenMPI (Roadrunner!), LAM. Implementacje producentów sprzętu są optymalizowane pod kątem sprzętowych rozwiązań (sieci) komunikacyjnych i architektury (topologii) danego systemu. 27

Roadrunner: 1.144 petaflop/s (węzły po 2 AMD OpteronTM dual-core + 4 PowerXCell 8iTM, Linux) 28

Kompilacja i uruchomienie Sposób kompilacji zależy od implementacji, np. $ mpicc myprog.c Sposób uruchamiania zadań zależy od implementacji, np. $ mpirun -np 10 a.out liczba kopii może być większa od liczby dostępnych procesorów. 29

Wywołania funkcji MPI Prawie wszystkie funkcje MPI zwracają kod błędu: w C jako wartość funkcji, w Fortranie jako wartość ostatniego argumentu. Przed zwróceniem wartości wywoływana jest bieżąca procedura obsługi błędu: standardowo powoduje przerwanie zadania, ustawienie uchwytu MPI_ERRORS_RETURN spowoduje zwracanie kodu błędu. MPI nie gwarantuje dalszego działania dla błędu. W razie powodzenia zwracany jest MPI_SUCCESS. 30

Format funkcji MPI int error; error = MPI_Xxxxx(parametr,...); MPI_Xxxxx(parametr,...); 31

Struktura aplikacji MPI 32

/* Standardowy pierwszy przyklad MPI - Hello world */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "mpi.h" main(int argc, char **argv) { char message[20]; int i, rank, size, type = 99; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) { strcpy(message, "Hello, world"); for (i = 1; i < size; i++) MPI_Send(message, 13, MPI_CHAR, i, type, MPI_COMM_WORLD); } else MPI_Recv(message, 20, MPI_CHAR, 0, type, MPI_COMM_WORLD, &status); printf("message from process =%d : %.13s\n", rank, message); MPI_Finalize(); } return 0; 33

jstar@edi:~/prir/mpi$ mpicc p1.c jstar@edi:~/prir/mpi$ mpirun -np 4 a.out Message from process =0 : Hello, world Message from process =1 : Hello, world Message from process =2 : Hello, world Message from process =3 : Hello, world jstar@edi:~/prir/mpi$ mpirun -np 7 a.out Message from process =0 : Hello, world Message from process =1 : Hello, world Message from process =2 : Hello, world Message from process =3 : Hello, world Message from process =4 : Hello, world Message from process =6 : Hello, world Message from process =5 : Hello, world jstar@edi:~/prir/mpi$ mpirun -np 17 a.out Message from process =0 : Hello, world Message from process =2 : Hello, world Message from process =4 : Hello, world Message from process =6 : Hello, world Message from process =7 : Hello, world Message from process =11 : Hello, world Message from process =12 : Hello, world Message from process =13 : Hello, world Message from process =14 : Hello, world Message from process =5 : Hello, world Message from process =1 : Hello, world Message from process =8 : Hello, world Message from process =3 : Hello, world Message from process =10 : Hello, world Message from process =9 : Hello, world Message from process =15 : Hello, world Message from process =16 : Hello, world jstar@edi:~/prir/mpi$ 34

MPI jest proste! Dla wielu aplikacji wystarcza użycie tylko 6 funkcji: MPI_Init MPI_Finalize MPI_Comm_size MPI_Comm_rank MPI_Send MPI_Recv 35

Ale Opis standardu 1.3 to prawie 250 stron Opis standardu 2.1 to prawie 600 stron Wszystkich funkcji w 1.3 jest ponad 100 W 2.1 jest ich jeszcze więcej - 5 i pół strony w dwóch kolumnach, po jakieś 30 funkcji w kolumnie 36

Inicjacja biblioteki MPI Funkcja MPI_Init: argumentami są wskazania na argumenty funkcji main, funkcja MPI_Init może zmienić te argumenty, interpretując argumenty przekazane dla biblioteki MPI i pozostawiając argumenty przeznaczone dla procesu. Funkcja MPI_Init powinna być wywołana jak najwcześniej w programie: należy unikać operacji na pamięci przed jej wywołaniem. jak większość funkcji MPI zwraca stałą int o wartości MPI_SUCCESS w przypadku pomyślnego wykonania. #include "mpi.h main(int argc, char **argv) { MPI_Init(&argc, &argv); 37

Zakończenie pracy biblioteki MPI Funkcja MPI_Finalize: kończy współpracę procesu z biblioteką MPI i zwalnia używane przez nią zasoby; żadne funkcje MPI nie mogą być użyte po wywołaniu MPI_Finalize. #include "mpi.h" main(int argc, char **argv) { MPI_Init(&argc, &argv); MPI_Finalize(); return 0; } 38

Komunikatory i grupy 39

Komunikatory i grupy procesów Komunikator grupa procesów plus pewien kontekst (topologia wirtualna): komunikat wysłany z danym kontekstem może być odebrany tylko przy użyciu tego samego kontekstu (komunikatora); kontekst przechowuje argumenty nadane przez aplikację, które mogą być w dowolnej chwili odczytywane. Komunikatory są identyfikowane przez uchwyty typu MPI_Comm: w każdej implementacji powstaje komunikator MPI_COMM_WORLD obejmujący wszystkie procesy, oraz MPI_COMM_SELF obejmujący tylko używający go proces (i MPI_COMM_NULL zwracany przy błędzie). 40

Grupa procesów Zbiór procesów każdy proces w grupie posiada swój indeks. Indeksy są w grupie ciągłe w zakresie od zera do liczby procesów w grupie zmniejszonej o jeden. Grupy są identyfikowane przez uchwyt o typie MPI_Group: predefiniowana grupa o uchwycie MPI_GROUP_EMPTY nie zawiera żadnego procesu, uchwyt MPI_GROUP_NULL jest zwracany gdy nie można utworzyć grupy. 41

Operacje na grupach Funkcja MPI_Comm_group: wpisuje pod adres group uchwyt do grupy związanej z komunikatorem comm. Funkcja MPI_Group_size: wpisuje pod adres size liczbę procesów w grupie group. Funkcja MPI_Group_rank: pod adresem rank wpisuje indeks procesu, który ją wywołuje w grupie group (jeśli nie należy do niej wpisywana jest wartość MPI_UNDEFINED). 42

Operacje na grupach (2) MPI_Group_union MPI_Group_intersection MPI_Group_difference Kolejność procesów w nowej grupie jest taka sama jak w group1, a dla sumy następne są procesy z group2, nie będące w group1. 43

Operacje na grupach (3) Funkcja MPI_Group_incl: tworzy grupę newgroup z n procesów grupy group o indeksach podanych w tablicy ranks, kolejność procesów jest taka jak w tablicy ranks, funkcja pozwala zmienić kolejność procesów. Funkcja MPI_Group_excl: tworzy grupę newgroup przez usunięcie n procesów o indeksach podanych w tablicy ranks. Funkcja MPI_Group_free: usuwa grupę group i zwalnia zasoby, pod zwolniony adres wpisuje MPI_GROUP_NULL. 44

Operacje na komunikatorach Funkcja MPI_Comm_size: pod adresem size wpisuje liczbę procesów w komunikatorze comm. Funkcja MPI_Comm_rank: pod adresem rank wpisuje identyfikator wywołującego ją procesu w komunikatorze comm. W/w operacje mają charakter lokalny. 45

Operacje na komunikatorach (2) Operacje kolektywne muszą być wykonywane we wszystkich procesach komunikatora comm będącego pierwszym argumentem funkcji. Funkcja MPI_Comm_dup: Tworzy kopię comm i umieszcza uchwyt do niej pod adresem newcomm, kopia zawiera te same procesy w tej samej kolejności ale w nowym kontekście. 46

Komunikatory wewnętrzne Funkcja MPI_Comm_create: tworzy komunikator wewnętrzny, używający grupy group, grupa group powinna być identyczna (skład, kolejność) we wszystkich wywołujących ją kolektywnie oraz być podgrupą grupy wewnętrznego komunikatora comm, funkcja powinna być wołana przez wszystkie procesy komunikatora comm, uchwyt do nowego komunikatora jest wpisywany pod adresem newcomm, komunikator wewnętrzny nie może być używany przez procesy nie należące do jego grupy (w tych procesach pod adresem newcomm wpisywana jest wartość MPI_COMM_NULL). 47

Komunikatory wewnętrzne (2) Funkcja MPI_Comm_split: "dzieli" grupę skojarzoną z komunikatorem comm według color na nowe rozłączne grupy o komunikatorze (dla danej grupy) wskazywanym przez newcomm, procesy podające tę samą wartość color (>0) będą należeć do tego samego komunikatora (jeśli wartość jest MPI_UNDEFINED to do żadnego: MPI_COMM_NULL), kolejność procesów w utworzonych komunikatorach jest zdefiniowana przez argument key, który ma priorytet w stosunku do kolejności w komunikatorze. 48

Przykłady color = (rank < size/2)? 0 : 1; MPI_Comm_split(comm, color, 0, &newcomm); color = (rank % 2 == 0)? 0 : 1; key = size - rank; MPI_Comm_split(comm, color, key, &newcomm); 49

Operacje na komunikatorach (3) Funkcja MPI_Comm_free: zwalnia komunikator (zewnętrzny lub wewnętrzny) o uchwycie umieszczonym pod adresem comm i wpisuje tam wartość MPI_COMM_NULL, funkcja ma charakter kolektywny, może być wywołana gdy są wykonywane operacje z tym komunikatorem (usunięcie zostanie opóźnione). 50

Komunikatory zewnętrzne Służą do przesyłania komunikatów między dwoma procesami należącymi do różnych grup. Komunikator zawiera dwie rozłączne grupy procesów: grupa lokalna zawiera proces wywołujący daną funkcję, grupa zdalna. Funkcje kolektywne przeważnie nie mogą używać komunikatorów zewnętrznych. 51

int MPI_Comm_test_inter ( comm, flag ) Komunikatory zewnętrzne (2) Funkcja lokalna MPI_Comm_test_inter: pod adresem result wpisuje true, jeśli komunikator comm jest zewnętrzny, lub false, jeśli jest wewnętrzny. int MPI_Comm_test_inter (MPI_Comm comm, int *flag ) Funkcje MPI_Comm_remote_size (rozmiar grupy zdalnej komunikatora) i MPI_Comm_remote_group (uchwyt do grupy zdalnej) są zewnętrznymi odpowiednikami wersji lokalnych. Nie istnieje odpowiednik funkcji MPI_Comm_rank. 52

Komunikatory zewnętrzne (3) Funkcja MPI_Intercomm_create: tworzy komunikator zewnętrzny o uchwycie umieszczanym pod adresem newintercomm, kolektywna wołana przez członków grupy zdalnej i lokalnej, uchwyt local_comm oznacza komunikator grupy lokalnej dla wywołującego procesu, obie grupy muszą mieć wyróżnionych liderów: local_leader i remote_leader (należące do grupy komunikatora peer_comm), musi istnieć komunikator wewnętrzny peer_comm, zawierający obie grupy (najczęściej jest to kopia MPI_COMM_WORLD), etykieta tag nadawana komunikatom przesyłanym podczas tworzenia komunikatora nie może kolidować z innymi odebranymi przez komunikator peer_comm. 53

Komunikatory zewnętrzne (4) Funkcja MPI_Intercomm_merge: przekształca komunikator zewnętrzny intercomm w wewnętrzny, nowoutworzony komunikator wewnętrzny newintracomm zawiera procesy obu grup, funkcja działa kolektywnie, wartości argumentu high powinny w jednej z grup mieć wartość true (efekt: wyższe indeksy) w drugiej false (niższe indeksy). 54

Przesyłanie komunikatów Wzajemna synchronizacja stron: komunikacja synchroniczna nadawca czeka na gotowość odbiorcy i kończy wysyłanie komunikatu gdy odbiorca potwierdza odbiór, komunikacja asynchroniczna nadawca wysyła komunikat i nie oczekuje potwierdzenia odbioru. Warunek powrotu z funkcji wysyłanie/odbiór: komunikacja blokująca powrót z funkcji następuje po zakończeniu operacji (funkcja czeka na rezultat swojego działania), komunikacja nie blokująca powrót z funkcji następuje natychmiast. 55

Tryby komunikacji MPI Możliwe są różne kombinacje trybów wysyłania i odbierania komunikatów, np. : nieblokujące, synchroniczne wysyłanie oraz blokujące odbieranie, blokujące, asynchroniczne wysyłanie oraz nieblokujące odbieranie, i inne. 56

Przykład możliwego buforowania 57

Komunikacja blokująca Funkcja MPI_Send: blokująco* i asynchronicznie wysyła komunikat umieszczony pod adresem buf, zawierający count danych typu datatype, do procesu o identyfikatorze dest w komunikatorze comm, jeśli komunikator jest wewnętrzny, to nadawca i odbiorca muszą należeć do jego grupy; jeśli zewnętrzny, to nadawca musi należeć do jednej z jego grup, a odbiorca do drugiej, argument tag określa etykietę nadawaną komunikatowi (wartość z zakresu 0..MPI_TAG_UB), * buforowanie może być realizowane przez implementację, o ile pozwalają na to dostępne zasoby. 58

Funkcja MPI_Send int MPI_Send( void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm ); MPI_Send(&sum, 1, MPI_INT, 0, 1, MPI_COMM_WORLD); 59

Standardowe typy danych * - zależne od implementacji MPI (*) bez konwersji dane spakowane bez konwersji dane spakowane 60

Komunikacja buforowana, synchroniczna i natychmiastowa Funkcja MPI_Bsend: (B buffered) asynchronicznie wysyła komunikat w trybie buforowanym; nadawcy jest przydzielany odpowiednio duży bufor na wysyłane dane, bufor musi być przydzielony wcześniej. Funkcja MPI_Ssend: (S synchronous) przesyła komunikat w trybie synchronicznym. Funkcja MPI_Rsend: (R ready) przesyła komunikat natychmiastowo, odbiorca musi już wykonywać funkcję odbierającą. 61

Porównanie tryb synchroniczny tryb buforowany tryb natychmiastowy 62

Odbiór blokujący Funkcja MPI_Recv: służy do odczytu blokującego (syn- i asynchronicznego), funkcja czeka na wysłanie przez proces o identyfikatorze source z komunikatora comm komunikatu z etykietą tag, dane z komunikatu są (ewentualnie) przekształcane na lokalną reprezentację i umieszczane pod adresem buf, wartość datatype musi być identyczna jak w funkcji wysyłającej; argument count może być większy, argument status wskazuje na strukturę, która jest wypełniana przez funkcję informacjami identyfikatorze nadawcy, etykiecie komunikatu i kodzie błędu. 63

Funkcja MPI_Recv int MPI_Recv( void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status ) MPI_Recv(&accum, 1, MPI_INT, j, 1, MPI_COMM_WORLD, &status); 64

Argumenty MPI_Recv Argument source: MPI_ANY_SOURCE odbiór od dowolnego nadawcy. Argument tag: MPI_ANY_TAG odczyt komunikatu o dowolnej etykiecie. Argument status: status.mpi_source identyfikator nadawcy, status.mpi_tag etykieta odebranego komunikatu, status.mpi_error kod błędu (o ile funkcja zwróci wartość MPI_ERR_IN_STATUS). 65

Funkcja MPI_Get_count int MPI_Get_count( MPI_Status *status, MPI_Datatype datatype, int *count ); wypisuje pobraną ze struktury MPI_Status wartość argumentu count, użytą podczas wysyłania komunikatu i umieszcza ją pod wskazanym adresem, pozwala to odczytać ilość rzeczywiście przesłanych danych. 66

Przydzielanie buforów Funkcja MPI_Buffer_attach: przydziela bufor (tylko jeden w procesie) wskazywany przez adres buf o rozmiarze przynajmniej size bajtów, bufor będzie wykorzystywany przy przesyłaniu komunikatów w trybie buforowanym. Funkcja MPI_Buffer_detach: pozwala odzyskać pamięć przydzieloną na bufor, pod adres buf_addr wpisuje adres poprzedniego bufora, a pod adres size jego rozmiar. 67

Dobór rozmiaru bufora Rozmiar buforu musi być powiększony o nagłówek dla każdego komunikatu. Rozmiar nagłówka jest określony stałą MPI_BSEND_OVERHEAD. Przykład: (niektóre funkcje objaśnione dalej) 68

Komunikacja nieblokująca Funkcje nieblokujące różnią się od wersji blokujących przedrostkiem I (immediate) w nazwie oraz jednym dodatkowym argumentem: request, który jest używany do sprawdzenia (za pomocą funkcji MPI_Wait), czy dana operacja została zakończona. 69

Funkcje nieblokujące Funkcja MPI_Isend: (standardowa) Funkcja MPI_Ibsend: (buforowana) Funkcja MPI_Issend: (synchroniczna) Funkcja MPI_Irsend: (natychmiastowa) 70

Odbiór nieblokujący Funkcja MPI_Irecv: nie ma argumentu MPI_Status, może odbierać także komunikaty wysyłane w sposób blokujący (i vice-versa). 71

Komunikacja nieblokująca (2) Funkcja MPI_Wait: pozwala czekać na zakończenie nie blokującej operacji (wysyłania, odbioru) wskazanej przez argument request, pod adresem status wpisuje status zakończonej operacji, po zakończeniu funkcja wpisuje po adresem request wartość MPI_REQUEST_NULL. int MPI_Wait(MPI_Request *request, MPI_Status *status); 72

int MPI_Wait(MPI_Request *request, MPI_Status *status) Komunikacja nieblokująca (3) Funkcja MPI_Test: jeśli operacja o uchwycie wskazywanym przez request skończyła się, to funkcja działa jak MPI_Wait i dodatkowo pod adresem flag wpisuje wartość true, jeśli operacja się nie zakończyła, funkcja pod adresem flag wpisuje false i powraca. int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status); Jeśli funkcje MPI_Wait i MPI_Test sygnalizują zakończenie operacji, to następuje zwolnienie zajmowanych przez nią zasobów. Jawnie można zwolnić zasoby funkcją MPI_Request_free. int MPI_Request_free(MPI_Request *request); 73

Komunikacja nieblokująca (4) Funkcja MPI_Waitany: czeka na zakończenie jakiejkolwiek z count operacji na uchwytach przekazanych w tablicy array_of_requests, indeks (z array_of_requests) zakończonej operacji jest zapisywany pod adresem index, status operacji jest zapisywany pod adresem status, jeśli kilka operacji się zakończyło, funkcja wybiera tylko jedną z nich (dla pozostałych można wywołać ją ponownie), zasoby są zwalniane, a w odpowiednią pozycję tablicy array_of_requests wpisywane MPI_REQUEST_NULL. 74

Komunikacja nieblokująca (5) Funkcja MPI_Testany Funkcja MPI_Waitall Funkcja MPI_Testall 75

Anulowanie komunikacji Funkcja MPI_Cancel: pozwala przerwać oczekującą nie blokującą komunikację, nie oznacza to zwolnienia zasobów (należy jeszcze użyć MPI_Request_Free, MPI_Wait lub MPI_Test), użycie tej funkcji może znacznie spowalniać wykonanie, nie należy jej nadużywać, sprawdzenie, czy anulowanie się powiodło umożliwia funkcja MPI_Test_cancelled: jeśli po powrocie flag=true to anulowanie się powiodło i status jest nieokreślony. 76

test_cancel.c Przykład 77

Sprawdzanie rozmiaru bufora Funkcja MPI_Probe: działa podobnie do MPI_Recv, ale nie odczytuje komunikatu, a jedynie jego parametry, po alokacji odpowiednich buforów komunikat można bezzwłocznie odebrać funkcją MPI_Recv. Funkcja MPI_Iprobe: wersja nie blokująca (flag=true jeśli komunikat jest gotowy do odbioru). 78

Komunikacja łączona Operacja Send-Receive łączy w jednym wywołaniu wysłanie komunikatu do określonego odbiorcy oraz odbiór od określonego nadawcy innego komunikatu. Użyteczna w cyklicznych operacjach przesunięć: odporna na powstawanie blokad (deadlock). Funkcja MPI_Sendrecv: (blokująca) 79

Komunikacja trwała W trybie komunikacji trwałej (persistent) można przygotować (zainicjować) operację w celu jej powtarzania np. w pętli. Redukuje to narzut na alokację zasobów. Po zainicjowaniu można wielokrotnie wywoływać operację MPI_Start podając uzyskany wcześniej request, a następnie zawsze weryfikować jej wykonanie via MPI_Test / MPI_Wait. Na koniec należy zwolnić zasoby: 80

Typy pochodne Typ pochodny można zdefiniować za pomocą specjalnej funkcji. Po zdefiniowaniu nowego typu należy go ustanowić (skompilować): przed użyciem typu do przesyłania komunikatów, nie konieczne przed definiowaniu kolejnych typów pochodnych. Po zakończeniu używania typu należy zwolnić przydzielone mu zasoby. 81

Mapowanie typów Określa rozłożenie w pamięci obiektów tworzących dany typ danych. Typemap mapa typu sekwencja par: typ podstawowy, przesunięcie w pamięci (w bajtach): typemap = {(type 0,disp 0 ),...,(type n-1,disp n-1 )} Sygnatura typu lista typów w typemap: type signature = {type 0,...,type n-1 } lb dolne ograniczenie przesunięć: lb(typemap) = min j (disp j ) ub górne ograniczenie przesunięć: ub = max j (disp j + sizeof(type j )) extent zakres (różnica ub-lb powiększona o wyrównanie): extent(typemap) = ub(typemap) - lb(typemap) + pad 82

Mapa typów - przykład struct Partstruct { int class; /* particle class */ double d[6]; /* particle coordinates */ char b[7]; /* some additional information */ }; MPI_Datatype type[3] = {MPI_INT, MPI_DOUBLE, MPI_CHAR}; int blocklen[3] = {1, 6, 7}; MPI_Aint disp[3]; MPI_Address( particle, disp); MPI_Address( particle[0].d, disp+1); MPI_Address( particle[0].b, disp+2); int base; base = disp[0]; for ( int i= 0; i < 3; i++ ) disp[i] -= base; MPI_Datatype Particletype; MPI_Type_struct( 3, blocklen, disp, type, &Particletype); 83

Tablica typów Funkcja MPI_Type_contiguous: najprostszy konstruktor typu pochodnego, argument count określa liczbę elementów w tablicy, argument oldtype określa typ składowy, wynikowy identyfikator typu jest umieszczany pod adresem newtype, przesunięcia powiększane o zakres typu składowego. 84

Przykład ciągłego TD: float a[size][size] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 }; float b[size]; MPI_Status stat; MPI_Datatype rowtype; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); MPI_Type_contiguous(SIZE, MPI_FLOAT, &rowtype); 85

Wektor Funkcja MPI_Type_vector: definiuje typ składający się z count bloków, zawierających blocklength elementów typu oldtype każdy, między początkami bloków występują odstępy o długości stride elementów oldtype. 86

Przykład: float a[size][size] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 }; float b[size]; MPI_Status stat; MPI_Datatype columntype; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); MPI_Type_vector(SIZE, 1, SIZE, MPI_FLOAT, &columntype); 87

Pakowanie danych Definicje typów mają konstrukcję statyczną (niezależną od przesyłanych danych). Nie można w ten sposób zdefiniować unii o wariancie określonym przez przesyłane dane albo listy. Do przesyłania bardziej złożonych konstrukcji wykorzystuje się pakowanie. Wadą takiego podejścia jest konieczność kopiowania danych do dodatkowych buforów. 88

Pakowanie Funkcja MPI_Pack: kopiuje incount danych typu datatype (typ prosty lub pochodny) umieszczonych pod adresem inbuf do bufora o początku outbuf i rozmiarze outsize, ponieważ w buforze outbuf mogą się już znajdować dane, zmienna position powinna określać, ile bajtów tego bufora jest już używanych (po przekopiowaniu danych funkcja modyfikuje tę zmienną), argument comm określa komunikator, który będzie użyty do wysłania danych. 89

Pakowanie (2) Funkcja MPI_Pack_size: umożliwia poznanie rozmiaru bufora przed operacją pakowania, pod adresem size wpisuje rozmiar bufora wymagany do spakowania incount danych typu datatype. 90

Przesyłanie Dane spakowane są przesyłane jako typ MPI_PACKED. Przy odbiorze długość komunikatu może nie być znana; jego długość może zostać odczytana za pomocą funkcji MPI_Probe. Pozwala to na zaalokowanie odpowiedniego buforu i odczytanie spakowanego komunikatu. 91

Przykład 92

Rozpakowywanie Funkcja MPI_Unpack: pobiera outcount danych typu datatype i umieszcza je pod adresem outbuf, dane są pobierane z bufora o początku inbuf i rozmiarze insize, zmienna wskazywana przez position określa liczbę danych już pobranych (będzie zmodyfikowana przez funkcję), argument comm określa komunikator, który był używany przy odbiorze komunikatu. 93

Przykład 94

Komunikacja kolektywna Komunikacja MPI między więcej niż dwoma procesami: synchronizacja za pomocą bariery, wysyłanie komunikatu do grupy procesów, zbieranie danych od grupy procesów, rozsyłanie danych między członków grupy, operacje redukcji. Komunikacja zachodzi między wyróżnionym procesem grupy (liderem), a pozostałymi członkami grupy, określonej komunikatorem wewnętrznym (wyłącznie MPI 1.x). 95

Ograniczenia W komunikacji kolektywnej liczba danych wysyłanych musi być równa liczbie danych wyspecyfikowanych do odbioru. Komunikaty kolektywne nie są oznaczane identyfikatorami (tag), kolejność wywołań musi być jednakowa we wszystkich procesach danego komunikatora. Operacje kolektywne mogą, ale nie muszą wymuszać synchronizacji między procesami biorącymi w nich udział. 96

Operacje kolektywne 97

Synchronizacja Funkcja MPI_Barrier: realizuje operację bariery, blokuje wykonanie, aż do momentu gdy wszyscy członkowie grupy komunikatora comm ją wywołają. 98

Rozgłaszanie Funkcja MPI_Bcast: rozsyła komunikat od procesu lidera o identyfikatorze root do pozostałych członków grupy komunikatora comm, wysyłanie odbywa się w procesie root, w pozostałych procesach ma miejsce odbiór, rozsyłanych jest count danych typu datatype umieszczonych pod adresem buffer w procesie root, w pozostałych procesach argument buffer wskazuje gdzie odebrane dane zostaną umieszczone. 99

P1 = root P2 P3 root Zbieranie P4 MPI_GATHER Funkcja MPI_Gather: każdy proces grupy komunikatora comm, włącznie z liderem, wysyła identyczną liczbę danych sendcount typu sendtype umieszczonych w buforze sendbuf, proces lidera o identyfikatorze root odbiera od każdego z procesów recvcount danych typu recvtype, łączy je w kolejności identyfikatorów nadawców i umieszcza pod adresem recvbuf (recvcount, recvtype i recvbuf są istotne tylko dla procesu root), recvcount liczba danych od każdego procesu (nie łącznie). 100

Przykład 101

Topologie wirtualne Ciągłe indeksowanie procesów w grupie nie musi odpowiadać topologii narzucanej przez algorytm: siatki wielowymiarowe i grafy. W MPI można adresować procesy w przestrzeni wirtualnej, określonej przez użytkownika. Funkcje tworzące nowe topologie na bazie istniejącego komunikatora tworzą nowy, o takiej samej grupie procesów i nowej topologii. Funkcje te mają charakter kolektywny. 102

Topologia kartezjańska Funkcja MPI_Cart_create: tworzy komunikator topologii kartezjańskiej i zwraca do niego uchwyt comm_cart, argument oldcomm określa kopiowany komunikator, liczbę wymiarów określa argument ndims, tablica dims zawiera rozmiary poszczególnych wymiarów, jeśli reorder = false, to indeksy procesów w nowym komunikatorze są takie same, jak w oldcomm, inaczej mogą być inne (dopasowanie do architektury systemu), tablica periods określa, czy kolejne wymiary są cykliczne (= true) tworzą pierścień, czy nie (= false), jeśli liczba procesów w oldcomm jest większa niż wynikająca z rozmiarów dims, to tworzony komunikator ma mniej procesów, a w nadmiarowych procesach jest wpisywane MPI_COMM_NULL. 103

Przykład 104

Uzyskiwanie współrzędnych Funkcja MPI_Cart_rank: pozwala wyznaczyć identyfikator rank procesu na podstawie jego współrzędnych coords w komunikatorze kartezjańskim comm. Funkcja MPI_Cart_coords: operacja odwrotna: uzyskanie współrzędnych kartezjańskich coords procesu o identyfikatorze rank, argument maxdims określa liczbę wymiarów. 105

Przesunięcia procesów Funkcja MPI_Cart_shift: pozwala wyznaczyć indeks (umieszczany pod adresem rank_dest) procesu komunikatora kartezjańskiego przesuniętego względem procesu ją wywołującego o disp węzłów w kierunku direction, pod adresem rank_source jest wpisywany indeks procesu przesuniętego w przeciwnym kierunku, kierunki (współrzędne) są numerowane od 0, gdy dojdzie do brzegu (niecyklicznego), wpisywana jest wartość MPI_PROC_NULL. 106

Przykład Wymiar cykliczny Wymiar skończony (dla nieistniejącego sąsiada jest zwracana indeks MPI_PROC_NULL) 107

Topologia grafu (ogólna) Funkcja MPI_Graph_create: tworzy komunikator topologii grafu i zwraca do niego uchwyt comm_graph, graf jest określony liczbą węzłów i indeksów sąsiadów, liczbę węzłów określa argument nnodes, indeksy sąsiadów kolejnych węzłów są umieszczane w tablicy edges, tablica index zawiera sumy liczb sąsiadów danego węzła i węzłów o indeksach niższych. 108

Wyznaczanie sąsiadów Funkcja MPI_Graph_neighbors_count: pozwala uzyskać liczbę sąsiadów nneighbors węzła o identyfikatorze rank komunikatora comm o topologii grafu. Funkcja MPI_Graph_neighbors: pozwala uzyskać w wektorze neighbors o rozmiarze maxneighbors identyfikatory sąsiadów procesu rank. 109

Przykład 110

Rozszerzenia MPI Specyfikacja MPI 2.0 m.in.: dynamiczne tworzenie procesów, komunikacja jednostronna, równoległe operacje wejścia/wyjścia, implementacja C/C++/F90. 111

Dynamiczne tworzenie procesów Funkcja MPI_Comm_spawn: próbuje uruchomić maxprocs identycznych procesów command z argumentami określonymi przez argv, powinna być wywoływana kolektywnie w komunikatorze comm (ale tylko proces root uruchamia procesy potomne), tworzy komunikator zewnętrzny intercomm obejmujący grupy procesów macierzystych i potomnych, argument info określa uchwyt do obiektu z dodatkowymi informacjami (parami tekstów: klucz, wartość) określającymi np. katalog roboczy 'wdir', węzeł docelowy 'host', funkcja może blokować aż do MPI_Init w potomnych, procesy potomne otrzymują osobny MPI_COMM_WORLD. 112

MPI_Comm_spawn Tablica array_of_codes zawiera kody błędów uruchomienia poszczególnych procesów. 113

Tworzenie procesów (2) Funkcja MPI_Comm_get_parent: pozwala procesom potomnym uzyskać uchwyt do komunikatora zewnętrznego dla komunikacji z rodzicami. Utworzenie komunikatora wewnętrznego obejmującego procesy potomne i rodziców umożliwia funkcja MPI_Intercomm_merge. 114

Przykład użycia MPI Iteracyjne rozwiązywanie układu równań: A x = b Zdominowana diagonalnie macierz A. Proces główny (PG) nie uczestniczy w obliczeniach: czyta i sprawdza dane wejściowe, uruchamia (MPI2) procesy obliczeniowe (PO), rozsyła im dane, oraz przechowuje aktualne wartości wektora x i decyduje o zakończeniu obliczeń. 115

start =0 0 Schemat yes Main Process: sync? no Sync Loop: Async Loop: UpdatePartX myid? Computational Process: Compute: x k+1 = x k - D (A x k - b) Send x SendNewX stop? no no Recv x end tag? SendStop stop 116