Comment déboguer un programme MPI?

J’ai un programme MPI qui comstack et s’exécute, mais je voudrais le passer en revue pour m’assurer que rien n’est bizarre. Idéalement, je voudrais un moyen simple d’attacher GDB à un processus particulier, mais je ne suis pas vraiment sûr que ce soit possible ou comment le faire. Une alternative serait que chaque processus écrive la sortie de débogage dans un fichier journal distinct, mais cela ne donne pas vraiment la même liberté qu’un débogueur.

Y a-t-il de meilleures approches? Comment déboguez-vous les programmes MPI?

Comme quelqu’un d’autre l’a dit, TotalView est la norme pour cela. Mais cela vous coûtera un arm et une jambe.

Le site OpenMPI a une excellente FAQ sur le débogage MPI . L’élément n ° 6 de la FAQ décrit comment attacher GDB aux processus MPI. Lisez le tout, il y a de bons conseils.

Si vous constatez que vous avez trop de processus à suivre, consultez l’ outil STAT (Stack Trace Analysis Tool) . Nous l’utilisons chez Livermore pour collecter des traces de stack parmi des centaines de milliers de processus en cours d’exécution et les représenter intelligemment aux utilisateurs. Ce n’est pas un débogueur complet (un débogueur complet ne serait jamais compatible avec 208 ko), mais il vous dira quels groupes de processus font la même chose. Vous pouvez ensuite parcourir un représentant de chaque groupe dans un débogueur standard.

J’ai trouvé gdb très utile. Je l’utilise comme

mpirun -np  xterm -e gdb ./program 

Ceci lance les fenêtres xterm dans lesquelles je peux faire

 run   ...  

fonctionne généralement bien

Vous pouvez également regrouper ces commandes en utilisant:

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

La plupart des articles ici concernent GDB, mais ne mentionnent pas comment attacher un processus au démarrage. De toute évidence, vous pouvez attacher à tous les processus:

 mpiexec -n X gdb ./a.out 

Mais cela est extrêmement inefficace car vous devrez rebondir pour lancer tous vos processus. Si vous souhaitez simplement déboguer un (ou un petit nombre) de processus MPI, vous pouvez l’append en tant qu’exécutable distinct sur la ligne de commande à l’aide de l’opérateur:

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

Désormais, un seul de vos processus recevra GDB.

Comme d’autres l’ont mentionné, si vous travaillez uniquement avec une poignée de processus MPI, vous pouvez essayer d’utiliser plusieurs sessions gdb , le redoutable valgrind ou lancer votre propre solution printf / logging.

Si vous utilisez plus de processus que cela, vous avez vraiment besoin d’un débogueur approprié. La FAQ OpenMPI recommande à la fois Allinea DDT et TotalView .

Je travaille sur Allinea DDT . C’est un débogueur de code source complet, donc oui, vous pouvez:

  • Déboguer ou attacher à (plus de 200k) processus MPI
  • Les étape et les mettre en pause en groupes ou individuellement
  • Ajouter des points d’arrêt, des montres et des traces
  • Détecter les erreurs de mémoire et les fuites

…etc. Si vous avez utilisé Eclipse ou Visual Studio, vous serez chez vous.

Nous avons ajouté des fonctionnalités intéressantes spécifiquement pour le débogage du code parallèle (que ce soit MPI, multi-thread ou CUDA):

  • Les variables scalaires sont automatiquement comparées dans tous les processus: Sparklines montrant les valeurs à travers les processus

  • Vous pouvez également suivre et filtrer les valeurs des variables et des expressions sur les processus et l’heure: Les points de trace enregistrent les valeurs au fil du temps

Il est largement utilisé parmi les 500 meilleurs sites de HPC, tels que ORNL , NCSA , LLNL , Jülich et. Al.

L’interface est plutôt rapide. Dans le cadre des tests d’acceptation du cluster Jaguar d’Oak Ridge, nous avons synchronisé les stacks et les variables de 220 000 processus à 0,1 seconde.

@tgamblin a mentionné l’excellent STAT , qui s’intègre à Allinea DDT , tout comme plusieurs autres projets open source populaires.

http://valgrind.org/ nuf dit


Lien plus spécifique: Débogage des programmes parallèles MPI avec Valgrind

http://github.com/jimktrains/pgdb/tree/master est un utilitaire que j’ai écrit pour faire cela. Il y a des documents et n’hésitez pas à me contacter pour des questions.

En gros, vous appelez un programme Perl qui encapsule GDB et canalise son IO vers un serveur central. Cela permet à GDB d’être exécuté sur chaque hôte et de pouvoir y accéder sur chaque hôte du terminal.

L’utilisation de screen avec gdb pour déboguer les applications MPI fonctionne parfaitement, surtout si xterm n’est pas disponible ou si vous traitez avec plus de quelques processeurs. Il y a eu beaucoup de pièges avec les recherches de stackoverflow, donc je vais reproduire intégralement ma solution.

