slide1 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Najczęstsze błędy i wypaczenia przy stosowaniu komunikacji zbiorowej PowerPoint Presentation
Download Presentation
Najczęstsze błędy i wypaczenia przy stosowaniu komunikacji zbiorowej

play fullscreen
1 / 32

Najczęstsze błędy i wypaczenia przy stosowaniu komunikacji zbiorowej

125 Views Download Presentation
Download Presentation

Najczęstsze błędy i wypaczenia przy stosowaniu komunikacji zbiorowej

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. Komunikacja zbiorowa: część II • Najczęstsze błędy i wypaczenia przy stosowaniu komunikacji zbiorowej • Grupy procesów i podział komunikatorów • Operacje na grupach procesów • Komunikacja wewnątrzgrupowa i komunikatory wewnętrzne • Komunikacja międzygrupowa i komunikatory zewnętrzne

  2. Błędy i wypaczenia w komunikacji zbiorowej • Wywołanie procedury komunikacji zbiorowej tylko dla części procesorów zawartych w zaspecyfikowanym komunikatorze. • W szczególności zapomnienie o tym, że w przypadku MPI_Bcast zarówno procesor źródłowy jak i wszyscy odbiorcy muszą zawołać tę procedurę. • Założenie, że wszystkie procesory jednocześnie zakończą wykonywanie danej procedury komunikacji zbiorowej. • Użycie tego samego bufora wejściowego i wyjściowego w wywołaniu MPI_Reduce (MPI_Allreduce).

  3. 1 i 2. Wywołanie w zależności od procesora (BARDZO POWAŻNY błąd, bo nie powoduje zatrzymania programu i przez to znakomicie utrudnia jego odrobaczenie). if (rank == 0) { MPI_Bcast(dane, ..., Master, ..., MPI_COMM_WORLD); do_masters_work(); else { do_work(dane,wyniki); MPI_Gather(wyniki,...,Master,...,MPI_COMM_WORLD); } W takim przypadku master wyśle dane do pozostałych procesorów ale dane te nigdy nie zostaną odebrane, natomiast wyniki wysłane przez robotników nigdy nie zostaną odebrane przez mastera. Należy napisać tak: MPI_Bcast(dane, ..., Master, ..., MPI_COMM_WORLD); if (rank == 0) { do_masters_work(); else do_work(dane,wyniki); } MPI_Gather(wyniki,...,Master,...,MPI_COMM_WORLD);

  4. 4. Użycie tego samego bufora wejściowego i wyjściowego w MPI_Reduce call MPI_Allreduce(a, a, 1, MPI_REAL, MPI_SUM, comm, ierr); Spowoduje to natychmiastowy bład wykonania i przerwanie programu, więc błąd taki jest łatwy do wykrycia. Wymóg, aby bufor wyjściowy był różny od wyjściowego zapewnia kompatybilność ze standartem FORTRANu (przekazywanie zmiennej przez adres a nie przez wartość); w związku z tym ograniczenie obowiązuje również przy wołaniu MPI_Reduce w programach w C. Poprawny kod: call MPI_Allreduce(a, a_sum, 1, MPI_REAL, MPI_SUM, comm, ierr);

  5. Grupy procesów i podział komunikatorów • Grupa procesów: zbiór procesorów uporządkowany według rzędu. W MPI zdefiniowano „pustą” grupę: MPI_GROUP_EMPTY oraz dwie stałe: MPI_GROUP_EMPTY (odnośnik do grupy pustej) oraz MPI_GROUP_NULL (odnośnik do grupy zdefiniowanej niewłaściwie). • Podział komunikatorów: • Komunikatory wewnętrzne (intrakomunikatory): służą do komunikacji w obrębie grupy; możliwa jest komunikacja punktowa i zbiorowa. • Komunikatory zewnętrzne (interkomunikatory): służą do komunikacji pomiędzy dwoma grupami. W standarcie MPI-1 możliwa jest jedynie komunikacja punktowa (MPI_Send i MPI_Receive).

  6. Funkcjonalność Intrakomunikator Interkomunikator Liczba grup 1 2 Bezpieczeństwo Tak Tak Komunikacja zbiorowa Tak Nie Topologie Tak Nie Kaszowanie Tak Tak Charakterystyka intra- i interkomunikatorów

  7. Operacje na grupach MPI_GROUP_SIZE(group, size): zwraca liczbę procesorów w grupie. MPI_Group_size(MPI_Group group, int *size) MPI_GROUP_SIZE(GROUP, SIZE, IERROR) INTEGER GROUP, SIZE, IERROR group - grupa size - liczba procesorów w grupie MPI_GROUP_RANK(group, rank): zwraca rząd danego procesora w grupie; jeżeli procesor nie jest w grupie jest zwracany rząd MPI_UNDEFINED. group - grupa rank - rząd procesora w grupie. MPI_Group_rank(MPI_Group group, int *rank) MPI_GROUP_RANK(GROUP, RANK, IERROR) INTEGER GROUP, RANK, IERROR

  8. MPI_GROUP_TRANSLATE_RANKS(group1, n, ranks1, group2, ranks2) podaje rzędy procesorów z jednej grupy w innej grupie; w przypadku, gdy któryś z procesorów nie należy do drugiej grupy zwraca w tym miejscu MPI_UNDEFINED. group1 - grupa pierwsza n - liczba procesorów w tablicach ranks1 i ranks2 ranks1 - tablica rzędów w grupie pierwszej group2 - grupa druga ranks2 - tablica rzędów w grupie drugiej MPI_Group_translate_ranks (MPI_Group group1, int n, int *ranks1, MPI_Group group2, int *ranks2) MPI_GROUP_TRANSLATE_RANKS(GROUP1, N, RANKS1, GROUP2, RANKS2, IERROR) INTEGER GROUP1, N, RANKS1(*), GROUP2, RANKS2(*), IERROR

  9. MPI_GROUP_COMPARE(group1, group2, result) • porównuje dwie grupy zwracając wynik w zmiennej result: • MPI_IDENT: grupy są identyczne; • MPI_SIMILAR: grupy zawierają te same procesory ale w innym porządku; • MPI_UNEQUAL: grupy są różne.

  10. Kreatory grup MPI_COMM_GROUP(comm, group) uzyskiwanie wskaźnika grupy (group) odpowiadającej komunikatorowi comm. MPI_Comm_group(MPI_Comm comm, MPI_Group *group) MPI_COMM_GROUP(COMM, GROUP, IERROR) INTEGER COMM, GROUP, IERROR

  11. Trzy standardowe operacje mnogościowe: MPI_GROUP_UNION(group1, group2, newgroup) MPI_GROUP_INTERSECTION(group1, group2, newgroup) MPI_GROUP_DIFFERENCE(group1, group2, newgroup)

  12. MPI_GROUP_INCL(group, n, ranks, newgroup) tworzenie nowej grupy z elementów starej. group - stara grupa; n - liczba procesorów ze starej grupy, które mają być włączone do nowej; ranks - tablica zawierająca te rzędy; newgroup - nowa grupa. MPI_Group_incl(MPI_Group group, int n, int *ranks, MPI_Group *newgroup) MPI_GROUP_INCL(GROUP, N, RANKS, NEWGROUP, IERROR) INTEGER GROUP, N, RANKS(*), NEWGROUP, IERROR MPI_GROUP_EXCL(group, n, ranks, newgroup) tworzy nową grupę ze starej poprzez wyłączenie n procesorów o rzędach podanej w tablicy ranks. Składnia analogiczna do MPI_GROUP_INCL.

  13. MPI_GROUP_RANGE_INCL(group, n, ranges, newgroup) MPI_GROUP_RANGE_EXCL(group, n, ranges, newgroup) Wygodniejsze formy poprzednich. Tablica ranges(3,*) zawiera zakresy włączanych/wyłączanych procesorów; ranges(1,i) i ranges(2,i) definiują odpowiednio pierwszy i ostatni procesorów w i-tym zakresie, ranges(3,i) mówi z jakim krokiem włącza/wyłącza się procesory (1 - każdy, 2 - co drugi, itd.). Destruktor grupy MPI_GROUP_FREE(group) MPI_Group_free(MPI_Group *group) MPI_GROUP_FREE(GROUP, IERROR) INTEGER GROUP, IERROR

  14. Komunikacja wewnątrzgrupowa i komunikatory wewnętrzne Komunikacja wewnątrzgrupowa: wymiana informacji w obrębie procesorów należących do jednej grupy. Możliwe jest tutaj stosowanie zarówno procedur komunikacji punktowej jak i zbiorowej.

  15. Operacje na komunikatorach MPI_COMM_SIZE(comm, size) MPI_COMM_RANK(comm, rank) MPI_COMM_COMPARE(comm1, comm2, result) Wartości zwracane przez MPI_COMM_COMPARE w zmiennej result są podobne jak w przypadku MPI_GROUP_COMPARE z wyjątkiem, że w przypadku identyczności grup odpowiadających komunikatorom comm1 i comm2 zwracana jest wartość MPI_CONGRUENT. Standardowe komunikatory MPI_COMM_WORLD: wszystkie procesory przydzielone zadaniu; MPI_COMM_SELF: dany procesor (zawsze ma rząd 0). MPI_COMM_NULL: pusty komunikator.

  16. Kreatory komunikatorów MPI_COMM_DUP(comm, newcomm) tworzenie duplikatu komunikatora. comm - stary komunikator; newcomm - nowy komunikator. MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm) MPI_COMM_DUP(COMM, NEWCOMM, IERROR) INTEGER COMM, NEWCOMM, IERROR

  17. MPI_COMM_CREATE(comm, group, newcomm) tworzenie („pączkowanie”) nowego komunikatora. comm - stary komunikator (może być MPI_COMM_WORLD); group - grupa procesorów, które mają utworzyć nowy komunikator; newcomm - nowy komunikator. int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm) MPI_COMM_CREATE(COMM, GROUP, NEWCOMM, IERROR) INTEGER COMM, GROUP, NEWCOMM, IERROR

  18. MPI_COMM_SPLIT(comm, color, key, newcomm) tworzenie nowych komunikatorów poprzez podział starego według przypisania zawartego w zmiennej color. comm - stary komunikator; color - kolor; procesory o różnych kolorach będą tworzyły różne komunikatory; key - klucz; wskazuje, jak ma wzrastać rząd procesorów (jeżeli dla dwóch procesorów w nowej grupie jest taki sam, kolejność rzędów jest tak jak kolejność rzędów w starej grupie); newcomm - nowy komunikator, w którym znajdzie się wywołujący procesor. Jeżeli nie chcemy, żeby dany procesor znalazł się w jakimkolwiek z nowych komunikatorów, nadajemy mu kolor MPI_UNDEFINED. MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm) MPI_COMM_SPLIT(COMM, COLOR, KEY, NEWCOMM, IERROR) INTEGER COMM, COLOR, KEY, NEWCOMM, IERROR

  19. Rozważmy grupę procesorów a-j o rzędach (w starym komunikatorze) od 0-9 (┴ oznacza kolor MPI_UNDEFINED): rząd 0 1 2 3 4 5 6 7 8 9 procesor a b c d e f g h i j kolor 0 3 0 3 0 0 5 3 klucz 3 1 2 5 1 1 1 2 1 0 ┴ ┴ • Wywołanie MPI_COMM_SPLIT dla tego układu spowoduje powstanie trzech nowych komunikatorów: • {f,g,a,d} (kolor 0); rzędy będą wynosiły odpowiednio 0, 1, 2, 3. • {e,i,c} (kolor 3); rzędy będą wynosiły 0, 1, 2. • {h} (kolor 5); rząd oczywiście 0. • Procesory b oraz j nie będą należały do żadnego z komunikatorów.

  20. Destruktor komunikatora MPI_COMM_FREE(comm) MPI_Comm_free(MPI_Comm *comm) MPI_COMM_FREE(COMM, IERROR) INTEGER COMM, IERROR

  21. Przykład: Obliczanie liczby p metodą Monte Carlo Algorytm obliczania liczby p: losujemy pary liczb (x,y) należące do przedziału [-1..1] a następnie obliczamy przybliżenie ze stosunku liczby wylosowanych punktów leżących w kole scentrowanym w punkcie (0,0) i o promieniu 1 do liczby wszystkich wylosowanych punktów.

  22. Dedykujemy procesor o najwyższym rzędzie jako serwer liczb losowych dla pozostałych procesorów. • Z pozostałych procesorów tworzymy grupę przy pomocy procedury MPI_GROUP_EXCL oraz MPI_COMM_CREATE grupę „robotników” i definiujemy odpowiedni komunikator workers. • „Robotnicy” obliczają ile przysłanych losowych punktów leży w kole (N_in) a ile poza nim (N_out), następnie wykorzystując proceduręMPI_ALLREDUCE działająca w obrębie komunikatora workers. • Jeżeli obliczone przybliżenie liczby różni się od wartości prawdziwej o mniej niż zadeklarowaną dokładność (pobierana z linii polecenia) lub przekroczono maksymalną zadeklarowaną liczbę kroków, program się kończy. Jeżeli nie, każdy z „robotników” wysyła do serwera żądanie inicjalizacji generatora liczb losowych i procedura jest powtarzana od punktu 3. • Kod źródłowy programu w języku C • Wyniki (4 procesory)

  23. Przykład zastosowania procedury MPI_Comm_split Źródło programu w C Wyniki

  24. Komunikacja międzygrupowa Komunikacja międzygrupowa: wymiana informacji pomiędzy procesami należącymi do rozłącznych grup. Komunikację międzygrupową stosuje się dla zadań modularnych, gdzie informacje muszą przepływać pomiędzy kolejnymi grupami (rura) lub, w bardziej ogólnym przypadku, płynąć po grafie zdefiniowanym przez interkomunikatory.

  25. Cechy komunikacji międzygrupowej: • Można stosować jedynie procedury komunikacji punktowej. • Pomiędzy grupami procesów definiuje się skierowane interkomunikatory; zbiór interkomunikatorów tworzy graf połączeń. • Procesy identyfikuje się poprzez ich rzędy w lokalnych grupach.

  26. Kreator interkomunikatorów MPI_INTERCOMM_CREATE(local_comm, local_leader, bridge_comm, remote_leader, tag, newintercomm) local_comm - komunikator lokalny local_leader - rząd procesora będącego „bazą” komunikatora lokalnego; musi być w bridge_comm bridge_comm - komunikator mostkujący; musi zawierać procesory obu łączonych grup (na ogół MPI_COMM_WORLD) remote_leader - rząd procesora-bazy komunikatora odległego (w bridge_comm) tag – „pieczątka” interkomunikatora newintercomm - nowo postały interkomunikator

  27. MPI_Intercomm_create(MPI_Comm local_comm, int local_leader, MPI_Comm bridge_comm, int remote_leader, int tag, MPI_Comm *newintercomm) MPI_INTERCOMM_CREATE(LOCAL_COMM, LOCAL_LEADER, PEER_COMM, REMOTE_LEADER, TAG, NEWINTERCOMM, IERROR) INTEGER LOCAL_COMM, LOCAL_LEADER, PEER_COMM, REMOTE_LEADER, TAG, NEWINTERCOMM, IERROR

  28. Tworzenie intrakomunikatora z dwóch interkomunikatorów MPI_INTERCOMM_MERGE(intercomm, high, newintracomm) intercomm - interkomunikator high - kolejność procesorów w tworzonej grupie newintracomm - utworzony intrakomunikator MPI_Intercomm_merge(MPI_Comm intercomm, int high, MPI_Comm *newintracomm) Sprawdzanie, czy komunikator jest intra- czy interkomunikatorem MPI_COMM_TEST_INNER(comm, flag) comm - komunikator flag - flaga; true jeżeli komunikator jest interkomunikatorem MPI_Comm_test_inter(MPI_Comm comm, int *flag)

  29. Uzyskiwanie rozmiaru, rzędu procesora oraz grupy odpowiadającej „lokalnej” części interkomunikatora: MPI_COMM_RANK (comm, rank) MPI_COMM_SIZE (comm, size) MPI_COMM_GROUP (comm, group) Uzyskiwanie rozmiaru oraz grupy odpowiadającej „odległej” części interkomunikatora: MPI_COMM_REMOTE_SIZE (comm, size) MPI_COMM_REMOTE_GROUP (comm, group)

  30. Przykład: Symulacja układu ocean: atmosfera call MPI_COMM_SIZE( MPI_COMM_WORLD, nprocs, ierr ) call MPI_COMM_RANK( MPI_COMM_WORLD, rank, ierr ) if (rank .lt. Size/2 ) then color = OCEAN else color = ATMOS endif call MPI_COMM_SPLIT( MPI_COMM_WORLD, color, rank, ocean_or_atmos_comm, ierr) call MPI_INTERCOMM_CREATE( ocean_or_atoms_comm, 0, MPI_COMM_WORLD, 0, 0, intercomm, ierr) if (color .eq. OCEAN) then ocean_comm = ocean_or_atmos_comm call do_ocean( ocean_comm ) else atmos_comm = ocean_or_atmos_comm call do_atmos( atmos_comm ) endif call ocean_and_atmos( intercomm )

  31. Przykład bardziej konkretny: przepływ danych pomiędzy grupami procesorów („rura”) Grupę 12 procesorów dzielimy na 3 podgrupy po 4 procesory w każdej, jak na rysunku. Dane są wymieniane w obie strony pomiędzy grupami 0 i 1 oraz 1 i 2. W tym celu dla grup 0 i 2 musimy zdefiniować po jednym komunikatorze, natomiast dla grupy 1 musimy zdefiniować 2 interkomunikatory - odpowiednio do komunikacji z grupą 0 i 2.

  32. Źródło programu w C Wyniki (12 procesorów)