MPICH

Sprzątanie Wikipedii
Ten artykuł należy dopracować:
zastosować znaczniki „code”.
Dokładniejsze informacje o tym, co należy poprawić, być może znajdują się w dyskusji tego artykułu.
Po wyeliminowaniu niedoskonałości należy usunąć szablon {{Dopracować}} z tego artykułu.
MPICH
Aktualna wersja stabilna 4.2.1
(17 kwietnia 2024) [±]
System operacyjny Microsoft Windows, Unix
Rodzaj Biblioteka zgodna ze standardem MPI
Strona internetowa

MPICH – ogólnodostępna, darmowa i przenośna implementacja standardu MPI. Pozwala na przekazywanie komunikatów pomiędzy aplikacjami działającymi równolegle. Nadaje się do stosowania na małych klastrach.

Najnowszą wersję biblioteki MPICH można pobrać ze strony domowej projektu. Biblioteki MPICH można używać zarówno na systemach klasy MS Windows jak i Unix.

Rozwinięciem MPICH jest MPICH2.

Powstała także wersja tej biblioteki o nazwie MPICH-G2 pozwalająca uruchamiać aplikacje równoległe w środowiskach gridowych, z wykorzystaniem pakietu Globus Toolkit jako warstwy pośredniej. Dzięki temu rozwiązaniu aplikacja może działać na kilku klastrach rozproszonych geograficznie.

Charakterystyka

MPICH jest implementacją biblioteki sterowania procesem obliczeń równoległych na maszyny klasy PC. Protokół ten przeznaczony jest do sterowania procesem obliczeń równoległych w sieciach rozproszonych. Biblioteka procedur MPICH jest dostępna bezpłatnie. Najnowsza wersja tej biblioteki MPICH2 poza zapewnieniem bardziej wydajnych mechanizmów komunikacji posiada dodatkowo:

  • wsparcie dla komunikacji jednostronnej
  • rozszerzoną funkcjonalność MPI-IO

Instalacja

Opis instalacji MPICH (jednej z implementacji MPI)

1. Na początku należy pobrać źródła programu : mpich.tar.gz

2. Rozpakowujemy plik mpich.tar.gz
# tar xfz mpich.tar.gz

3. Będąc w katalogu /mpich wydajemy komendę:
# ./configure --prefix=/opt/mpich
--prefix=/opt/mpich - określa ścieżkę docelową dla MPICH

4. Kompilujemy program wydając komendę:
# make

5. Dokonujemy instalacji w katalogu podanym w opcji prefix:
# make install

Konfiguracja

Konfiguracja MPICH

W pliku machines.LINUX (katalog: /opt/mpich/share lub inny wybrany w opcji prefix podczas instalacji) dopisujemy nazwy hostów wchodzących w skład klastra:

W pliku machines.LINUX (katalog: /opt/mpich/share lub inny wybrany w opcji prefix podczas instalacji) dopisujemy nazwy hostów wchodzących w skład klastra:

hostname1:liczba_procesów
hostname2:liczba_procesów
hostname3:liczba_procesów

gdzie:

  • hostname – oznacza nazwa komputera wchodzącego w skład klastra,
  • liczba_procesów – liczba procesorów danego hosta

Przesyłanie komunikatów

Komunikacja punkt – punkt

Przykład

Przykład komunikacji międzyprocesowej typu punkt-punkt. Zadaniem programu jest przesłanie komunikatu o treści "Komunikat od procesu 0" z procesu o numerze rank = 0 (SOURCE) do procesu o numerze rank = 1 (DEST).

