Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Podstawy MPI-2: część I Literatura: Using MPI-2. Advanced Features of the Message-Passing Interface, W. Gropp, E. Lusk, R. Thakur, MIT Press, Cambridge,

Podobne prezentacje


Prezentacja na temat: "Podstawy MPI-2: część I Literatura: Using MPI-2. Advanced Features of the Message-Passing Interface, W. Gropp, E. Lusk, R. Thakur, MIT Press, Cambridge,"— Zapis prezentacji:

1 Podstawy MPI-2: część I Literatura: Using MPI-2. Advanced Features of the Message-Passing Interface, W. Gropp, E. Lusk, R. Thakur, MIT Press, Cambridge, Przykłady są dostępne na sieci pod Prezentacja “Introduction to parallel I/O and MPI-IO”, R. Thakur, ANLIntroduction to parallel I/O and MPI-IO Tutorial “Rozszerzenia standardu MPI” na stronie Poznańskiego Centrum Sieciowo-Superkomupterowego.“Rozszerzenia standardu MPI” MPI Forum (http://www.mpi-forum.org)http://www.mpi-forum.org

2 Historia 1992: Pierwsze spotkanie MPI Forum na konferencji Supercomputing ‘92. Początek prac nad standardem MPI : Pierwsze wydanie książki “Using MPI” pomaga przekonać programistów równoległych do tego standardu. Użytkownicy PVM wskazują jednak na brak możliwości dynamicznej alokacji procesów, wszyscy użytkownicy wskazują na konieczność równoległych operacji I/O a CRAY- T3D (biblioteka shmem) i CM-5 udowadniają użyteczność jednostronnych operacji na pamięci. 1995: spotkanie MPI-2 Forum i ponowne podjęcie prac nad standardem MPI. Trochę zmodyfikowany standard MPI : MPI-2 dostępna dla użytkowników.

3 Nowe rzeczy w MPI-2 Główne modyfikacje (“wielka trójka”) Równoległe operacje wejścia/wyjścia. Operacje na pamięci odległej. Dynamiczne zarządzanie procesami Pomniejsze modyfikacje Specyfikacje zewnętrznych interfejsów. Połączenie z C++ i Fortranem 90. Wątki. Łączenie modułów w różnych językach. Rozszerzone operacje komunikacji zbiorowej (np. na interkomunikatorach).

4 Równoległe operacje wejścia/wyjścia MPI-IO Pisanie do pliku jest wysłaniem wiadomości do systemu plików; narzędzia do tego celu już są w MPI. Podstawowe funkcje MPI-IO: –open, –close, –seek, –read, –write Argumenty tych funkcji są podobne jak w UNIXowym I/O.

5 Cechy operacji MPI-IO Rozproszenie pamięci oraz rekordów pliku. Zbiorowe operacje I/O. Niewstrzymuące operacje I/O. Specyfikacja offsetu położenia rekordu w pliku w celu uniknięcia oddzielnych operacji seek. Lokalne i globalne wskaźniki plików. Reprezentacje danych przenaszalne i możliwe do definiowania przez użytkownika. Wskazówki dla implementacji i systemu plików.

6 Operacje na pamięci odległej Model przesyłania wiadomości: dane są przesyłane przy użyciu pary send/receive. Model pamięci wspólnej: procesory mają dostęp do wspólnej części pamięci i mogą pobierać lub umieszczać w niej dane. W MPI-2 zdefiniowano operacje put, get i collect, które umożliwiają dostęp do pamięci innego procesora w sposób analogiczny do modelu pamięci wspólnej. Te operacje określa się mianem operacji na pamięci odległej, zdalnych operacji na pamięci lub jednostronnych operacji na pamięci (ang. “one-sided” lub “remote memory” operations). Pamięć dostępną dla innego procesora specyfikuje się jako okno pamięci (window).

7 Cechy operacji na pamięci odległej w MPI-2 Zrównoważenie efektywności i przenaszalności między różnymi architekturami, włączając maszyny SMP (Shared Memory multiProcessors), NUMA (NonuUiform Memory Access), MPP (distributed memory Massively Parallel Processors), klastry SMP, czy sieci heterogeniczne. Zachowanie “spojrzenia i czucia” (look and feel) MPI. Uwzględnienie subtelnych różnic zachowania pamięci takich, jak koherencja pamięci cache, zgodność sekwencyjna, itp. Oddzielenie synchronizacji od przesyłania danych w celu zwiększenia efektywności.

8 Dynamiczne zarządzanie procesami W MPI-2 dany proces może –uczestniczyć w tworzeniu nowego procesu MPI (operacja rozmnażania; ang. spawning), –nawiązać komunikację z procesami wystartowanymi oddzielnie (operacja połączenia). Główe cele przy projektowaniu takiego API (Application Programing Interface): –Utrzymanie prostoty i elastyczności. –Interakcja z systemem operacyjnym, zarządcą zasobów, procesu oraz złożonym otoczeniem programowym. –Unikanie efektu “wyścigu” źle wpływającego na dokładność. Aby osiągnąć te cele, operacje zarządzania pamięcią muszą być zbiorowe, zarówno w obrębie procesów macierzystych jak i potomych. Procesy potomne są reprezentowane przez interkomunikatory.

9 MPI-IO

10 Sekwencyjne I/O w programie równoległym Master plik Pamięć Procesor Pisze/czyta tylko master, który odpowiednio zbiera dane od innych procesorów lub rozsyła do nich przeczytane dane.

11 MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); MPI_Comm_size(MPI_COMM_WORLD, &numprocs); for (i=0; i

12 Zalety takiej organizacji pisania/czytania Maszyna na której chodzi program równoległy może dopuszczać I/O tylko z jednego albo ograniczonej liczby procesów lub znacznie ograniczać wydajność jeżeli każdy procesor pisze do oddzielnego pliku na wspólnym systemie plików (np. bigben w PSC czy galera w TASKu). Można używać zaawansowanych nierównoległych bibliotek I/O (np. biblioteki zarządzania danymi). Wszystkie wyniki są w jednym pliku, na którym takie operacje jak ftp, cp, mv są łatwiejsze i szybsze niż na wielu. Wady Obniżanie efektywności kodu poprzez sekwencyjność operacji pisania/czytania i konieczność przesyłania danych.

13 Równoległe nie-MPI I/O w programie równoległym plik Pamięć Procesor Każdy procesor pisze do oddzielnego pliku albo niezależnie czyta z tego samego lub oddzielnego pliku

14 Przykład pisania przez każdy procesor do oddzielnego pliku o nazwie zawierającej rząd procesora MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); for (i=0; i

15 Zalety takiego podejścia Operacje I/O są równoległe ale mogą korzystać z sekwencyjnych bibliotek I/O. Wady Często pliki wyprodukowane przez poszczególne procesory trzeba łączyć w jeden do dalszego przetwarzania. Program używających te pliki jako pliki danych często sam musi być równoległy i chodzić na tej samej liczbie procesorów co program, który je wyprodukował. Uciążliwość w “ogarnięciu” i wykonywaniu opearacji takich jak cp, mv, ftp na dziesiątkach a nawet tysiącach małych plików. Pojawianie się nieoczekiwanych błędów przy jednoczesnym czytaniu jednego dużego pliku danych przez wiele procesorów.

16 Kod piszący wyniki do wielu plików z użyciem MPI-IO MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); for (i=0; i

17 MPI_FILE_OPEN(comm, filename, amode, info, fh) [ IN comm] komunikator (handle) [ IN filename] nazwa pliku (string) [ IN amode] tryb dostępu do pliku (integer) [ IN info] obiekt info (handle) [ OUT fh] “pokrętło” utworzonego pliku (handle) C: int MPI_File_open(MPI_Comm comm, char *filename, int amode, MPI_Info info, MPI_File *fh) FORTRAN/FORTRAN 90: MPI_FILE_OPEN(COMM, FILENAME, AMODE, INFO, FH, IERROR) CHARACTER*(*) FILENAME INTEGER COMM, AMODE, INFO, FH, IERROR C++: static MPI::File MPI::File::Open(const MPI::Intracomm& comm, const char* filename, int amode, const MPI::Info& info)

18 MPI_FILE_WRITE(fh, buf, count, datatype, status) [ INOUT fh] “pokrętło” pliku (handle) [ IN buf] początkowy adres buforu (choice) [ IN count] liczba elementów danych w buforze (integer) [ IN datatype] typ każdego elementu danych (handle) [ OUT status] obiekt stanu (Status) C: int MPI_File_write(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) FORTRAN/FORTRAN90: MPI_FILE_WRITE(FH, BUF, COUNT, DATATYPE, STATUS, IERROR) BUF(*) INTEGER FH, COUNT, DATATYPE, STATUS(MPI_STATUS_SIZE), IERROR C++: void MPI::File::Write(const void* buf, int count, const MPI::Datatype& datatype, MPI::Status& status) void MPI::File::Write(const void* buf, int count, const MPI::Datatype& datatype)

19 MPI_FILE_CLOSE(fh) [ INOUT fh] “pokrętło” pliku (handle) C: int MPI_File_close(MPI_File *fh) FORTRAN/FORTRAN90: MPI_FILE_CLOSE(FH, IERROR) INTEGER FH, IERROR C++: void MPI::File::Close()

20 Schemat równoległego pisania/czytania z tego samego pliku przez wiele procesorów. Każdy procesor ma w danej chwili dostęp do innej części pliku. plik Pamięć Procesor

21 Kod piszący wyniki do jednego pliku z użyciem MPI-IO: C MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); for (i=0; i

22 Kod piszący wyniki do jednego pliku z użyciem MPI-IO: FORTRAN90 call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, myrank, ierr) do i = 0, BUFSIZE buf(i) = myrank * BUFSIZE + i enddo call MPI_FILE_OPEN(MPI_COMM_WORLD, 'testfile', & MPI_MODE_WRONLY + MPI_MODE_CREATE, & MPI_INFO_NULL, thefile, ierr) ! assume 4-byte integers disp = myrank * BUFSIZE * 4 call MPI_FILE_SET_VIEW(thefile, disp, MPI_INTEGER, & MPI_INTEGER, 'native', & MPI_INFO_NULL, ierr) call MPI_FILE_WRITE(thefile, buf, BUFSIZE, MPI_INTEGER, & MPI_STATUS_IGNORE, ierr) call MPI_FILE_CLOSE(thefile, ierr) call MPI_FINALIZE(ierr)

