jaca 23.doc

(186 KB) Pobierz

MPI-2 (pojawiła się w 1997r.)

 

l W 1995 przeprowadzono ankietę wśród użytkowników MPI, pytając co chcieliby widzieć w kolejnej wersji standardu. Najczęściej padały prośby o dodanie:

l        dynamicznego zarządzania procesami

(startowanie nowych procesów w trakcie działania programu, etc.),

l        wsparcia dla C++ (już z niego korzystamy),

l        komunikacji jednostronnej (wszystkie informacje potrzebne do przesłania wiadomości dostarcza jedna strona, drugiej nie zawraca się głowy).

Operacje typu Put i Get, pozwalają pisać i czytać z węzła bez jego udziału.

l        równoległego we/wy.

 

l Nie wszystkie implementacje MPI dysponują rozszerzeniami z MPI-2, ale większość tak.

 

l        Po co nam równoległe we/wy?

l Najczęściej mamy do czynienia z sytuacją, w której każdy węzeł pracuje na porcji danych (dekompozycja danych). W pamięci masowej chcielibyśmy jednak mieć wszystkie dane w (uporządkowanej) całości.

 

<---> Bez równoległego we/wy – metoda 1

l Każdy węzeł może zapisywać dane do oddzielnego pliku.

l Łatwe do zrobienia, ale ma szereg wad:

l        Podczas obróbki danych (post-processing) niewygodnie jest pracować z wieloma plikami zamiast z jednym.

l        Co zrobić, jeśli liczba węzłów zmieni się pomiędzy kolejnymi wywołaniami programu? Przykładowo program pracował na 4 węzłach, wyprodukował 4 pliki wyjściowe, a jutro chcemy by pracował na 5 węzłach.

l        Potrzeba dodatkowych użytków, które sklejałyby pliki do jednego po tym, jak program zakończy się strata czasu i przestrzeni dyskowej (co if pliki po 4 GB?).

l        Zapis do wielu plików jest niewydajny (seek,fragmentacja).

 

<---> Bez równoległego we/wy – metoda 2

l Można zebrać dane na 1 węźle korzystając z przesyłania wiad.i zapisać je z tego węzła.

l Wady tego rozwiązania:

l        Nierówny podział pracy – węzeł, na którym piszemy do pliku jest zajęty wykonując we/wy, podczas gdy pozostałe węzły nudzą się.

l        Na węźle odpowiedzialnym za we/wy potrzebujemy mnóstwo dodatkowej pamięci, żeby pomieścić naraz dane ze wszystkich węzłów (jeśli korzystamy z Gather).

l        Można przesyłać po kawałku i pisać po kawałku, ale wtedy pozostałe węzły są dłużej zajęte (czekają z przesłaniem reszty master zapisze poprzednią porcję).

l        Obciążenie sieci teraz wszystkie dane muszą przejść przez węzeł master, a być może bezpośrednie połączenia węzeł-serwer plików są krótsze.

 

MPI-2 oferuje równoległe we/wy – wszystkie węzły piszą jednocześnie do jednego pliku

 

l Wygodne (dostajemy jeden plik).

l Dobry podział pracy (wszystkie węzły zajęte).

l Efektywne (MPI i SO mogą optymalizować zapisy i odczyty).

l Podobnie dla odczytu.

 

Równoległe we/wy – jak?

l Skoncentrujmy uwagę na najbardziej pospolitej czynności –  wczytaniu danych

z jednego pliku na wiele węzłów tak, że każdy z nich dostaje fragment danych.

 

l Trzy metody:

l        przesuń wskaźnik pliku i czytaj,

l        czytaj-od-miejsca (read_at),

l        widoki plików.

 

<---> Równoległe we/wy – otwarcie pliku

 

l Zaczynamy od równoległego otwarcia pliku:

static MPI::File MPI::File::Open(const MPI::Intracomm& comm,

const char *filename, int amode, const MPI::Info& info);

l To jest operacja zbiorowa wszystkie węzły  komunikatora muszą ją wywołać.

 

 

<---> Równoległe we/wy zamykanie pliku

 

l Gdy skończymy pracę z plikiem, trzeba go zamknąć:

void MPI::File::Close();

l Zatem wołamy metodę Close() na rzecz obiektu klasy MPI::File, który reprezentuje nasz plik i który otrzymaliśmy jako wynik działania funkcji MPI::File::Open().

l To też jest operacja zbiorowa wszystkie węzły muszą jednocześnie zamykać plik.

l Musimy zamknąć wszystkie pliki zanim wywołamy MPI::Finalize().

l W momencie zamknięcia pliku musimy zagwarantować, że wszystkie nieblokujące operacje we/wy zakończyły się (my mówimy tylko o blokujących operacjach we/wy).

 

<---> Równoległe we/wy – czytamy z pliku

 

l Odczyt wygląda podobnie do odbierania wiadomości:

void MPI::File::Read(void* buf, int count,const MPI::Datatype& datatype, PI::Status& status);

l NIE jest operacją grupową (!) nie wszystkie węzły komunikatora muszą czytać.

 

Jeśli chcemy czytać na niektórych węzłach, wywołujemy MPI::File::Read() tylko na tych.

l Istnieje wersja: MPI::File::Read_all(), która służy do odczytu na wszystkich węzłach.

l Jeśli czytamy na wszystkich węzłach, korzystniej jest zastosować wersję grupową z uwagi na możliwość optymalizacji odczytu przez MPI i SO.

 

<---> Równoległe we/wy – uwagi dot. odczytu

 

l Wskaźniki pozycji pliku są niezależne na wszystkich węzłach.

l Oznacza to, że odczyt na jednym węźle nie ma wpływu na stan pliku

(w szczególności na wskaźnik pozycji pliku) na pozostałych węzłach

l Po tym jak węzeł A dokonał odczytu jego wskaźnik pozycji pliku przesuwa się, ale wskaźnik pozycji na B pozostaje niezmieniony.

l Istnieje przeciążona wersja operacji Read() pozbawiona ostatniego argumentu (status) korzystamy z niej jeśli status nas nie interesuje.

l Liczbę odczytanych elementów możemy wydobyć za pomocą metody Get_count().

l Kontrolą błędów musimy się zająć sami.

<--->  Równoległe we/wy – zapis do pliku

 

l Analogicznie do odczytu (i podobnie do wysłania wiadomości):

void MPI::File::Write(const void* buf, int count,

const MPI::Datatype& datatype, MPI::Status& status);

l Podobnie jak poprzednio: NIE jest operacją zbiorową (!) nie wszystkie węzły komunikatora muszą pisać.

l Jeśli jednak piszemy na wszystkich węzłach, warto skorzystać ze zbiorowej operacji MPI::File::Write_all() pozwoli ona MPI optymalizować zapis.

l Argumenty jak dla MPI::File::Read(), tylko bufor jest const.

l Jak przy odczycie – każdy węzeł ma swój, niezależny wskaźnik zapisu.

l Sygnalizacja problemu: co ...

Zgłoś jeśli naruszono regulamin