Jakich funkcji potrzebują użytkownicy interfejsu MPI C ++?

28

Wersja 3.0 standardu MPI formalnie usunęła interfejs C ++ (wcześniej był przestarzały). Chociaż implementacje mogą nadal go obsługiwać, funkcje nowe w MPI-3 nie mają interfejsu C ++ zdefiniowanego w standardzie MPI. Więcej informacji można znaleźć na stronie http://blogs.cisco.com/performance/the-mpi-c-bindings-what-happened-and-why/ .

Motywacją do usunięcia interfejsu C ++ z MPI było to, że nie miał on znaczącej wartości w stosunku do interfejsu C. Było bardzo niewiele różnic innych niż „s / _ / :: / g” i wiele funkcji, do których przyzwyczajeni są użytkownicy C ++, nie było wykorzystywanych (np. Automatyczne określanie typu za pomocą szablonów).

Jako ktoś, kto uczestniczy w Forum MPI i pracuje z wieloma projektami C ++, które zaimplementowały własny interfejs C ++ do funkcji MPI C, chciałbym wiedzieć, jakie są pożądane cechy interfejsu C ++ do MPI. Chociaż nic się nie zobowiązuję, chciałbym zobaczyć wdrożenie samodzielnego interfejsu MPI C ++, który spełnia potrzeby wielu użytkowników.