23 MPI_FILE_SET_VIEW(fh, disp, etype, filetype, datarep, info) [ INOUT fh] “pokrętło” pliku (handle) [ IN disp] przesunięcie (pozycja początkowego rekordu) (integer) [ IN etype] elementarny typ danych (handle) [ IN filetype] typ pliku (handle) [ IN datarep] reprezentacja danych (string) [ IN info] obiekt informacyjny (handle) C: int MPI_File_set_view(MPI_File fh, MPI_Offset disp, MPI_Datatype etype, MPI_Datatype filetype, char *datarep, MPI_Info info) FORTRAN/FORTRAN90 MPI_FILE_SET_VIEW(FH, DISP, ETYPE, FILETYPE, DATAREP, INFO, IERROR) INTEGER FH, ETYPE, FILETYPE, INFO, IERROR CHARACTER*(*) DATAREP INTEGER(KIND=MPI_OFFSET_KIND) DISP C++ void MPI::File::Set_view(MPI::Offset disp, const MPI::Datatype& etype, const MPI::Datatype& filetype, const char* datarep, const MPI::Info& info)

24 Czytanie pliku przez inną liczbę procesorów niż użyta to jego zapisu MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); MPI_Comm_size(MPI_COMM_WORLD, &numprocs); MPI_File_open(MPI_COMM_WORLD, "testfile", MPI_MODE_RDONLY, MPI_INFO_NULL, &thefile); MPI_File_get_size(thefile, &filesize); /* in bytes */ filesize = filesize / sizeof(int); /* in number of ints */ bufsize = filesize / numprocs + 1; /* local number to read */ buf = (int *) malloc (bufsize * sizeof(int)); MPI_File_set_view(thefile, myrank * bufsize * sizeof(int), MPI_INT, MPI_INT, "native", MPI_INFO_NULL); MPI_File_read(thefile, buf, bufsize, MPI_INT, &status); MPI_Get_count(&status, MPI_INT, &count); printf("process %d read %d ints\n", myrank, count); MPI_File_close(&thefile); MPI_Finalize();