Tout d’abord, ajoutez le code après MPI_Init pour imprimer le PID et arrêter le programme pour attendre que vous vous connectiez. La solution standard semble être une boucle infinie. J’ai finalement opté pour une raise(SIGSTOP); , ce qui nécessite un appel supplémentaire de continue à s’échapper dans gdb.

 } int i, id, nid; MPI_Comm_rank(MPI_COMM_WORLD,&id); MPI_Comm_size(MPI_COMM_WORLD,&nid); for (i=0; i 

Après la compilation, exécutez l'exécutable en arrière-plan et attrapez le fichier stderr. Vous pouvez ensuite grep le fichier stderr pour un mot-clé (ici le PID littéral) pour obtenir le PID et le rang de chaque processus.

 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`) 

Une session gdb peut être attachée à chaque processus avec gdb $MDRUN_EXE $PID . Faire cela dans une session d'écran permet un access facile à n'importe quelle session gdb. -d -m lance l'écran en mode détaché, -S "P$RANK" vous permet de nommer l'écran pour un access facile plus tard, et l'option -l pour bash le démarre en mode interactif et empêche gdb de quitter immédiatement.

 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 

Une fois que gdb a démarré dans les écrans, vous pouvez écrire un script sur les écrans (afin de ne pas avoir à entrer dans chaque écran et à taper la même chose) en utilisant la commande -X stuff écran. Une nouvelle ligne est requirejse à la fin de la commande. Ici, les écrans sont accessibles par -S "P$i" utilisant les noms donnés précédemment. L'option -p 0 est critique, sinon la commande échoue par intermittence (selon que vous avez ou non déjà connecté à l'écran).

 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 

À ce stade, vous pouvez attacher à n'importe quel écran en utilisant screen -rS "P$i" et détacher en utilisant Ctrl+A+D Les commandes peuvent être envoyées à toutes les sessions gdb par analogie avec la section précédente du code.

Le moyen “standard” de déboguer les programmes MPI consiste à utiliser un débogueur qui prend en charge ce modèle d’exécution.

Sous UNIX, TotalView est réputé avoir un bon support pour MPI.

J’utilise cette petite méthode homebrewn pour attacher le débogueur aux processus MPI – appelez la fonction suivante, DebugWait (), juste après MPI_Init () dans votre code. Maintenant que les processus attendent une saisie au clavier, vous avez tout le temps de leur associer le débogueur et d’append des points d’arrêt. Lorsque vous avez terminé, fournissez une entrée de caractère unique et vous êtes prêt à partir.

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

Bien sûr, vous ne voudriez comstackr cette fonction que pour les versions de débogage.

Il y a aussi mon outil open-source, padb, qui vise à aider avec la programmation parallèle. Je l’appelle un “outil d’inspection de travail” car il fonctionne non seulement comme un débogueur peut également fonctionner par exemple comme un programme parallèle à la forme supérieure. Exécuté en mode “Rapport complet”, il vous montrera des traces de chaque processus de votre application ainsi que des variables locales pour chaque fonction sur chaque rang (en supposant que vous ayez compilé avec -g). Il vous montrera également les “files d’attente de messages MPI”, c’est-à-dire la liste des envois et des réceptions en attente pour chaque rang dans le travail.

En plus d’afficher le rapport complet, il est également possible d’indiquer à padb de zoomer sur des bits individuels d’informations dans le travail, il existe une multitude d’options et d’éléments de configuration pour contrôler les informations affichées.

Padb

Si vous êtes un utilisateur de tmux vous vous sentirez très à l’aise avec le script de Benedikt Morbach : tmpi

Source primaire: https://github.com/moben/scripts/blob/master/tmpi

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

Avec lui, vous avez plusieurs panneaux (nombre de processus) tous synchronisés (chaque commande est copiée sur tous les panneaux ou processus en même temps, ce qui vous permet de gagner beaucoup de temps en comparant avec l’approche xterm -e ). De plus, vous pouvez connaître les valeurs des variables dans le processus que vous souhaitez simplement effectuer une print sans avoir à passer à un autre panneau, cela imprimera sur chaque panneau les valeurs de la variable pour chaque processus.

Si vous n’êtes pas un utilisateur de tmux je vous recommande fortement de l’essayer et de voir.

La commande pour attacher gdb à un processus mpi est incomplète, elle devrait être

 mpirun -np  xterm -e gdb ./program 

Une brève discussion sur mpi et gdb peut être trouvée ici

Je fais du débogage MPI avec des traces de journal, mais vous pouvez aussi lancer gdb si vous utilisez mpich2: MPICH2 et gdb . Cette technique est une bonne pratique en général lorsque vous avez affaire à un processus difficile à lancer depuis un débogueur.

Une autre solution consiste à exécuter votre code dans SMPI, le MPI simulé. C’est un projet open source dans lequel je suis impliqué. Chaque classement MPI sera converti en threads du même processus UNIX. Vous pouvez alors facilement utiliser gdb pour escalader les classements MPI.

SMPI propose d’autres avantages pour l’étude des applications MPI: clairevoyance (on peut observer toutes les parties du système), reproductibilité (plusieurs exécutions conduisent exactement au même comportement sauf spécification), absence de heisenbugs (la plateforme simulée est maintenue différente) de l’hôte), etc.

Pour plus d’informations, consultez cette présentation ou la réponse correspondante .

Un moyen assez simple de déboguer un programme MPI.

Dans la fonction main (), ajoutez sleep (some_seconds)

Exécutez le programme comme d’habitude

 $ mpirun -np    

Le programme va commencer et entrer dans le sumil.

Donc, vous aurez quelques secondes pour trouver vos processus par ps, lancez gdb et attachez-leur.

Si vous utilisez un éditeur comme QtCreator, vous pouvez utiliser

Debug-> Démarrer le débogage-> Attacher à l’application en cours d’exécution

et trouvez-vous des processus là-bas.