I tak, znam Boost :: MPI ( http://www.boost.org/doc/libs/1_54_0/doc/html/mpi.html ), ale obsługuje on tylko funkcje MPI-1, a model serializacji byłby niezwykle trudne do obsługi RMA.

Jeden interfejs C ++ do MPI, który mi się podoba, to interfejs Elemental ( https://github.com/poulson/Elemental/blob/master/src/core/imports/mpi.cpp ), więc być może ludzie mogą podać jakieś pro i con wrt, że podejście. W szczególności myślę, że MpiMap rozwiązuje istotny problem.

Jeff
źródło
Nie sądzę, że jest to odpowiednie miejsce na takie pytanie.
Jack Poulson
Czy możesz podać kilka powodów? Wiele pytań MPI na tej stronie sugeruje, że ludzie tutaj są gotowi odpowiedzieć na to pytanie. Również 0,2 upvotes na minutę sugeruje, że inni ludzie nie zgadzają się z twoją oceną. W każdym razie bardziej pomocne byłoby zasugerowanie alternatywnego miejsca do opublikowania tego, jeśli nie podoba ci się bieżące miejsce.
Jeff
Pytanie jest cenne i myślę, że może uzyskać cenne odpowiedzi na szersze listy mailingowe z zakresu nauk obliczeniowych, jeśli są tam objęte. (Może NA-digest, SIAM-CSE, a nawet publiczny post w G +?) To pytanie może nie pasować do strony Stack Exchange, ponieważ jest subiektywne (patrz scicomp.stackexchange.com/help/dont-ask ) . Dopóki odpowiedzi są konkretne i koncentrują się na konkretnych przypadkach użycia (bez znaczących powtórzeń lub nakładania się), myślę, że warto zachować otwartość.
Geoff Oxberry
@Jeff: Pytanie jest dla mnie jak ankieta. Nie kwestionuję tego, że jest cenny, ale nie widzę, aby istniała jedna zaakceptowana odpowiedź. Czy takie pytanie byłoby nietypowe dla forum MPI?
Jack Poulson
@JackPoulson Nie chcę wiedzieć, co według autorów jest właściwą odpowiedzią; Chcę wiedzieć, czego potrzebują naukowcy obliczeniowi. Pod tym względem pytanie ma obiektywne odpowiedzi. Nie ma jednej właściwej odpowiedzi, ale to nie znaczy, że jest to sytuacja subiektywna.
Jeff

Odpowiedzi:

17

Pozwól mi najpierw odpowiedzieć, dlaczego uważam, że interfejsy C ++ do MPI na ogół nie były zbyt udane, ponieważ długo zastanawiałem się nad tym problemem, próbując zdecydować, czy powinniśmy po prostu użyć standardowych powiązań C MPI, czy też budować na czymś wyższym :

Kiedy patrzysz na rzeczywiste kody MPI (powiedzmy PETSc lub w moim przypadku deal.II), okazuje się, że być może, co zaskakujące, liczba wywołań MPI w rzeczywistości nie jest bardzo duża. Na przykład w 500k liniach transakcji. II jest tylko ~ 100 połączeń MPI. Konsekwencją tego jest to, że ból związany z korzystaniem z interfejsów niższego poziomu, takich jak wiązania MPI C, nie jest zbyt duży. I odwrotnie, nie można wiele zyskać, używając interfejsów wyższego poziomu.

Moje drugie spostrzeżenie jest takie, że wiele systemów ma zainstalowanych wiele bibliotek MPI (różne implementacje MPI lub różne wersje). Stanowi to znaczną trudność, jeśli chcesz użyć, powiedzmy, boost :: mpi, które nie składają się tylko z plików nagłówkowych: albo musi być wiele instalacji tego pakietu, albo trzeba go zbudować jako część projekt, który korzysta z boost :: mpi (ale to znowu problem sam w sobie, biorąc pod uwagę, że boost korzysta z własnego systemu kompilacji, co nie jest niczym innym)

Sądzę więc, że wszystko to sprzysięgło się w stosunku do obecnego zbioru interfejsów C ++ do MPI: stare wiązania MPI C ++ nie oferowały żadnych korzyści, a zewnętrzne pakiety miały problemy ze światem rzeczywistym.

To wszystko powiedziało, oto, jak myślę, funkcje zabójcy, które chciałbym mieć z interfejsu wyższego poziomu:

  • Powinien być ogólny. Konieczność określenia typu danych zmiennej zdecydowanie nie jest podobna do C ++. Oczywiście prowadzi to również do błędów. Klasa MpiMap firmy Elemental byłaby już dobrym pierwszym krokiem (chociaż nie mogę zrozumieć, dlaczego ta MpiMap::typezmienna nie jest stałą statyczną, więc można uzyskać do niej dostęp bez tworzenia obiektu).

  • Powinien mieć możliwości przesyłania strumieniowego dowolnych typów danych.

  • Operacje wymagające MPI_Opargumentu (np. Redukcje) powinny być ładnie zintegrowane z std::functioninterfejsem C ++ , aby łatwo było po prostu przekazać wskaźnik funkcji (lub lambda!), Zamiast konieczności niezgrabnego rejestrowania czegoś.

boost :: mpi faktycznie spełnia wszystkie z nich. Myślę, że gdyby to była biblioteka tylko z nagłówkami, byłaby o wiele bardziej popularna w praktyce. Pomógłby również, gdyby obsługiwał funkcje post-MPI 1.0, ale bądźmy szczerzy: obejmuje to większość tego, czego potrzebujemy przez większość czasu.

Wolfgang Bangerth
źródło
Jednym z problemów z serializacją w Boost :: MPI jest to, że nie działa z jednostronnym (inaczej RMA). Czy uważasz, że możliwe będzie tworzenie typów danych MPI dla obiektów C ++, którymi interesują się użytkownicy? Oczywiście teoretycznie wszystko powinno być wspierane, ale wolę zacząć od bardziej pragmatycznego celu.
Jeff
Myślę, że błędem jest myślenie, że szeregowe typy danych mogą kiedykolwiek działać z jednostronną komunikacją. Zakłada to pogląd, że serializacja obejmuje tylko pakowanie danych do łańcucha, a po drugiej stronie rozpakowywanie go ponownie. Ale funkcje serializacji mogą znacznie więcej (np. Śledzić wskaźniki do innych obiektów, liczyć bajty, które zostały serializowane itp.), Niż można oczekiwać, że będą działać, jeśli nie będzie można wykonać niczego na hoście docelowym. Uważam, że serializacja w stylu C ++ i jednostronna komunikacja to po prostu nie-starter. Myślę, że nikt nie powinien oczekiwać, że to zadziała, więc tak mało by tego brakowało.
Wolfgang Bangerth,
Cześć Wolfgang, masz rację, że MpiMap byłby bardziej elegancki, gdyby użył stałej zmiennej członka const. Zreorganizowałem wdrożenie: github.com/poulson/Elemental/commit/…
Jack Poulson
Tak, o wiele ładniej :-)
Wolfgang Bangerth,
+1 o nielicznych rozmowach MPI @WolfgangBangerth. Zasadniczo mpi ma przyspieszać obliczenia, chcesz zminimalizować połączenia mpi, ponieważ one cię kosztują!
Charles
6

Aby uruchomić piłkę, oto dwie moje potrzeby:

  • Interfejs powinien być w stanie wyeliminować zbędne lub niepotrzebne argumenty, np. MPI_IN_PLACE.
  • Interfejs powinien automatycznie wykrywać wbudowane typy danych alpi Elemental's MpiMap.
  • Jeśli / kiedykolwiek jest to możliwe, dla klas należy konstruować typy danych zdefiniowane przez użytkownika.
Jeff
źródło
5

Moja lista nie ma określonej kolejności preferencji. Interfejs powinien:

  • być tylko nagłówkiem, bez żadnych zależności, ale <mpi.h>i biblioteką standardową,
  • być ogólne i rozszerzalne,
  • nie blokuj tylko (jeśli chcesz blokować, to blokuj jawnie, nie domyślnie),
  • pozwalają na ciągłe łączenie operacji nieblokujących,
  • obsługa rozszerzalnej i wydajnej serializacji (np. Boost.Fusion, dzięki czemu współpracuje z RMA),
  • mieć zerową karę abstrakcji (tj. być co najmniej tak szybka jak interfejs C),
  • bądź bezpieczny (destruktor niegotowej przyszłości nazywa się? -> std :: terminate!),
  • mieć mocny DEBUGtryb z mnóstwem twierdzeń,
  • wyjątkowo bezpieczny dla typów (koniec ints / void * dla wszystkiego, do cholery chcę, żeby tagi były typami!),
  • powinien działać z lambdami (np. wszystkie redukuj + lambda),
  • konsekwentnie używaj wyjątków jako mechanizmu raportowania i obsługi błędów (koniec kodów błędów! koniec argumentów wyjściowych funkcji!),
  • MPI-IO powinien oferować nieblokujący interfejs I / O w stylu Boost.AFIO,
  • i postępuj zgodnie z dobrymi nowoczesnymi praktykami projektowania interfejsu C ++ (definiuj typy regularne, funkcje nieprzyjazne dla innych członków, baw się dobrze semantyką ruchu, operacje zakresu wsparcia, ...)

Dodatki:

  • pozwól mi wybrać wykonawcę środowiska MPI, to znaczy, której puli wątków używa. W tej chwili możesz mieć aplikacje z mieszanką OpenMP, MPI, CUDA i TBB ... w tym samym czasie, gdzie każdy czas działania uważa, że ​​jest właścicielem środowiska, i dlatego pytaj system operacyjny o wątki za każdym razem, gdy mają na to ochotę to. Poważnie?

  • użyj konwencji nazewnictwa STL (i Boost). Czemu? Każdy programista w C ++ o tym wie.

Chcę napisać taki kod:

auto buffer = some_t{no_ranks};
auto future = gather(comm, root(comm), my_offsets, buffer)
              .then([&](){
                /* when the gather is finished, this lambda will 
                   execute at the root node, and perform an expensive operation
                   there asynchronously (compute data required for load 
                   redistribution) whose result is broadcasted to the rest 
                   of the communicator */
                return broadcast(comm, root(comm), buffer);
              }).then([&]() {
                /* when broadcast is finished, this lambda executes 
                   on all processes in the communicator, performing an expensive
                   operation asynchronously (redistribute the load, 
                   maybe using non-blocking point-to-point communication) */
                 return do_something_with(buffer);
              }).then([&](auto result) {
                 /* finally perform a reduction on the result to check
                    everything went fine */
                 return all_reduce(comm, root(comm), result, 
                                  [](auto acc, auto v) { return acc && v; }); 
              }).then([&](auto result) {
                  /* check the result at every process */
                  if (result) { return; /* we are done */ }
                  else {
                    root_only([](){ write_some_error_log(); });
                    throw some_exception;
                  }
              });

/* Here nothing has happened yet! */

/* ... lots and lots of unrelated code that can execute concurrently 
   and overlaps with communication ... */

/* When we now call future.get() we will block 
   on the whole chain (which might have finished by then!).
*/

future.get();

Pomyśl, jak można połączyć wszystkie te operacje za pomocą MPI_C request. Będziesz musiał przetestować na wielu (lub na każdym) pośrednim kroku przez wiele niepowiązanych kodów, aby sprawdzić, czy możesz przyspieszyć swój łańcuch bez blokowania .

gnzlbg
źródło
To jest wyczerpująca lista wymagań. Niektóre z nich są niemożliwe do wszystkich praktycznych celów (np. Wspieranie jagniąt w redukcjach). Jednak ogólnie uważam, że jest to coś, co społeczność MPI powinna starać się wspierać.
Jeff
Jeśli chodzi o wątki i środowisko wykonawcze, MPI nie używa wewnętrznie żadnych wątków ani wątków systemu operacyjnego (POSIX, Windows lub Solaris, w zależności od systemu operacyjnego). Nie jestem pewien, czy rozumiem tutaj wymóg.
Jeff
Problem polega na tym, że MPI może dowolnie żądać wątków z systemu operacyjnego. Moja aplikacja ma pulę wątków i chciałbym, aby MPI żądał tych wątków z mojej puli wątków. Obecnie nie jest to możliwe (i zazwyczaj nie stanowi problemu), chyba że masz aplikację korzystającą z OpenMP, TBB i MPI, każda z własną pulą wątków, każda z 4x liczbą rdzeni.
gnzlbg
1
MPI może, ale ogólnie nie korzysta wewnętrznie z wątków systemu operacyjnego. W każdym przypadku, z którym jestem zaznajomiony (MPICH (2), MVAPICH2, OpenMPI, CrayMPI), tylko opcja środowiska uruchomieniowego dostarczona przez użytkownika powoduje, że tak się dzieje, tzn. Domyślnie jest tak, że nie. Blue Gene / Q MPI jest wyjątkiem, ale w takiej formie, aby nie była istotna w tej dyskusji.
Jeff
Dzięki @Jeff! Czy mógłbyś wyjaśnić, w jaki sposób MPI obsługuje wiele nieblokujących połączeń podczas korzystania z jednego wątku? Czy korzysta z coroutines / zielonych nici / włókien?
gnzlbg
2

Osobiście nie mam nic przeciwko wywoływaniu długich funkcji w stylu C z dokładnie tego powodu, o którym wspomniał Wolfgang; jest naprawdę niewiele miejsc, do których trzeba do nich zadzwonić, a nawet wtedy prawie zawsze otacza je jakiś kod wyższego poziomu.

Jedynymi rzeczami, które naprawdę przeszkadzają mi w MPI w stylu C, są niestandardowe typy danych i, w mniejszym stopniu, niestandardowe operacje (ponieważ używam ich rzadziej). Jeśli chodzi o niestandardowe typy danych, powiedziałbym, że dobry interfejs C ++ powinien być w stanie obsługiwać ogólny i wydajny sposób obsługi tego, najprawdopodobniej poprzez serializację. Jest to oczywiście trasa, boost.mpiktórą obrałeś, a jeśli będziesz ostrożny , zaoszczędzisz dużo czasu.

Jeśli chodzi boost.mpio dodatkowe zależności (zwłaszcza, że boost.serializationsam nie jest tylko nagłówkiem), ostatnio natknąłem się na bibliotekę serializacji C ++ zawierającą tylko nagłówki, zwaną zbożem, która wydaje się obiecująca; przyznano, że wymaga kompilatora zgodnego z C ++ 11. Warto przyjrzeć się i wykorzystać jako podstawę czegoś podobnego do boost.mpi.

GradGuy
źródło
Zauważ, że niekoniecznie szukałem czegoś, co można by umieścić w standardzie MPI. Całkowicie zgadzam się z tym, że MPI prawie zawsze powinno być „otoczone jakimś kodem wyższego poziomu”, więc zastanawiam się, jak wygląda ten kod wyższego poziomu? Elemental ma fajne podejście, ale czy jest najlepsze we wszystkich przypadkach? Gdyby ktoś chciał mieć interfejs C ++ do MPI, który próbował uszczęśliwić bardzo dużą liczbę ludzi, jak by to wyglądało?
Jeff
@Jeff. Dla mnie: 1. Lubię z łatwością wysyłać niestandardowe typy danych. 2. Lubię być w stanie z łatwością przeprowadzać redukcję za pomocą niestandardowych operacji. Myślę też, że 1
kołysam się ważniej
Nie rozumiem, jak C ++ robi coś magicznego wrt (2). Co tu sobie wyobrażasz?
Jeff
@Jeff Zastanawiałem się nad tym, jak thrustto zrobić w przypadku redukcji: docs.thrust.googlecode.com/hg/group__reductions.html
GradGuy
-1

Projekt github easyLambda zapewnia interfejs wysokiego poziomu do MPI z C ++ 14.

Myślę, że projekt ma podobne cele i da pewne wyobrażenie o tym, co może być i co jest robione w tej dziedzinie przy użyciu nowoczesnego C ++. Kierowanie innymi wysiłkami, a także sama easyLambda.

Początkowe testy wydajności i wierszy kodu wykazały obiecujące wyniki.

wprowadź opis zdjęcia tutaj

Poniżej znajduje się krótki opis funkcji i interfejsu, który zapewnia.

Interfejs oparty jest na programowaniu przepływu danych i funkcyjnych operacjach listowych, które zapewniają nieodłączną równoległość. Równoległość jest wyrażona jako właściwość zadania. Przydziału procesu i dystrybucji danych dla zadania można zażądać za pomocą właściwości .prll (). Istnieje wiele przykładów na stronie internetowej i repozytorium kodów, które obejmują dynamikę molekularną LAMMPS po przetworzeniu, wyraźne rozwiązanie różnic skończonych do równania ciepła, regresję logistyczną itp. Jako przykład problem dyfuzji ciepła omawiany w artykule HPC umiera ... można wyrazić w ~ 20 wierszach kodu.

Mam nadzieję, że można podawać linki zamiast dodawać tutaj więcej szczegółów i przykładowych kodów.

Disclamer: Jestem autorem biblioteki. Uważam, że nie robię nic złego, mając nadzieję uzyskać konstruktywną informację zwrotną na temat obecnego interfejsu easyLambda, który może być korzystny dla easyLambda i innych projektów realizujących podobne cele.

Utkarsh Bhardwaj
źródło
Pytanie brzmi: „ Szukamy długich odpowiedzi, które zawierają wyjaśnienie i kontekst. Nie udzielaj odpowiedzi tylko w jednym wierszu; wyjaśnij, dlaczego Twoja odpowiedź jest poprawna, najlepiej z cytatami. Odpowiedzi, które nie zawierają wyjaśnień, mogą zostać usunięte . ” Dlaczego uważasz, że twoja odpowiedź jest wystarczająco kompletna, aby pasowała do tego opisu?
nicoguaro
Wskazuję na projekt, który zapewnia interfejs podobny do tego, o który prosi OP. Potrafię podać szczegóły motywacji i cech projektu w samej odpowiedzi, a OP i inni mogą przeczytać i zasugerować, co o nim myślą. Jednak zdecydowałem się podać tylko linki. Wiem o co ci chodzi. Pozwól mi dodać tekst z odniesieniami do odpowiedzi.
Utkarsh Bhardwaj
@UtkarshBhardwaj: Kilka komentarzy: (1) Dziękujemy za napisanie biblioteki, która łączy C ++ z MPI. To znaczące przedsięwzięcie i wygląda na to, że włożyłeś w to dużo pracy. (2) Szybko przeglądając dokumenty (znowu, niezła robota), wyróżnia się długi łańcuch używanych poleceń metod, który wydaje się stylistycznie ... bolesny przy debugowaniu, nawet jeśli ładnie je sformatowałeś. (3) Abstrakcje zakładają funkcjonalny paradygmat, który wygląda na użyteczny w zadaniach podobnych do mapowania, ale jako ktoś, kto programuje w MPI, nie chcę przerabiać moich algorytmów i zbytnio oddalać się od interfejsów, które znam.
Geoff Oxberry
(4) W tym przykładzie nigdzie nie widzę komunikatorów, co prowadzi mnie do podejrzeń, że używasz MPI_COMM_WORLD do wszystkiego, i ogranicza potencjał twojej biblioteki. (5) Wydaje się, że abstrakcje opierają się na abstrakcjach MPI i mogą mieć inne zaplecze. (6) Na podstawie (3) - (5), nie sądzę, że ta biblioteka jest interfejsem MPI i uważam, że ten komentarz jest w związku z tym nie na temat.
Geoff Oxberry
@Geoff dzięki za cenne opinie, bardzo dziękuję. Odpowiedz na określone punkty: 2) Łańcuch jest czasami nazywany ExpressionBuilder . Jest to powszechny sposób wyrażania kompozycji w funkcjonalnym stylu. Pisanie w tym stylu w ezl nie jest konieczne. Można najpierw napisać poszczególne jednostki, a następnie je skomponować, sprawdź [przykład] ( goo.gl/YzaL0k ). 3) Wiem, że trudno jest przejść od kontroli przepływu i imperatywu do przepływu danych i funkcjonalności. Każdy ma wady i zalety. Uważam jednak, że należy to zbadać bardziej, aby poznać jego prawdziwą skuteczność.
Utkarsh Bhardwaj