Pergunta

Eu tenho um programa MPI que compila e executa, mas eu gostaria de passo por ele para ter certeza que nada bizarro está acontecendo. Idealmente, eu gostaria de uma maneira simples para anexar GDB a qualquer processo particular, mas eu realmente não estou certo se isso é possível ou como fazê-lo. Uma alternativa seria ter cada depuração saída do processo de gravação para um arquivo de log separado, mas isso realmente não dá a mesma liberdade como um depurador.

Existem melhores abordagens? Como você depurar programas MPI?

Foi útil?

Solução

Como alguém disse, TotalView é o padrão para isso. Mas vai custar-lhe um braço e uma perna.

O site OpenMPI tem uma grande FAQ sobre MPI depuração . Item # 6 na FAQ descreve como anexar GDB para processos MPI. Leia a coisa toda, existem algumas ótimas dicas.

Se você achar que você tem demasiados processos para acompanhar, no entanto, consulte a Stack Ferramenta de Análise de Traços (STAT) . Nós usamos isso em Livermore para coletar rastreamentos de pilha de potencialmente centenas de milhares de processos em execução e para representá-los de forma inteligente para os usuários. Não é um depurador full-featured (um depurador full-featured nunca iria escalar para 208K cores), mas ele vai dizer que grupos de processos estão fazendo a mesma coisa. Você pode, então, passo através de um representante de cada grupo em um depurador padrão.

Outras dicas

Eu encontrei gdb bastante útil. Eu usá-lo como

mpirun -np <NP> xterm -e gdb ./program 

Este as janelas lançamentos xterm em que eu posso fazer

run <arg1> <arg2> ... <argN>

geralmente funciona bem

Você também pode empacotar esses comandos em conjunto, utilizando:

mpirun -n <NP> xterm -hold -e gdb -ex run --args ./program [arg1] [arg2] [...]

Muitos dos posts aqui são sobre GDB, mas não mencionam como anexar a um processo de inicialização. Obviamente, você pode anexar a todos os processos:

mpiexec -n X gdb ./a.out

Mas isso é descontroladamente ineficaz uma vez que você tem que saltar de volta para iniciar todos os seus processos. Se você quer apenas a uma depuração (ou um pequeno número de) processo MPI, você pode adicionar isso como um executável separado na linha de comando usando o operador ::

mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out

Agora, apenas um de seus processos terá GDB.

Como já foi mencionado, se você estiver trabalhando apenas com um punhado de MPI processos que você pode tentar usar várias sessões GDB , o temível valgrind ou rolar o seu próprio / solução registrando printf.

Se você estiver usando mais processos do que isso, você realmente começar a precisar de um depurador apropriado. A OpenMPI FAQ recomenda tanto Allinea DDT e TotalView .

Eu trabalho em Allinea DDT . É um depurador de código-fonte completo, gráfica então sim, você pode:

  • Debug ou anexar a (mais de 200k) processos MPI
  • Passo e pausa-los em grupos ou individualmente
  • adicionar pontos de interrupção, relógios e tracepoints
  • erros de memória de captura e vazamentos

... e assim por diante. Se você já usou Eclipse ou Visual Studio, então você estará em casa.

Nós adicionamos algumas características interessantes especificamente para depuração paralelo código (seja ele MPI, multi-threaded ou CUDA):

  • As variáveis ??escalares são automaticamente comparadas em todos os processos: Sparklines apresentando valores entre processos

  • Você também pode rastrear e filtrar os valores das variáveis ??e expressões sobre processos e tempo: TracePoints valores ao longo do tempo log

É amplamente utilizado entre os TOP500 locais HPC, como ORNL , NCSA , LLNL , Jülich et. al.

A interface é bastante mal-humorado; nós programado pisar e fundindo as pilhas e variáveis ??de 220.000 processos em 0.1s como parte do teste de aceitação em conjunto Jaguar de Oak Ridge.

@tgamblin mencionou a excelente STAT , que se integra com Allinea DDT , assim como vários outros projetos de código aberto populares.

http://github.com/jimktrains/pgdb/tree/master é um utilitário que eu escrevi para fazer isso mesmo. Existem alguns documentos e fique à vontade para pm me para perguntas.

Você basicamente chamar um programa perl que envolve GDB e funis-lo de IO a um servidor central. Isso permite que o GDB para ser executado em cada host e para que você possa acessá-lo em cada host no terminal.

Usando screen juntamente com gdb para depurar aplicativos MPI funciona muito bem, especialmente se xterm não está disponível ou você está lidando com mais do que alguns processadores. Havia muitas armadilhas ao longo do caminho com acompanhamento de pesquisas stackoverflow, por isso vou reproduzir minha solução na íntegra.

Em primeiro lugar, o código add após MPI_Init para imprimir o PID e interromper o programa para esperar por você para anexar. A solução padrão parece ser um circuito infinito; I finalmente a acordo sobre raise(SIGSTOP);, o que requer uma chamada extra de continue para escapar dentro 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);
}

