Jak debugować program MPI?

132

Mam program MPI, który się kompiluje i działa, ale chciałbym przejść przez niego, aby upewnić się, że nie dzieje się nic dziwnego. Idealnie chciałbym w prosty sposób dołączyć GDB do dowolnego konkretnego procesu, ale nie jestem do końca pewien, czy to możliwe i jak to zrobić. Alternatywą byłoby zapisanie danych debugowania przez każdy proces do oddzielnego pliku dziennika, ale tak naprawdę nie daje to takiej samej swobody jak debuger.

Czy są lepsze podejścia? Jak debuguje się programy MPI?

Jay Conrod
źródło

Odpowiedzi:

63

Jak ktoś powiedział, standardem jest TotalView . Ale będzie cię to kosztować rękę i nogę.

Witryna OpenMPI zawiera świetne FAQ dotyczące debugowania MPI . Punkt 6 w FAQ opisuje, jak dołączyć GDB do procesów MPI. Przeczytaj całość, jest kilka świetnych wskazówek.

Jeśli jednak okaże się, że masz zbyt wiele procesów, aby je śledzić, wypróbuj narzędzie Stack Trace Analysis Tool (STAT) . Używamy tego w Livermore do zbierania śladów stosu z potencjalnie setek tysięcy uruchomionych procesów i do inteligentnego przedstawiania ich użytkownikom. Nie jest to w pełni funkcjonalny debugger (w pełni funkcjonalny debugger nigdy nie skalowałby się do 208k rdzeni), ale powie Ci, które grupy procesów robią to samo. Następnie możesz przejść przez przedstawiciela z każdej grupy w standardowym debugerze.

