Come posso eseguire il debug di un programma MPI?


129

Ho un programma MPI che viene compilato ed eseguito, ma vorrei esaminarlo per accertarmi che non stia accadendo nulla di bizzarro. Idealmente, vorrei un modo semplice per collegare GDB a qualsiasi processo particolare, ma non sono davvero sicuro che sia possibile o come farlo. Un'alternativa sarebbe che ogni processo scriva l'output di debug in un file di registro separato, ma ciò non dà la stessa libertà di un debugger.

Ci sono approcci migliori? Come si esegue il debug dei programmi MPI?

Risposte:


62

Come ha detto qualcun altro, TotalView è lo standard per questo. Ma ti costerà un braccio e una gamba.

Il sito OpenMPI ha una grande FAQ sul debug MPI . L'articolo n. 6 nelle FAQ descrive come collegare GDB ai processi MPI. Leggi tutto, ci sono alcuni ottimi consigli.

Se trovi che hai troppi processi per tenere traccia, però, controlla Stack Trace Analysis Tool (STAT) . Lo utilizziamo su Livermore per raccogliere tracce di stack da potenzialmente centinaia di migliaia di processi in esecuzione e rappresentarli in modo intelligente per gli utenti. Non è un debugger con funzionalità complete (un debugger con funzionalità complete non ridimensionerebbe mai a 208k core), ma ti dirà quali gruppi di processi stanno facendo la stessa cosa. È quindi possibile scorrere un rappresentante di ciascun gruppo in un debugger standard.


14
A partire dal 2010 Allinea DDT è un debugger completo che si ridimensiona a oltre 208k core
Segna

1
Quindi andrò avanti e voterò la risposta di Mark qui. DDT è carino. Provalo anche tu. Anche TotalView ora si integra con STAT, quindi se il tuo sito ha un'installazione TotalView puoi provare anche quello. LLNL mantiene TotalView e DDT in giro, ed è bello che TotalView abbia finalmente una forte concorrenza.
Todd Gamblin,

