Używanie screen
razem z gdb
do debugowania aplikacji MPI działa dobrze, zwłaszcza jeśli xterm
jest 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 continue
do 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 grep
plik 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 -m
uruchamia ekran w trybie odłączonym, -S "P$RANK"
umożliwia nazwanie ekranu w celu późniejszego uzyskania łatwego dostępu, a -l
opcja 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 stuff
polecenia 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 0
opcja 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.