Todd Gamblin
źródło
14
Od 2010 Allinea DDT to w pełni funkcjonalny debugger, który skaluje się do ponad 208 tys. Rdzeni
Mark
1
Więc pójdę dalej i zagłosuję tutaj za odpowiedzią @ Mark. DDT jest fajne. Wypróbuj też. TotalView integruje się teraz również ze STAT, więc jeśli Twoja witryna ma instalację TotalView, możesz również spróbować. LLNL utrzymuje TotalView i DDT i fajnie, że TotalView w końcu ma twardą konkurencję.
Todd Gamblin
Chciałbym dodać link do FAQ na temat debugowania MPI ( open-mpi.org/faq/?category=debugging#serial-debuggers ). W szczególności punktor 6 jest dobrym, szybkim i łatwym (wystarczającym nawet dla mnie!), Aby zrozumieć sposób przynajmniej na debugowanie pojedynczego procesu.
Jeff,
Kroki z punktu 6 strony z często zadawanymi pytaniami działały doskonale i pomogły mi rozwiązać problem. Wielkie dzięki za to.
Jon Deaton,
87

Uważam, że gdb jest całkiem przydatne. Używam go jako

mpirun -np <NP> xterm -e gdb ./program 

To uruchamia okna xterm, w których mogę to zrobić

run <arg1> <arg2> ... <argN>

zwykle działa dobrze

Możesz również spakować te polecenia razem, używając:

mpirun -n <NP> xterm -hold -e gdb -ex run --args ./program [arg1] [arg2] [...]
messenjah
źródło
Jak mogę wysłać to samo wejście do wszystkich xterms NP gdb? Na przykład chcę dodać dwa punkty przerwania do każdego procesu, a jest 16 procesów. Czy jest jakaś alternatywa dla xterm, aby to zrobić? Czy możemy połączyć sesje w jedną instancję screen, tmux lub Terminator Chrisa Jonesa?
osgx
@osgx Możesz to zrobić, zapisując polecenia („break xxx”, „break yyy”, „run”) do <file>i przekazując -x <file>do gdb.
eush77
ale napotykam błąd, komunikat o błędzie to „błąd execvp w pliku xterm (brak takiego pliku lub katalogu)”
hitwlh
kiedy próbuję tego z jdb i OpenMPI, to nie działa, tj. każda instancja jdb widzi num_ranks o wartości 1 zamiast tego, co jest podane argumentowi -np. jakiś pomysł, dlaczego?
Michel Müller
26

Wiele postów tutaj dotyczy GDB, ale nie wspomina się, jak dołączyć do procesu od uruchomienia. Oczywiście możesz dołączyć do wszystkich procesów:

mpiexec -n X gdb ./a.out

Ale to jest szalenie nieskuteczne, ponieważ będziesz musiał podskakiwać, aby uruchomić wszystkie swoje procesy. Jeśli chcesz tylko debugować jeden (lub niewielką liczbę) procesu MPI, możesz dodać go jako oddzielny plik wykonywalny w wierszu poleceń za pomocą :operatora:

mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out

Teraz tylko jeden z Twoich procesów otrzyma GDB.

Wesley Bland
źródło
Mogę użyć „mpiexec -n X gdb ./a.out”, ale czy istnieje sposób na użycie trybu gdb -tui?
hitwlh
16

Jak wspominali inni, jeśli pracujesz tylko z kilkoma procesami MPI, możesz spróbować użyć wielu sesji gdb , niewątpliwego valgrind lub uruchomić własne rozwiązanie printf / logging.

Jeśli używasz więcej procesów, naprawdę zaczynasz potrzebować odpowiedniego debuggera. OpenMPI FAQ zaleca zarówno Allinea DDT i TotalView .

Pracuję na Allinea DDT . Jest to w pełni funkcjonalny, graficzny debugger kodu źródłowego, więc tak, możesz:

  • Debuguj lub dołącz do (ponad 200 000) procesów MPI
  • Krocz i wstrzymuj je w grupach lub indywidualnie
  • Dodaj punkty przerwania, zegarki i punkty śledzenia
  • Wyłap błędy i wycieki pamięci

...i tak dalej. Jeśli korzystałeś z Eclipse lub Visual Studio, będziesz w domu.

Dodaliśmy kilka interesujących funkcji specjalnie do debugowania kodu równoległego (czy to MPI, wielowątkowość czy CUDA):

  • Zmienne skalarne są automatycznie porównywane we wszystkich procesach: (źródło: allinea.com )Wykresy przebiegu w czasie przedstawiające wartości z różnych procesów

  • Możesz także śledzić i filtrować wartości zmiennych i wyrażeń w zależności od procesów i czasu: Punkty śledzenia rejestrują wartości w czasie

Jest szeroko stosowany wśród 500 najlepszych witryn HPC, takich jak ORNL , NCSA , LLNL , Jülich et. glin.

Interfejs jest dość zgryźliwy; w ramach testów akceptacyjnych na klastrze Jaguar firmy Oak Ridge wyznaczyliśmy czas na stopniowanie i łączenie stosów i zmiennych 220 000 procesów z dokładnością do 0,1 sekundy.

@tgamblin wspomniał o znakomitym STAT , który integruje się z Allinea DDT , podobnie jak kilka innych popularnych projektów open source.

znak
źródło
7

Jeśli jesteś tmuxużytkownikiem, poczujesz się bardzo komfortowo korzystając ze skryptu Benedikta Morbacha :tmpi

Pierwotnym źródłem: https://github.com/moben/scripts/blob/master/tmpi

Widelec: https://github.com/Azrael3000/tmpi

Dzięki niemu masz wiele paneli (liczbę procesów), wszystkie zsynchronizowane (każde polecenie jest kopiowane na wszystkie panele lub procesy w tym samym czasie, dzięki czemu oszczędzasz dużo czasu w porównaniu z xterm -epodejściem). Co więcej, możesz znać wartości zmiennych w procesie, który chcesz wykonać, printbez konieczności przechodzenia do innego panelu, spowoduje to wydrukowanie na każdym panelu wartości zmiennej dla każdego procesu.

Jeśli nie jesteś tmuxużytkownikiem, zdecydowanie polecam spróbować i zobaczyć.

GG1991
źródło
2
Ponieważ tmpi jest naprawdę fantastyczne i dokładnie to, czego szukałem, rozwidliłem je na moim koncie github: github.com/Azrael3000/tmpi, ponieważ oryginalny autor usunął go
Azrael3000
6

http://github.com/jimktrains/pgdb/tree/master to narzędzie, które napisałem właśnie w tym celu. Jest kilku doktorów i zapraszam do wysyłania mi pytań.

Zasadniczo wywołujesz program w Perlu, który opakowuje GDB i kieruje jego IO do centralnego serwera. Dzięki temu GDB może działać na każdym hoście i mieć do niego dostęp na każdym hoście w terminalu.

Jim Keener
źródło
Dzięki! Na pewno to sprawdzę następnym razem, gdy będę pracował w MPI.
Jay Conrod
5

Używanie screenrazem z gdbdo debugowania aplikacji MPI działa dobrze, zwłaszcza jeśli xtermjest niedostępny lub masz do czynienia z więcej niż kilkoma procesorami. Po drodze było wiele pułapek związanych z wyszukiwaniem stosów, więc odtworzę moje rozwiązanie w całości.

Najpierw dodaj kod po MPI_Init, aby wydrukować PID i zatrzymaj program, aby czekał na dołączenie. Standardowe rozwiązanie wydaje się być nieskończoną pętlą; Ostatecznie zdecydowałem się na to raise(SIGSTOP);, co wymaga dodatkowego wezwania continuedo ucieczki w gdb.

}
    int i, id, nid;
    MPI_Comm_rank(MPI_COMM_WORLD,&id);
    MPI_Comm_size(MPI_COMM_WORLD,&nid);
    for (i=0; i<nid; i++) {
        MPI_Barrier(MPI_COMM_WORLD);
        if (i==id) {
            fprintf(stderr,"PID %d rank %d\n",getpid(),id);
        }
        MPI_Barrier(MPI_COMM_WORLD);
    }
    raise(SIGSTOP);
}