25 MPI_FILE_GET_SIZE(fh, size) [IN fhfile] “pokrętło” pliku (handle) [OUT size] rozmiar pliku w bajtach (integer) C: int MPI_File_get_size(MPI_File fh, MPI_Offset *size) FORTRAN/FORTRAN90: MPI_FILE_GET_SIZE(FH, SIZE, IERROR) INTEGER FH, IERROR INTEGER(KIND=MPI_OFFSET_KIND) SIZE C++ MPI::Offset MPI::File::Get_size() const

26 MPI_FILE_READ(fh, buf, count, datatype, status) [INOUT fh] “pokrętło” pliku (handle) [OUT buf] początkowy adres buforu (choice) [IN count] liczba elementów buforu (integer) IN datatype datatype of each buffer element (handle) [OUT status] obiekt stanu (Status) C: int MPI_File_read(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) FORTRAN/FORTRAN90: MPI_FILE_READ(FH, BUF, COUNT, DATATYPE, STATUS, IERROR) BUF(*) INTEGER FH, COUNT, DATATYPE, STATUS(MPI_STATUS_SIZE), IERROR C++: void MPI::File::Read(void* buf, int count, const MPI::Datatype& datatype, MPI::Status& status) void MPI::File::Read(void* buf, int count, const MPI::Datatype& datatype)

