O uso em screen
conjunto com gdb
para depurar aplicativos MPI funciona bem, especialmente se xterm
não estiver disponível ou você estiver lidando com mais do que alguns processadores. Houve muitas armadilhas ao longo do caminho nas pesquisas de fluxo de pilha que acompanham, portanto, reproduzirei minha solução por completo.
Primeiro, adicione o código após MPI_Init para imprimir o PID e interrompa o programa para aguardar a conexão. A solução padrão parece ser um loop infinito; Acabei decidindo raise(SIGSTOP);
, o que requer uma chamada extra continue
para escapar dentro do 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);
}
Após a compilação, execute o executável em segundo plano e pegue o stderr. Você pode então grep
o arquivo stderr para alguma palavra-chave (aqui literal PID) para obter o PID e a classificação de cada processo.
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`)
Uma sessão gdb pode ser anexada a cada processo com gdb $MDRUN_EXE $PID
. Fazer isso em uma sessão de tela permite fácil acesso a qualquer sessão de GDB. -d -m
inicia a tela no modo desanexado, -S "P$RANK"
permite que você nomeie a tela para facilitar o acesso posteriormente, e a -l
opção bash a inicia no modo interativo e evita que o gdb saia imediatamente.
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
Uma vez iniciado o gdb nas telas, você pode inserir a entrada de scripts nas telas (para que você não precise entrar em todas as telas e digitar a mesma coisa) usando o -X stuff
comando da tela . Uma nova linha é necessária no final do comando. Aqui as telas são acessadas -S "P$i"
usando os nomes dados anteriormente. A -p 0
opção é crítica, caso contrário, o comando falhará de forma intermitente (com base no fato de você estar ou não conectado anteriormente à tela).
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
Neste ponto, você pode conectar a qualquer tela usando screen -rS "P$i"
e desconectando usando Ctrl+A+D
. Os comandos podem ser enviados para todas as sessões gdb em analogia com a seção anterior do código.