Po kompilacji uruchom plik wykonywalny w tle i przechwyć stderr. Możesz następnie grepplik stderr dla jakiegoś słowa kluczowego (tutaj dosłowny PID), aby uzyskać PID i pozycję każdego procesu.

MDRUN_EXE=../../Your/Path/To/bin/executable
MDRUN_ARG="-a arg1 -f file1 -e etc"

mpiexec -n 1 $MDRUN_EXE $MDRUN_ARG >> output 2>> error &

sleep 2

PIDFILE=pid.dat
grep PID error > $PIDFILE
PIDs=(`awk '{print $2}' $PIDFILE`)
RANKs=(`awk '{print $4}' $PIDFILE`)

Sesję gdb można dołączyć do każdego procesu z gdb $MDRUN_EXE $PID. Wykonanie tego w ramach sesji screen umożliwia łatwy dostęp do dowolnej sesji gdb. -d -muruchamia ekran w trybie odłączonym, -S "P$RANK"umożliwia nazwanie ekranu w celu późniejszego uzyskania łatwego dostępu, a -lopcja bash uruchamia go w trybie interaktywnym i zapobiega natychmiastowemu wyjściu gdb.

for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
    PID=${PIDs[$i]}
    RANK=${RANKs[$i]}
    screen -d -m -S "P$RANK" bash -l -c "gdb $MDRUN_EXE $PID"
done

Gdy gdb uruchomi się na ekranach, możesz skryptować wejście na ekrany (aby nie trzeba było wchodzić na każdy ekran i wpisywać tego samego) za pomocą -X stuffpolecenia screen . Na końcu polecenia wymagany jest znak nowej linii. Tutaj dostęp do ekranów odbywa się za -S "P$i"pomocą podanych wcześniej nazw. Ta -p 0opcja jest krytyczna, w przeciwnym razie polecenie sporadycznie kończy się niepowodzeniem (w zależności od tego, czy wcześniej byłeś podłączony do ekranu).

for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
    screen -S "P$i" -p 0 -X stuff "set logging file debug.$i.log
"
    screen -S "P$i" -p 0 -X stuff "set logging overwrite on
"
    screen -S "P$i" -p 0 -X stuff "set logging on
"
    screen -S "P$i" -p 0 -X stuff "source debug.init
"
done

W tym momencie możesz dołączyć do dowolnego ekranu za pomocą screen -rS "P$i"i odłączyć za pomocą Ctrl+A+D. Polecenia mogą być wysyłane do wszystkich sesji gdb analogicznie do poprzedniej sekcji kodu.

user3788566
źródło
3

Jest też moje narzędzie open source, padb, które ma na celu pomóc w programowaniu równoległym. Nazywam to „narzędziem inspekcji pracy”, ponieważ działa nie tylko jako debugger, ale może również funkcjonować na przykład jako równoległy program typu top. Uruchom w trybie "pełnego raportu", pokaże ci ślady każdego procesu w twojej aplikacji wraz ze zmiennymi lokalnymi dla każdej funkcji w każdej pozycji (zakładając, że skompilowałeś z -g). Pokazuje również "kolejki komunikatów MPI", czyli listę oczekujących wysyłek i odbiorów dla każdej pozycji w zadaniu.