27 Wydruk z programu piszącego bufor (dla BUFSIZE=2 i 4 procesorów)programu piszącego bufor mpirun -np 4./io3p | sort -n -k 1 Processor 0 buf[0]=0 Processor 0 buf[1]=1 Processor 1 buf[0]=2 Processor 1 buf[1]=3 Processor 2 buf[0]=4 Processor 2 buf[1]=5 Processor 3 buf[0]=6 Processor 3 buf[1]=7 Wydruk z programu czytającego bufor (dla 2 procesorów)programu czytającego bufor mpirun -np 2./io35p | sort -n -k 1 process 0 read 5 ints process 1 read 3 ints processor 0 buf[0]=0 processor 0 buf[1]=1 processor 0 buf[2]=2 processor 0 buf[3]=3 processor 0 buf[4]=4 processor 1 buf[0]=5 processor 1 buf[1]=6 processor 1 buf[2]=7

28 Inne sposoby pisania do pliku wspóldzielonego MPI_File_seek MPI_File_read_at MPI_File_write_at MPI_File_read_shared MPI_File_write_shared Wszystkie te operacje są operacjami komunikacji zbiorowej

29 Niewstrzymujące instrukcje czytania/pisania Standardowe operacje read i write są operacjami wstrzymującymi jak standardowe send i receive ale można użyć MPI_File_iread MPI_File_iwrite Żeby upewnić się, że pliki zostały zapisane/przeczytane należy dodać w odpowiednim miejscu instrukcję MPI_Wait tak jak w przypadku niewstrzymującego send lub receive.

30 Zbiorowe instrukcje czytania/pisania Odpowiednikami operacji komunikacji zbiorowej są MPI_File_read_all MPI_File_write_all Pierwszą operacją można porównać do broadcast a drugą do gather.

31 Operacje na pamięci odległej

32 Okno dostępu do pamięci: część pamięci adresowej danego procesora udostępnionej dla innych procesorów będących w danym komunikatorze. Utworzenie okna dostępu do pamięci jest operacją komunikacji zbiorowej. Okna dostępu do pamięci tworzą rozproszony obiekt złożony z częśći pamięci procesorów dostępnych dla innych. W obrębie okna są dostępne operacje: –get : uzyskiwanie danych z okna pamięci, –put : umieszczanie danych w oknie pamięci, –accumulate : modyfikacja danych w oknie dostępu do pamięci (np. dodawanie nowego składnika do sumy). Te operacje są niewstrzymujące i wymagają synchronizacji ( fence ).

33 get put Lokalna przestrzeń adresowa Okna dostępu do pamięci odległej Ilustracja operacji na pamięci odległej Procesor 0Procesor 1

34 Dla ilustracji rozważymy jeszcze raz obliczanie liczby  przez całkowanie numeryczne pochodnej funkcji arcus tangens metodą trapezów. Ilustracja przybliżonego obliczania liczby  przez całkowanie numeryczne dla liczby przedziałów n=10.

35 Zrównoleglenie algorytmu 1.Przedział całkowania dzieli się na n części: 1, 2,..., n 2.W układzie m procesorów, procesor 1 sumuje wkłady dla części 1, m+1, procesor 2 dla 2, m+2itd. 3.Procesory przesyłają swoje obliczone cząstkowe sumy do mastera, który oblicza sumę całkowitą. Źródło programu z użyciem MPI-1 (operacje broadcast i reduce) (C) Źrodło programu z użyciem MPI-2 (operacje na pamięci odległej) (C)

36 MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&n umprocs); MPI_Comm_rank(MPI_COMM_WORLD,& myid); MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&n umprocs); MPI_Comm_rank(MPI_COMM_WORLD,& myid); if (myid == 0) { MPI_Win_create(&n, sizeof(int), 1, MPI_INFO_NULL,MPI_COMM_WORLD, &nwin); MPI_Win_create(&pi, sizeof(double), 1, MPI_INFO_NULL,MPI_COMM_WORLD, &piwin); } else { MPI_Win_create(MPI_BOTTOM, 0, 1, MPI_INFO_NULL,MPI_COMM_WORLD, &nwin); MPI_Win_create(MPI_BOTTOM, 0, 1, MPI_INFO_NULL,MPI_COMM_WORLD, &piwin); } Porównanie kodu w MPI-1 (po lewej) z kodem w MPI-2 (po prawej)

