O uso em screenconjunto com gdbpara depurar aplicativos MPI funciona bem, especialmente se xtermnã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 continuepara 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 grepo 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 -minicia a tela no modo desanexado, -S "P$RANK"permite que você nomeie a tela para facilitar o acesso posteriormente, e a -lopçã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 stuffcomando 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 0opçã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.