Oprócz pokazania pełnego raportu, można również powiedzieć padb, aby przybliżył poszczególne fragmenty informacji w zadaniu, istnieje niezliczona liczba opcji i elementów konfiguracji, które kontrolują, jakie informacje są wyświetlane, więcej szczegółów można znaleźć na stronie internetowej.

Padb


źródło
3

„Standardowym” sposobem debugowania programów MPI jest użycie debugera, który obsługuje ten model wykonywania.

Mówi się, że w systemie UNIX TotalView zapewnia dobre wsparcie dla MPI.

Społeczność
źródło
2

Używam tej małej metody homebrewn do dołączania debuggera do procesów MPI - wywołaj następującą funkcję, DebugWait (), zaraz po MPI_Init () w twoim kodzie. Teraz, gdy procesy czekają na dane wejściowe z klawiatury, masz cały czas, aby dołączyć do nich debugger i dodać punkty przerwania. Kiedy skończysz, wprowadź pojedynczy znak i jesteś gotowy do pracy.

static void DebugWait(int rank) {
    char    a;

    if(rank == 0) {
        scanf("%c", &a);
        printf("%d: Starting now\n", rank);
    } 

    MPI_Bcast(&a, 1, MPI_BYTE, 0, MPI_COMM_WORLD);
    printf("%d: Starting now\n", rank);
}

Oczywiście chciałbyś skompilować tę funkcję tylko dla kompilacji debugowania.


źródło
MPI wymagało większości instrukcji debugowania, jakie kiedykolwiek napisałem, nawet dla prostego kodu. (lol) To może być bardzo pomocne.
Troggy,
3
To rozwiązanie jest podobne do punktu 6 tutaj ( open-mpi.org/faq/?category=debugging#serial-debuggers ). Możesz trochę ulepszyć swój kod, dodając gethostname(hostname, sizeof(hostname)); printf("PID %d on host %s ready for attach\n", getpid(), hostname);. Następnie dołączasz do procesu, wpisując rsh <hostname_from_print_statement>i na koniec gdb --pid=<PID_from_print_statement>.
Jeff,
2

Polecenie dołączenia gdb do procesu mpi jest niekompletne, a powinno

mpirun -np <NP> xterm -e gdb ./program 

Krótkie omówienie mpi i gdb można znaleźć tutaj

akintayo
źródło
2

Całkiem prosty sposób na debugowanie programu MPI.

W funkcji main () dodaj usypianie (some_seconds)

Uruchom program jak zwykle

$ mpirun -np <num_of_proc> <prog> <prog_args>

Program uruchomi się i wejdzie w sen.

Będziesz miał więc kilka sekund na znalezienie procesów przez ps, uruchomienie gdb i dołączenie do nich.

Jeśli używasz jakiegoś edytora, takiego jak QtCreator, możesz użyć

Debuguj-> Rozpocznij debugowanie-> Dołącz do uruchomionej aplikacji

i znajdź tam swoje procesy.

nieznajomy
źródło
1

Robię debugowanie związane z MPI ze śladami dziennika, ale możesz również uruchomić gdb, jeśli używasz mpich2: MPICH2 i gdb . Ta technika jest ogólnie dobrą praktyką, gdy masz do czynienia z procesem, którego uruchomienie z debuggera jest trudne.

Jim Hunziker
źródło
Zmieniono na inny link, który nie jest uszkodzony, dodano komentarz.
Jim Hunziker
0

Innym rozwiązaniem jest uruchomienie kodu w ramach SMPI, symulowanego MPI. To projekt open source, w który jestem zaangażowany. Każda ranga MPI zostanie przekonwertowana na wątki tego samego procesu UNIX. Następnie możesz łatwo użyć gdb do zmiany rang MPI.

SMPI proponuje inne zalety badania aplikacji MPI: jasnowidzenie (można obserwować każdą część systemu), odtwarzalność (kilka przebiegów prowadzi do dokładnie tego samego zachowania, chyba że tak określono), brak heisenbugs (ponieważ symulowana platforma jest inna od hosta) itp.

Aby uzyskać więcej informacji, zobacz tę prezentację lub odpowiednią odpowiedź .

Martin Quinson
źródło