#include <stdio.h>
#include "mpi.h"
#define TAG 0 #define COUNT 25 #define SOURCE 0 #define DEST 1
int main(int argc, char *argv[]) { int rank, size; MPI_Status status;
char Msg[]="Komunikat od procesu 0"; // treść komunikatu przesyłanego między procesami char Recv[COUNT]; MPI_Init(&argc,&argv); // inicjalizacja środowiska MPI manual MPI_Comm_size(MPI_COMM_WORLD,&size); // liczba procesów w grupie zapisywana jest w zmiennej size manual MPI_Comm_rank(MPI_COMM_WORLD,&rank); // rank bieżącego procesu zapisywany jest w zmiennej rank manual
if (size > 1) { // sprawdzane jest czy istnieje minimalna liczba procesów
// Komunikat przesyłany jest od procesu o numerze rank = 0 (SOURCE) // do procesu o numerze rank = 1 (DEST) if (rank == DEST) // jeżeli procesem jest proces odbierający komunikat: { printf ("process %d of %d waiting for message from %d\n", rank, size, SOURCE); // odbiór komunkatu i zapis zawartości do bufora Recv manual MPI_Recv(Recv, COUNT, MPI_CHAR, SOURCE, TAG, MPI_COMM_WORLD, &status); printf ("process %d of %d has received: '%s'\n", rank, size, Recv); }
else
if (rank == SOURCE) // jeżeli procesem jest proces nadający komunikat: { printf ("process %d of %d sending '%s' to %d\n", rank, size, Msg, DEST); // wysyłanie komunkatu zawartego w buforze Msg manual MPI_Send(Msg, COUNT, MPI_CHAR, DEST, TAG, MPI_COMM_WORLD); } } MPI_Finalize(); // zakończenie wykonywania procesów MPI manual return 0; }

Program kompiluje się wprowadzając polecenie:
# mpicc -o program_mpi program_mpi.c

Komunikacja grupowa

MPICH dostarcza kilku funkcji, ułatwiających komunikowanie się jednocześnie ze wszystkimi procesami w grupie. Poza sporym ułatwieniem zapewniają one (a raczej zapewnia to MPICH), że dane zostaną przesłane w optymalny sposób (naiwny broadcast(iteracja) vs. MPI_Bcast(algorytm „drzewiasty”) ).

MPI_Bcast

Rozsyła komunikat do wszystkich procesów w grupie.

int vsize = 4;
float vect[vsize];
...
int status = MPI_Bcast( vect ,vsize ,MPI_FLOAT ,0 /*root*/ , MPI_COMM_WORLD); // man

MPI_Scatter

Funkcja dzieli wektor danych wejściowych (w procesie oznaczonym jako root) i rozsyła je tak, że procesowi o randze N jest przesyłana N-ta część wektora danych.

int vsize = 4;
float matrix[vsize*vsize];
float rvect[vsize];
int status = MPI_Scatter(matrix, vsize, MPI_FLOAT, rvect, vsize, MPI_FLOAT, 0 /*root*/, MPI_COMM_WORLD); // do 4-ech procesów!!! man

MPI_Gather

Funkcja odwrotna do MPI_Scatter. Zbiera dane w procesie oznaczonym root. Ustawia je w kolejkę zgodnie z rangą nadsyłającego procesu.

int vsize = 4;
float matrix[vsize*vsize];
float rvect[vsize];
int status = MPI_Gather(rvect, vsize, MPI_FLOAT, matrix, vsize, MPI_FLOAT, 0 /*root*/ ,MPI_COMM_WORLD); // od 4-ech procesów !!!man

MPI_Reduce

Funkcja wykonuje zdefiniowaną operację na wysłanych przez procesy danych. Możliwe operacje:

  1. MPI_MAX – maximum
  2. MPI_MIN – minimum
  3. MPI_SUM – suma
  4. MPI_PROD – produkt
  5. MPI_LAND – logiczny AND
  6. MPI_LOR – logiczny OR
  7. MPI_LXOR – logiczny XOR
  8. MPI_BAND – bitowy AND
  9. MPI_BOR – bitowy OR
  10. MPI_BXOR – bitowy XOR
  int val = 1, procCnt;
  int status = MPI_Reduce( &val ,&procCnt ,1 ,MPI_INT ,MPI_SUM ,0 /*root*/ ,MPI_COMM_WORLD ); // alternatywna metoda liczenia procesów :) man

Przykład

Przykład komunikacji grupowej realizowanej za pośrednictwem funkcji MPI_Scatter i MPI_Reduce.
Działanie programu polega na rozesłaniu poszczególnych wierszy macierzy zawartej w buforze sendbuf do czterech procesów w grupie.

#include "mpi.h"
#include <stdio.h>
#define SIZE 4
main(int argc, char *argv[]) { int numtasks, rank, sendcount, recvcount, source; float sendbuf[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} }; // inicjalizacja bufora do wysyłki float recvbuf[SIZE];
MPI_Init(&argc,&argv); // inicjalizacja środowiska MPI manual MPI_Comm_rank(MPI_COMM_WORLD, &rank); // rank bieżącego procesu zapisywany jest w zmienej rank manual MPI_Comm_size(MPI_COMM_WORLD, &numtasks); // liczba procesów w grupie zapisywana jest w zmiennej size manual
if (numtasks == SIZE) { // jeżeli w grupie są dokładnie 4 procesy: source = 1; sendcount = SIZE; recvcount = SIZE;
// rozsyłanie do procesów w grupie komunikatu zawartego w buforze sendbuf manual MPI_Scatter(sendbuf,sendcount,MPI_FLOAT,recvbuf,recvcount, MPI_FLOAT,source,MPI_COMM_WORLD);
printf("rank= %d Results: %f %f %f %f\n",rank,recvbuf[0], recvbuf[1],recvbuf[2],recvbuf[3]); int val = 1, procCnt; MPI_Reduce( &val ,&procCnt ,1 ,MPI_INT ,MPI_SUM ,source ,MPI_COMM_WORLD ); // suma ,czyli liczba procesów man } else printf("Must specify %d processors. Terminating.\n",SIZE);
MPI_Finalize(); // zakończenie wykonywania procesów MPI manual }

Program kompiluje się wprowadzając polecenie:
# mpicc -o program_mpi program_mpi.c

Typy danych

Podstawowe typy danych

 

Typy podstawowe
MPI C Rozmiar
MPI_CHAR signed char 1 bajt
MPI_SHORT signed short int 2 bajty
MPI_INT signed int 2 bajty
MPI_LONG signed long int 4 bajty
MPI_UNSIGNED_CHAR unsigned char 1 bajt
MPI_UNSIGNED_SHORT unsigned short int 1 bajt
MPI_UNSIGNED unsigned int 2 bajty
MPI_UNSIGNED_LONG unsigned long int 4 bajty
MPI_FLOAT float 4 bajty
MPI_DOUBLE double 8 bajtów
MPI_LONG_DOUBLE long double 8, 10 lub 12 bajtów
MPI_BYTE 8 binarnych cyfr (8 bitów) 1 bajt
MPI_PACKED dane spakowane lub rozpakowane z użyciem MPI_Pack()/ MPI_Unpack()

W MPI możemy tworzyć własne typy danych. Najczęściej chcemy, aby typ przesyłanych danych był różny od standardowych typów zdefiniowanych w bibliotece MPI. W MPI zdecydowano się na rozwiązanie, w którym programista ma możliwość tworzenia nowych typów danych w czasie wykonywania programu. Takie typy danych nazywane są POCHODNYMI TYPAMI DANYCH lub TYPAMI UŻYTKOWNIKA. Pochodne typy danych tworzymy z podstawowych typów danych.

Typy pochodne

Każdy typ danych w MPI jest określony przez tablice typemap podającą dla każdego elementu parami typ podstawowy i przesunięcie w bajtach

Typemap={(type0 ,disp0 ),...,(typen-1 ,dispn-1 )}

przykład: 	 MPI_INT	 (int,0)


Definicje Dolnej i Górnej Granicy oraz Rozpiętości i Rozmiaru Typów Danych

lb(Typemap) = minj (dispj)
ub(Typemap) = maxj (dispj+sizeof(typej))+pad
extent(Typemap) = ub(Typemap)-lb(Typemap) 

„pad” określa poprawkę ze względu na rozmieszczenie danych w pamięci komputera, w większości przypadków wymagane jest aby dane określonego typu były umieszczone pod adresami będącymi wielokrotnością rozmiaru danego typu, np. int zajmuje 4 bajty więc adres powinien być podzielny przez 4, więc dla:

{(int,0),(char,4)}
lb=min(0,4)=0	
ub=max(0+4,4+1)+pad=5+pad=8
extent=5+pad=8
rozmiar=5


Pochodne typy danych

Contiguous
Jest to najprostszy typ pochodny; elementy są kopiami danego typu wejściowego a ich pozycje są wielokrotnościami jego rozpiętości.

int MPI_Type_contiguous(int count, MPI_Datatype oldtype,MPI_Datatype *newtype);

Vector
Elementy są kopiami danego typu wejściowego, ale pomiędzy nimi występują odstępy będące wielokrotnościami rozpiętości tego typu.

int MPI_Type_vector(int count, int block_length,int stride, MPI_Datatype element_type,MPI_Datatype *newtype);

Hvector
Jak Vector ale odstępy między elementami są określone w bajtach.

int MPI_Type_vector(int count, int block_length,int stride, MPI_Datatype element_type,MPI_Datatype *newtype);

Indexed
Jak Vector ale odstępy między elementami są określone dowolnie przez tablicę przesunięć.

int MPI_Type_indexed(int count,int *array_of_block_lengths,int *array_of_displacements,MPI_Datatype element_type,                 MPI_Datatype *newtype);

Hindexed
Jak Indexed ale elementy tablicy przesunięć są podane w bajtach.

int MPI_Type_indexed(int count,int *array_of_block_lengths,int *array_of_displacements,MPI_Datatype element_type,MPI_Datatype *newtype);

Struct
Najbardzięj ogólny typ, elementy nie muszą być jednakowego typu, a odstępy między nimi są określone przez tablicę przesunięć, której elementy są podane w bajtach.

int MPI_Type_struct(int count,int *array_of_block_lengths,MPI_Aint *array_of_displacements,MPI_Datatype *array_of_types,MPI_Datatype *newtype);

Extent
Zwraca rozmiar w bajtach danego typu danych. Funkcja ta jest użyteczna w podprogramach, które wymagają rozmiaru danego typu w bajtach np. w celu obliczenia przesunięcia.

int MPI_Type_extent(MPI_Datatype dtype, MPI_Aint *pextent)

Commit
Zatwierdza nowy typ w systemie. Wymagane dla wszystkich nowo stworzonych pochodnych typów danych.

int MPI_Type_commit ( MPI_Datatype *datatype )

Przykład – CONTIGUOUS

#include "mpi.h"
#include <stdio.h>
#define SIZE 4
main(int argc, char *argv[])
{ int numtasks, rank, source=0, dest, tag=1, i;
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);
MPI_Type_commit(&rowtype);
if (numtasks == SIZE){
if (rank == 0) { for (i=0; i<numtasks; i++) MPI_Send(&a[i][0], 1, rowtype, i, tag, MPI_COMM_WORLD); }
MPI_Recv(b, SIZE, MPI_FLOAT, source, tag, MPI_COMM_WORLD, &stat); printf("rank= %d b= %3.1f %3.1f %3.1f %3.1f\n", rank,b[0],b[1],b[2],b[3]); }
else
printf("Must specify %d processors. Terminating.\n",SIZE);
MPI_Finalize();
}


źródło: https://web.archive.org/web/20090131212047/http://icis.pcz.pl/~roman/mpi-www/

Linki zewnętrzne

  • Strona domowa projektu MPICH (wersja archiwalna)
  • Manual dla funkcji MPICH