Depois de compilar, executar o executável no fundo, e pegar o stderr. Você pode então grep o arquivo stderr para algumas palavras-chave (PID aqui literal) para obter o PID e 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 ligado a cada processo com gdb $MDRUN_EXE $PID. Ao fazê-lo dentro de uma sessão de tela permite fácil acesso a qualquer sessão gdb. -d -m começa a tela em modo individual, -S "P$RANK" permite nomear a tela para facilitar o acesso mais tarde, e a opção -l a festa começa-lo no modo interativo e mantém gdb de sair 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 gdb começou nas telas, você pode entrada de script para as telas (para que você não tem que entrar em cada tela e digite a mesma coisa) usando o comando -X stuff da tela. Uma nova linha é necessário no fim do comando. Aqui as telas são acessados ??por -S "P$i" usando os nomes anteriormente dadas. A opção -p 0 é fundamental, caso contrário, o comando de forma intermitente falhar (com base em se ou não tiver anteriormente ligado a 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 anexar a qualquer tela usando screen -rS "P$i" e retire usando Ctrl+A+D. Os comandos podem ser enviados para todas as sessões GDB em analogia com a secção anterior de código.

Se você é um usuário tmux você vai se sentir muito confortável usando o script de Benedikt Morbach : tmpi

Fonte original: https://github.com/moben/scripts / blob / master / tmpi

Fork: https://github.com/Azrael3000/tmpi

Com ele você tem vários painéis (Número de processos) todos sincronizados (cada comando é copiado em todos os painéis ou processos ao mesmo tempo para que você economizar muito tempo comparando com a abordagem xterm -e). Além disso, você pode conhecer as variáveis ??valores no processo que deseja apenas fazendo um print sem ter que se deslocar para outro painel, este será impresso em cada painel os valores da variável para cada processo.

Se você não for um usuário tmux Eu recomendo fortemente para tentar e ver.

A forma "padrão" para programas MPI depuração é usando um depurador que suporta esse modelo de execução.

No UNIX, TotalView é dito ter boa suppoort para MPI.

Eu uso este método homebrewn pouco para anexar depurador a processos MPI - chamar a seguinte função, DebugWait (), logo após MPI_Init () em seu código. Agora, enquanto os processos estão à espera para a entrada de teclado, você tem todo o tempo para anexar o depurador a eles e adicionar pontos de interrupção. Quando você é feito, dar um contributo único personagem e você está pronto para ir.

static void DebugWait(int rank) {
    char    a;

    if(rank == 0) {
        scanf("%c", &a);
        printf("%d: Starting now\n", rank);
    } 

    MPI_Bcast(&a, 1, MPI_BYTE, 0, MPI_COMM_WORLD);
    printf("%d: Starting now\n", rank);
}

Claro que você iria querer compilar esta função para compilações de depuração somente.

Há também a minha ferramenta de código aberto, padb, que visa ajudar com programação paralela. Eu chamo-a "Ferramenta de Inspeção de Trabalho", como ele funciona não só como um depurador também pode funcionar, por exemplo, como um top paralela como programa. Executar no modo "Relatório completo" vai mostrar-lhe empilhar traços de cada processo dentro de sua aplicação, juntamente com as variáveis ??locais para cada função sobre cada rank (supondo que você compilado com -g). Ele também vai mostrar-lhe os "MPI filas de mensagens", que é a lista de pendentes envia e recebe para cada posição dentro do trabalho.

Além de mostrar o relatório completo também é possível dizer padb para fazer zoom e pedaços individuais de informação dentro do trabalho, há uma infinidade de opções e itens de configuração para controlar o que informação é mostrada, consulte a página web para mais detalhes.

Padb

O comando para anexar gdb a um processo MPI é incompleta, deve ser

mpirun -np <NP> xterm -e gdb ./program 

Uma breve discussão da MPI e gdb pode ser encontrada aqui

Eu faço alguma depuração MPI-relacionada com vestígios de log, mas você também pode executar gdb se você estiver usando MPICH2: MPICH2 e gdb . Esta técnica é uma boa prática, em geral, quando você está lidando com um processo que é complicado para o lançamento de um depurador.

Muito uma maneira simples para depurar um programa MPI.

Em main () sono função add (some_seconds)

Executar o programa como de costume

$ mpirun -np <num_of_proc> <prog> <prog_args>

Programa será iniciado e entrar no sono.

Então você terá alguns segundos para encontrar você processa por ps, gdb executar e anexar a eles.

Se você usar algum editor como QtCreator você pode usar

Debug-> Iniciar debugging-> Anexar para execução da aplicação

e achar que você processa lá.

Outra solução é executar o seu código dentro SMPI, o MPI simulado. Isso é um projeto open source no qual estou envolvido. Todas as classes MPI serão convertidos em fios do mesmo processo UNIX. Você pode então usar o gdb para o passo das fileiras MPI.

SMPI propõe outras vantagens para o estudo de aplicações MPI: clairevoyance (você pode observar todas as partes do sistema), reprodutibilidade (várias corridas levar a exatamente o mesmo comportamento, a menos que você especifique de modo), ausência de heisenbugs (como a plataforma simulada é mantida diferente do host), etc.

Para obter mais informações, consulte esta apresentação , ou que relacionada resposta .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top