Vorrei secondare il link alle FAQ sul debug di MPI ( open-mpi.org/faq/?category=debugging#serial-debuggers ). In particolare, il proiettile 6 è un modo buono, rapido e facile (abbastanza anche per me!) Di capire almeno il debug di un singolo processo.
Jeff,

I passaggi al numero 6 della pagina FAQ hanno funzionato in modo eccellente per me e mi hanno aiutato a capire il mio problema. Grazie mille per questo.
Jon Deaton,

86

Ho trovato gdb abbastanza utile. Lo uso come

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

Questo avvia Windows xterm in cui posso fare

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

di solito funziona bene

Puoi anche impacchettare questi comandi insieme usando:

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

Come posso inviare lo stesso input a tutti gli xterm NP gdb? Ad esempio, voglio aggiungere due punti di interruzione a ogni processo e ci sono 16 processi. C'è qualche alternativa a xterm per farlo? Possiamo collegare sessioni in un'unica istanza di schermo, tmux o Terminator di Chris Jones?
osgx,

@osgx Puoi farlo salvando i comandi ("break xxx", "break yyy", "run") <file>e passando -x <file>a gdb.
eush77,

ma riscontro un errore, il messaggio di errore è "errore execvp sul file xterm (nessun file o directory del genere)"
hitwlh,

quando provo questo con jdb e OpenMPI non funziona, cioè ogni istanza jdb vede num_ranks di 1 invece di ciò che viene dato all'argomento -np. qualche idea del perché?
Michel Müller,

26

Molti dei post qui riguardano GDB, ma non menzionano come collegarsi a un processo all'avvio. Ovviamente, puoi collegarti a tutti i processi:

mpiexec -n X gdb ./a.out

Ma questo è incredibilmente inefficace poiché dovrai rimbalzare per avviare tutti i tuoi processi. Se vuoi solo eseguire il debug di uno (o un piccolo numero di) processi MPI, puoi aggiungerlo come eseguibile separato sulla riga di comando usando l' :operatore:

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

Ora solo uno dei tuoi processi otterrà GDB.


Posso usare "mpiexec -n X gdb ./a.out", ma c'è un modo per usare la modalità gdb -tui?
Hitwlh,

16

Come altri hanno già detto, se stai lavorando solo con una manciata di processi MPI puoi provare a utilizzare più sessioni gdb , il ridimensionabile valgrind o roll la tua soluzione di stampa / registrazione.

Se stai utilizzando più processi di questo, inizi davvero a necessitare di un debugger adeguato. Le FAQ di OpenMPI raccomandano sia Allinea DDT che TotalView .

Lavoro su Allinea DDT . È un debugger grafico completo di codice sorgente, quindi sì, puoi:

  • Debug o collegamento a (oltre 200k) processi MPI
  • Passo e metterli in pausa in gruppi o individualmente
  • Aggiungi punti di interruzione, orologi e punti di traccia
  • Cattura errori e perdite di memoria

...e così via. Se hai usato Eclipse o Visual Studio, ti sentirai come a casa.

Abbiamo aggiunto alcune interessanti funzionalità specifiche per il debug del codice parallelo (sia esso MPI, multi-thread o CUDA):

  • Le variabili scalari vengono confrontate automaticamente tra tutti i processi: (fonte: allinea.com )Sparkline che mostrano valori attraverso i processi

  • Puoi anche tracciare e filtrare i valori di variabili ed espressioni nel corso di processi e tempi: I tracepoint registrano i valori nel tempo

È ampiamente utilizzato tra i primi 500 siti HPC, come ORNL , NCSA , LLNL , Jülich et. al.

L'interfaccia è piuttosto scattante; abbiamo cronometrato intensificando e unendo le pile e le variabili di 220.000 processi a 0,1 secondi come parte dei test di accettazione sul cluster Jaguar di Oak Ridge.

@tgamblin ha menzionato l'eccellente STAT , che si integra con Allinea DDT , così come molti altri popolari progetti open source.



7

Se sei un tmuxutente ti sentirai molto a tuo agio usando lo script di Benedikt Morbach :tmpi

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

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

Con esso hai più pannelli (numero di processi) tutti sincronizzati (ogni comando viene copiato su tutti i pannelli o sui processi contemporaneamente in modo da risparmiare molto tempo rispetto xterm -eall'approccio). Inoltre puoi conoscere i valori delle variabili nel processo che vuoi fare semplicemente printsenza spostarti su un altro pannello, questo stamperà su ogni pannello i valori della variabile per ogni processo.

Se non sei un tmuxutente, ti consiglio vivamente di provarlo e vedere.


2
Poiché tmpi è davvero fantastico ed è esattamente quello che stavo cercando, l'ho modificato sul mio account github: github.com/Azrael3000/tmpi da quando l'autore originale lo ha rimosso
Azrael3000,

6

http://github.com/jimktrains/pgdb/tree/master è un'utilità che ho scritto per fare proprio questa cosa. Ci sono alcuni documenti e sentiti libero di farmi domande.

Fondamentalmente si chiama un programma perl che avvolge GDB e incanala il suo IO su un server centrale. Ciò consente a GDB di essere in esecuzione su ciascun host e di accedervi su ciascun host sul terminale.


Grazie! Lo verificherò sicuramente la prossima volta che lavoro in MPI.
Jay Conrod,

5

L'uso screeninsieme gdbal debug delle applicazioni MPI funziona bene, specialmente se xtermnon è disponibile o hai a che fare con più processori. Ci sono state molte insidie ​​lungo la strada con ricerche di stackoverflow di accompagnamento, quindi riprodurrò la mia soluzione per intero.

Innanzitutto, aggiungi il codice dopo MPI_Init per stampare il PID e fermare il programma in attesa di collegarti. La soluzione standard sembra essere un ciclo infinito; Alla fine mi sono deciso raise(SIGSTOP);, il che richiede una chiamata extra continueper scappare all'interno di 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);
}

Dopo la compilazione, esegui l'eseguibile in background e prendi lo stderr. È quindi possibile grepil file stderr per alcune parole chiave (qui letterale PID) per ottenere il PID e il grado di ciascun 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`)

Una sessione gdb può essere collegata a ciascun processo con gdb $MDRUN_EXE $PID. Farlo all'interno di una sessione dello schermo consente un facile accesso a qualsiasi sessione gdb. -d -mavvia lo schermo in modalità staccata, -S "P$RANK"consente di denominare lo schermo per un facile accesso in un secondo momento, e l' -lopzione per bash lo avvia in modalità interattiva e impedisce a gdb di uscire immediatamente.

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 volta che gdb è stato avviato nelle schermate, è possibile inserire script nelle schermate (in modo da non dover accedere a tutte le schermate e digitare la stessa cosa) usando il -X stuffcomando screen . È richiesta una nuova riga alla fine del comando. Qui è possibile accedere alle schermate -S "P$i"utilizzando i nomi precedentemente indicati. L' -p 0opzione è fondamentale, altrimenti il ​​comando fallisce in modo intermittente (in base al fatto che sia stato precedentemente collegato allo schermo).

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

A questo punto puoi collegarti a qualsiasi schermo usando screen -rS "P$i"e staccare usando Ctrl+A+D. I comandi possono essere inviati a tutte le sessioni gdb in analogia con la precedente sezione di codice.


3

C'è anche il mio strumento open source, padb, che ha lo scopo di aiutare con la programmazione parallela. Lo chiamo "strumento di ispezione del lavoro" in quanto funziona non solo come un debugger può funzionare ad esempio come un programma parallelo simile a una cima. Esegui in modalità "Rapporto completo" ti mostrerà le tracce dello stack di ogni processo all'interno della tua applicazione insieme alle variabili locali per ogni funzione su ogni rango (supponendo che tu sia compilato con -g). Ti mostrerà anche le "code di messaggi MPI", ovvero l'elenco degli invii e delle ricezioni in sospeso per ogni posizione all'interno del lavoro.

Oltre a mostrare il rapporto completo è anche possibile dire a Padb di ingrandire i singoli bit di informazioni all'interno del lavoro, ci sono una miriade di opzioni e voci di configurazione per controllare quali informazioni vengono visualizzate, vedere la pagina Web per maggiori dettagli.

Padb


3

Il modo "standard" di eseguire il debug dei programmi MPI consiste nell'utilizzare un debugger che supporti quel modello di esecuzione.

Su UNIX, TotalView si dice che abbia una buona suppoort per MPI.


2

Uso questo piccolo metodo homebrewn per collegare il debugger ai processi MPI - chiama la seguente funzione, DebugWait (), subito dopo MPI_Init () nel tuo codice. Ora, mentre i processi sono in attesa di input da tastiera, hai tutto il tempo per collegare il debugger a loro e aggiungere punti di interruzione. Al termine, inserisci un carattere singolo e sei pronto per iniziare.

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);
}

