Использование screen
вместе с gdb
для отладки приложений MPI прекрасно работает, особенно если xterm
недоступен или вы имеете дело с несколькими процессорами. Было много подводных камней, сопровождающих поиск стекового потока, поэтому я полностью воспроизведу свое решение.
Сначала добавьте код после MPI_Init, чтобы распечатать PID, и остановите программу, чтобы дождаться, пока вы присоединитесь. Стандартным решением кажется бесконечный цикл; В конце концов я остановился на raise(SIGSTOP);
, что требует дополнительного вызова continue
для выхода из 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);
}
После компиляции запустите исполняемый файл в фоновом режиме и перехватите stderr. Затем вы можете grep
файл stderr для некоторого ключевого слова (здесь буквальный PID), чтобы получить PID и ранг каждого процесса.
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`)
Сессия gdb может быть присоединена к каждому процессу с помощью gdb $MDRUN_EXE $PID
. Выполнение этого во время сеанса экрана обеспечивает легкий доступ к любому сеансу GDB. -d -m
запускает экран в отдельном режиме, -S "P$RANK"
позволяет вам дать имя экрану для быстрого доступа позже, а опция -l
для bash запускает его в интерактивном режиме и предотвращает немедленный выход 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
Как только GDB запустился на экранах, вы можете записать ввод данных на экран (чтобы вам не приходилось вводить каждый экран и вводить одно и то же) с помощью команды -X stuff
экрана. В конце команды требуется новая строка. Здесь экраны доступны по -S "P$i"
с использованием ранее указанных имен. Параметр -p 0
является критическим, в противном случае команда периодически завершается ошибкой (в зависимости от того, подключены ли вы ранее к экрану или нет).
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
На этом этапе вы можете подключиться к любому экрану с помощью screen -rS "P$i"
и отсоединить с помощью Ctrl+A+D
. Команды могут быть отправлены всем сеансам GDB по аналогии с предыдущим разделом кода.