37 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; 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; while (1) { if (myid == 0) { printf("Enter the number of intervals: (0 quits) "); scanf("%d",&n); pi = 0.0; } MPI_Win_fence(0, nwin); if (myid != 0) MPI_Get(&n, 1, MPI_INT, 0, 0, 1, MPI_INT, nwin); MPI_Win_fence(0, nwin); if (n == 0) break; else { 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;

38 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(); MPI_Win_fence( 0, piwin); MPI_Accumulate(&mypi, 1, MPI_DOUBLE, 0, 0, 1, MPI_DOUBLE, MPI_SUM, piwin); MPI_Win_fence(0, piwin); if (myid == 0) printf("pi is approximately %.16f, Error is %.16f\n", pi, fabs(pi - PI25DT)); } MPI_Win_free(&nwin); MPI_Win_free(&piwin); MPI_Finalize();

39 MPI_WIN_CREATE(base, size, disp_unit, info, comm, win) [IN base] początkowy adres okna (choice) [IN size] rozmiar okna w bajtach (integer, nieujemny) [IN disp_unit] lokalna jednostka przesunięcia w bajtach (integer, dodatni) [IN info] “pokrętło” obiektu informacyjnego (handle) [IN comm] komunikator (handle) [OUT win] “pokrętło” do okna (handle) C: int MPI_Win_create(void *base, MPI_Aint size, int disp_unit, MPI_Info info, MPI_Comm comm, MPI_Win *win) FORTRAN/FORTRAN90: MPI_WIN_CREATE(BASE, SIZE, DISP_UNIT, INFO, COMM, WIN, IERROR) BASE(*) INTEGER(KIND=MPI_ADDRESS_KIND) SIZE INTEGER DISP_UNIT, INFO, COMM, WIN, IERROR C++: static MPI::Win MPI::Win::Create(const void* base, MPI::Aint size, int disp_unit, const MPI::Info& info, const MPI::Intracomm& comm)

40 MPI_GET(origin_addr, origin_count, origin_datatype, target_rank, target_disp, target_count, target_datatype, win) [OUT origin_addr] początkowy adres początkowego bufora (choice) [IN origin_count] liczba elementów początkowego bufora (integer, nieujemny) [IN origin_datatype] typ danych każdego elementu (handle) [IN target_rank] rząd procesora celowego (integer, nieujemny) [IN target_disp] przesunięcie okna w stosunku do bufora celowego (integer, nieujemny) [IN target_count] liczba elementów bufora celowego (integer, nieujemny) [IN target_datatype] typ danych poszczególnych elementów bufora celowego (handle) [IN win] obiekt okna używany w komunikacji (handle)

41 C: int MPI_Get(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win) FORTRAN/FORTRAN90 MPI_GET(ORIGIN_ADDR, ORIGIN_COUNT, ORIGIN_DATATYPE, TARGET_RANK, TARGET_DISP, TARGET_COUNT, TARGET_DATATYPE, WIN, IERROR) ORIGIN_ADDR(*) INTEGER(KIND=MPI_ADDRESS_KIND) TARGET_DISP INTEGER ORIGIN_COUNT, ORIGIN_DATATYPE, TARGET_RANK, TARGET_COUNT, TARGET_DATATYPE, WIN, IERROR C++: void MPI::Win::Get(const void *origin_addr, int origin_count, const MPI::Datatype& origin_datatype, int target_rank, MPI::Aint target_disp, int target_count, const MPI::Datatype& target_datatype) const

42 MPI_WIN_FENCE(assert, win) [IN assert] asercja programowa (integer) [IN win] obiekt okna (handle) C: int MPI_Win_fence(int assert, MPI_Win win) FORTRAN/FORTRAN90: MPI_WIN_FENCE(ASSERT, WIN, IERROR) INTEGER ASSERT, WIN, IERROR C++: void MPI::Win::Fence(int assert) const

43 MPI_WIN_FREE(win) [INOUT win] obiekt okna (handle) C: int MPI_Win_free(MPI_Win *win) FORTRAN/FORTRAN90: MPI_WIN_FREE(WIN, IERROR) INTEGER WIN, IERROR C++: void MPI::Win::Free()


Pobierz ppt "Podstawy MPI-2: część I Literatura: Using MPI-2. Advanced Features of the Message-Passing Interface, W. Gropp, E. Lusk, R. Thakur, MIT Press, Cambridge,"

Podobne prezentacje


Reklamy Google