Przejdź do treści

MPI-IO

Wprowadzenie

MPI-IO to część standardu MPI definiująca API do równoległej pracy z plikami umieszczonymi we współdzielonym, sieciowym systemie plików przez wiele rozproszonych procesów. Przewidziany szczególnie do wydajnej pracy z równoległymi systemami plików, takimi jak Lustre czy GPFS.

MPI-IO jest traktowane jako niskopoziomowe API do równoległego I/O, chociaż nadaje się również do bezpośredniego użycia. Wyżej poziomowe biblioteki jak np. HDF5 czy NetCDF, w zakresie pracy z plikami rozproszonymi często bazują właśnie na MPI-IO (patrz parallel-HDF5).

W standardzie MPI obecny od wersji MPI-2 (patrz MPI > Informacje o standardzie), na przestrzeni lat interfejs przechodzi tylko nieznaczne zmiany. Z istotnych, w MPI-3 dodano funkcje iread/iwrite dla operacji kolektywnych, które powinny być używane w miejsce dotychczasowych split collective tj. funkcji z sufiksami _begin oraz _end.

Dostępność

Jako część standardu, MPI-IO jest dostarczane w ramach implementacji biblioteki MPI (patrz MPI > Implementacje). Standard określa interfejs programistyczny dla języków C / C++ / Fortran. Implementacja mpi4py dla języka Python również udostępnia funkcje MPI-IO.

Ważną implementacją MPI-IO jest ROMIO, które obecnie jest rozwijane w ramach MPICH. Wiele implementacji MPI w części dotyczącej I/O również opiera się o ROMIO, dlatego pewien zestaw optymalizacji (wskazówek) związanych z I/O jest przenośny pomiędzy różnymi bibliotekami MPI.

Szczegóły

Podstawowe funkcjonalności

Podstawowe funkcjonalności dostarczane przez MPI-IO rozwijające standardowe metody pracy z plikami udostępniane przez system operacyjny, to:

  • synchronizacja wielu procesów przy pracy ze współdzielonymi plikami,
  • możliwość równoległego odczytu/zapisu danych z/do pliku przez wiele procesów,
  • możliwość odczytywania/zapisywania nieciągłego układu danych w pliku.

Biblioteka udostępnia programiście standardowy logiczny widok pliku (ciągły strumień danych). Dane w pliku są zapisywane w postaci binarnej, przy czym możliwe jest kilka reprezentacji danych (konwersji między reprezentacją danych w pamięci programu, a reprezentacją na dysku twardym). Szczegóły wykonania fizycznego odczytu/zapisu są zależne od implementacji biblioteki.

parallel access

równoległy dostęp do plików [źródło, slajd 473]

Biblioteka daje możliwość przeplatania danych z różnych procesów, poprzez definiowanie widoku na plik. Dzięki widokowi każdy proces może odczytywać/zapisywać podzbiór danych według zadanego schematu danych. Definiowanie schematu jest oparte o złożone typy danych (MPI Derived Datatypes).

file views

równoległy dostęp do plików, widok pliku [źródło, slajd 481]

Sposoby dostępu

Współdzielona praca nad plikiem opiera się o kolektywne otwarcie pliku przez grupę procesów (wszystkie procesy muszą wywołać funkcję aby doszło do jej wykonania).

Dostęp (odczyt/zapis) do danych jest możliwy przez:

  • bezpośrednią adresację, tj. podanie pozycji względem początku pliku (offset),
  • indywidualny wskaźnik danego procesu (automatycznie przesuwany),
  • współdzielony wskaźnik grupy procesów (automatycznie przesuwany i synchronizowany).

Dostęp jest możliwy zarówno w sposób indywidualny jak i grupowy (funkcje read oraz write posiadają swoje kolektywny odpowiedniki z sufiksem _al).

Standardowy dostęp do danych jest blokujący (funkcja zwraca sterowanie dopiero po wykonaniu operacji I/O), ale biblioteka umożliwia również dostęp nieblokujący według schematu:

  • szybkie zainicjowanie dostępu do danych,
  • powrót do obliczeń,
  • zaczekanie aż dane będą dostępne.

Taki sposób stwarza okazję do asynchronicznego odczytu/zapisu danych. Należy mieć na uwadze, że prawdziwa asynchroniczność zależy od implementacji biblioteki, standard jej nie wymusza (np. cała praca z odbiorem danych może zostać wykonana dopiero w momencie zaczekania na zakończenie operacji).

Optymalizacja równoległego dostępu

Typową metodą optymalizacji równoległego dostępu do pliku jest tzw. kolektywne buforowanie (zwane również “dwufazowym I/O”), w którym występuje faza komunikacji i wymiany danych między procesami, oraz faza bezpośredniego dostępu do systemu plików.

collective buffering

wizualizacja kolektywnego buforowania [źródło]

Na przykładzie zapisu, najpierw dane są wymieniane między procesami przez sieć i zostają zgrupowane w buforach tylko kilku procesów (agregatorzy). Dane są grupowane w taki sposób, by umożliwić sekwencyjny zapis dłuższych fragmentów do pliku. Następnie tylko te kilka procesów wykonuje operacje zapisu. Dzięki takiemu podejściu biblioteka MPI porządkuje sposób dostępu i interakcja z systemem plików zostaje zoptymalizowana.

collective access

łączenie pojedynczych żądań w większe operacje [źródło]

Na sposób fizycznego zapisu można wpływać (optymalizować) poprzez wskazówki dla biblioteki, które można przekazać na dwa sposoby:

  • w kodzie aplikacji, definiując odpowiednie wartości w obiektach MPI_Info (podawanych przy otwieraniu pliku),
  • w momencie uruchomienia programu, eksportując wartości odpowiednich zmiennych środowiskowych.

Typowo wskazówki służą do:

  • ustawienia parametrów pliku w równoległym systemie plików (np. striping_unit, striping_factor dla systemów plików typu Lustre)
  • optymalizacji metod zbierania danych z wielu procesów (np. rozmiary i ilość buforów do agregacji danych)

Kwestia sposobu wykorzystania wskazówek jest zależna od implementacji biblioteki. Każda biblioteka definiuje swój zestaw wskazówek i konfigurowalnych zmiennych środowiskowych.

Linki


Ostatnia aktualizacja: 7 grudnia 2023