Ovviamente si vorrebbe compilare questa funzione solo per build di debug.


MPI ha richiesto la maggior parte delle dichiarazioni di debug che abbia mai scritto per un codice anche semplice. (lol) Questo può essere molto utile.
Troggy,

3
Questa soluzione è simile al punto 6 qui ( open-mpi.org/faq/?category=debugging#serial-debuggers ). Puoi migliorare un po 'il tuo codice aggiungendo gethostname(hostname, sizeof(hostname)); printf("PID %d on host %s ready for attach\n", getpid(), hostname);. Quindi, ci si collega al processo digitando rsh <hostname_from_print_statement>e infine gdb --pid=<PID_from_print_statement>.
Jeff,

2

Il comando per collegare gdb a un processo mpi è incompleto, dovrebbe essere

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

Una breve discussione su mpi e gdb è disponibile qui


2

Abbastanza un modo semplice per eseguire il debug di un programma MPI.

Nella funzione main () aggiungi sleep (some_seconds)

Esegui il programma come al solito

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

Il programma inizierà e si addormenterà.

Quindi avrai qualche secondo per trovare i tuoi processi da ps, eseguire gdb e collegarti ad essi.

Se usi un editor come QtCreator puoi usarlo

Debug-> Avvia debug-> Collega all'applicazione in esecuzione

e trova i tuoi processi lì.


1

Eseguo il debug di MPI con tracce di log, ma puoi anche eseguire gdb se stai usando mpich2: MPICH2 e gdb . Questa tecnica è una buona pratica in generale quando si ha a che fare con un processo difficile da avviare da un debugger.


Modificato in un altro collegamento che non è interrotto, aggiunto un commento.
Jim Hunziker,


0

Un'altra soluzione è eseguire il codice all'interno di SMPI, l'MPI simulato. È un progetto open source in cui sono coinvolto. Ogni rango MPI verrà convertito in thread dello stesso processo UNIX. È quindi possibile utilizzare facilmente gdb per scalare le classifiche MPI.

SMPI offre altri vantaggi allo studio delle applicazioni MPI: chiaroveggenza (è possibile osservare tutte le parti del sistema), riproducibilità (diverse esecuzioni portano allo stesso identico comportamento a meno che non sia specificato), assenza di heisenbugs (poiché la piattaforma simulata è mantenuta diversa da quello host), ecc.

Per ulteriori informazioni, consultare questa presentazione o quella risposta correlata .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.