El uso screen
junto con la gdb
depuración de aplicaciones MPI funciona bien, especialmente si xterm
no está disponible o si se trata de más de unos pocos procesadores. Hubo muchos escollos en el camino con las búsquedas de stackoverflow que lo acompañan, por lo que reproduciré mi solución en su totalidad.
Primero, agregue código después de MPI_Init para imprimir el PID y detenga el programa para esperar a que lo adjunte. La solución estándar parece ser un bucle infinito; Finalmente me decidí raise(SIGSTOP);
, lo que requiere una llamada adicional continue
para escapar dentro de 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);
}
Después de compilar, ejecute el ejecutable en segundo plano y capture el stderr. Luego puede grep
usar el archivo stderr para alguna palabra clave (aquí PID literal) para obtener el PID y el rango de cada proceso.
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`)
Se puede adjuntar una sesión gdb a cada proceso con gdb $MDRUN_EXE $PID
. Hacerlo dentro de una sesión de pantalla permite un fácil acceso a cualquier sesión de gdb. -d -m
inicia la pantalla en modo separado, le -S "P$RANK"
permite asignarle un nombre a la pantalla para acceder fácilmente más tarde, y la -l
opción de bash la inicia en modo interactivo y evita que gdb salga de inmediato.
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
Una vez que gdb ha comenzado en las pantallas, puede ingresar la secuencia de comandos en las pantallas (para que no tenga que ingresar a todas las pantallas y escribir lo mismo) usando el -X stuff
comando de pantalla . Se requiere una nueva línea al final del comando. Aquí se accede a las pantallas -S "P$i"
utilizando los nombres dados previamente. La -p 0
opción es crítica, de lo contrario, el comando falla intermitentemente (en función de si se ha conectado o no previamente a la pantalla).
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
En este punto, puede adjuntarlo a cualquier pantalla usando screen -rS "P$i"
y desconectar usando Ctrl+A+D
. Se pueden enviar comandos a todas las sesiones de gdb en analogía con la sección de código anterior.