2008-11-30 20 views
100

Tengo un programa MPI que compila y ejecuta, pero me gustaría revisarlo para asegurarme de que no ocurra nada extraño. Idealmente, me gustaría una forma simple de adjuntar GDB a cualquier proceso en particular, pero no estoy muy seguro de si eso es posible o cómo hacerlo. Una alternativa sería que cada proceso escriba la salida de depuración en un archivo de registro separado, pero esto realmente no da la misma libertad que un depurador.¿Cómo depuro un programa MPI?

¿Hay mejores enfoques? ¿Cómo se depuran los programas MPI?

Respuesta

48

Como dijo otra persona, TotalView es el estándar para esto. Pero te costará un brazo y una pierna.

El sitio OpenMPI tiene un gran FAQ on MPI debugging. El ítem # 6 en las preguntas frecuentes describe cómo adjuntar procesos de GDB a MPI. Lea todo, hay algunos buenos consejos.

Si encuentra que tiene demasiados procesos para realizar un seguimiento, consulte Stack Trace Analysis Tool (STAT). Usamos esto en Livermore para recopilar trazas de pila de potencialmente cientos de miles de procesos en ejecución y para representarlos inteligentemente a los usuarios. No es un depurador con todas las funciones (un depurador con todas las funciones nunca se escalaría a 208k núcleos), pero le dirá qué grupos de procesos están haciendo lo mismo. Luego puede pasar por un representante de cada grupo en un depurador estándar.

+10

A partir de 2010 [Allinea DDT] (http://www.olcf.ornl.gov/2010/07/12/upgrade-adds-muscle-to-debugger/) es un depurador con todas las funciones que escala a más de 208k núcleos – Mark

+0

Así que continuaré y votaré la respuesta de @ Mark aquí. DDT es bueno. Pruébalo también. TotalView también se integra con STAT ahora, por lo que si su sitio tiene una instalación de TotalView, puede probarlo también. LLNL mantiene TotalView y DDT, y es agradable que TotalView finalmente tenga una dura competencia. – tgamblin

+0

Me gustaría secundar el enlace a las preguntas frecuentes sobre la depuración de MPI (http://www.open-mpi.org/faq/?category=debugging#serial-debuggers). Específicamente, la viñeta 6 es una buena, rápida y fácil (¡incluso para mí!) Para comprender la forma de, al menos, depurar un proceso individual. – Jeff

3

La manera "estándar" de depurar programas MPI es mediante el uso de un depurador que admita ese modelo de ejecución.

En UNIX, se dice que TotalView tiene un buen soporte para MPI.

5

http://github.com/jimktrains/pgdb/tree/master es una utilidad que escribí para hacer esto mismo. Hay algunos documentos y no dude en llamarme para preguntas.

Básicamente se llama a un programa perl que envuelve GDB y canaliza su IO a un servidor central. Esto permite que GDB se ejecute en cada host y que pueda acceder a él en cada host en la terminal.

+0

¡Gracias! Definitivamente verifico esto la próxima vez que esté trabajando en MPI. –

1

Utilizo este pequeño método homebrewn para conectar el depurador a los procesos MPI: llame a la siguiente función, DebugWait(), justo después de MPI_Init() en su código. Ahora, mientras los procesos esperan la entrada del teclado, tiene todo el tiempo para adjuntar el depurador y agregar puntos de interrupción. Cuando haya terminado, proporcione una sola entrada de carácter y estará listo para comenzar.

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

Por supuesto, usted querrá compilar esta función solamente para compilaciones de depuración.

+0

MPI ha requerido la mayoría de las sentencias de depuración que he escrito, incluso para código simple. (lol) Esto puede ser muy útil. – Troggy

+2

Esta solución es similar a la viñeta 6 aquí (http://www.open-mpi.org/faq/?category=debugging#serial-debuggers). Puede mejorar su código un poco agregando 'gethostname (nombre de host, sizeof (nombre de host)); printf ("PID% d en el host% s listo para adjuntar \ n", getpid(), nombre de host); '. Luego, se conecta al proceso escribiendo 'rsh ', y finalmente 'gdb --pid = '. – Jeff

1

Realizo algunas depuraciones relacionadas con MPI con rastros de registro, pero también puede ejecutar gdb si está usando mpich2: MPICH2 and gdb. Esta técnica es una buena práctica en general cuando se trata de un proceso que es difícil de ejecutar desde un depurador.

+0

El enlace está roto. –

+0

Cambió a otro enlace que no está roto, agregó algunos comentarios. –

2

También existe mi herramienta de fuente abierta, padb, que tiene como objetivo ayudar con la programación paralela. Yo lo llamo una "Herramienta de Inspección de Trabajo" ya que funciona no solo como un depurador también puede funcionar, por ejemplo, como un programa paralelo similar. Ejecutar en el modo "Informe completo" le mostrará los rastros de pila de cada proceso dentro de su aplicación junto con las variables locales para cada función sobre cada rango (suponiendo que haya compilado con -g). También le mostrará las "colas de mensajes MPI", que es la lista de envíos pendientes y recibe para cada rango dentro del trabajo.

Además de mostrar el informe completo, también es posible indicarle a la barra de herramientas que amplíe bits de información dentro del trabajo, hay una gran cantidad de opciones y elementos de configuración para controlar qué información se muestra, consulte la página web para más detalles.

Padb

62

he encontrado bastante útil GDB. Yo lo uso como

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

Esto las ventanas lanzamientos xterm en el que yo puedo hacer

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

por lo general trabaja muy bien

También puede empaquetar estos comandos juntos usando:

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

¿Cómo puedo enviar la misma entrada a todos los NP gdb xterms? Por ejemplo, quiero agregar dos puntos de interrupción a cada proceso, y hay 16 procesos. ¿Hay alguna alternativa a xterm para hacer esto? ¿Podemos conectar sesiones en una sola instancia de pantalla, tmux o Terminator de Chris Jones? – osgx

+0

@osgx Puede hacerlo guardando los comandos ("break xxx", "break yyy", "run") en '' y pasando '-x ' a gdb. – eush77

+0

pero encuentro un error, el mensaje de error es "error execvp en el archivo xterm (No existe ese archivo o directorio)" – hitwlh

1

El comando para adjuntar gdb a un proceso de MPI es incompleta, debe ser

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

Un breve análisis de MPI y GDB se puede encontrar here

16

Como han mencionado otros, si solo está trabajando con un puñado de de procesos MPI, puede intentar usar multiple gdb sessions, el temible valgrind o rodar su propia solución printf/logging.

Si usa más procesos que eso, realmente necesita un depurador adecuado. El OpenMPI FAQ recomienda Allinea DDT y TotalView.

Yo trabajo en Allinea DDT. Es un depurador de código fuente con todas las funciones, gráfica así que sí, se puede:

  • depuración o adjuntar a (más de 200 k) MPI procesa
  • paso y hacer una pausa en grupos o individualmente
  • Añadir puntos de interrupción, relojes y Tracepoints
  • errores de memoria de capturas y fugas

... y así sucesivamente. Si has usado Eclipse o Visual Studio, entonces estarás en casa.

Hemos añadido algunas características interesantes específicamente para depurar código paralelo (ya sea MPI, multi-hilo o CUDA):

  • Las variables escalares se comparan de forma automática en todos los procesos: Sparklines showing values across processes

  • También puede rastrear y filtrar los valores de variables y expresiones sobre procesos y tiempo: Tracepoints log values over time

Es ampliamente utilizado entre top500 sitios HPC, tales como ORNL, NCSA, LLNL, Jülich et. Alabama.

La interfaz es bastante ágil; cronometramos el paso y la fusión de las pilas y variables de 220,000 procesos a 0.1s como parte de las pruebas de aceptación en el clúster Jaguar de Oak Ridge.

@tgamblin mencionó el excelente STAT, que se integra con Allinea DDT, al igual que muchos otros proyectos populares de código abierto.

17

Muchos de los puestos aquí son sobre BGF, pero no mencionan cómo adjuntar a un proceso desde el inicio. Obviamente, se puede conectar a todos los procesos:

mpiexec -n X gdb ./a.out 

pero que es tremendamente ineficaz, ya que tendrá que rebotar para poner en marcha todos sus procesos. Si lo que desea es eliminar errores de uno (o un pequeño número de) proceso de MPI, se puede añadir que como un ejecutable independiente en la línea de comandos utilizando el : operador:

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

Ahora sólo una de sus procesos conseguirán BGF .

+0

Puedo usar "mpiexec -n X gdb ./a.out", pero ¿hay alguna forma de usar el modo gdb -tui? – hitwlh

4

Usando screen junto con gdb para depurar aplicaciones MPI funciona muy bien, sobre todo si xterm no está disponible o que está tratando con más de un par de procesadores. Hubo muchas trampas en el camino con las búsquedas simultáneas de stackoverflow, así que reproduciré mi solución por completo.

Primero, agregue el código después de MPI_Init para imprimir el PID y detenga el programa para esperar que lo adjunte. La solución estándar parece ser un ciclo infinito; Finalmente me decidí por raise(SIGSTOP);, que requiere una llamada adicional de continue para escapar dentro de 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); 
} 

Después de compilar, ejecute el archivo ejecutable en segundo plano y capture el stderr. A continuación, puede grep el archivo stderr para alguna palabra clave (aquí PID literal) para obtener el PID y el rango de cada proceso.

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 sesión de GDB se puede unir a cada proceso con gdb $MDRUN_EXE $PID. Hacerlo dentro de una sesión de pantalla permite un fácil acceso a cualquier sesión de gdb.-d -m inicia la pantalla en modo separado, -S "P$RANK" le permite poner nombre a la pantalla para acceder fácilmente más tarde, y la opción -l de bash la inicia en modo interactivo y evita que gdb salga inmediatamente.

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 vez que el BGF ha comenzado en las pantallas, se puede introducir secuencia de comandos para las pantallas (de modo que usted no tiene que entrar en cada pantalla y escriba la misma cosa) con el comando de pantalla -X stuff. Se requiere una nueva línea al final del comando. Aquí se accede a las pantallas por -S "P$i" usando los nombres dados previamente. La opción -p 0 es crítica; de lo contrario, el comando falla de forma intermitente (en función de si previamente se ha adjuntado o no a la pantalla).

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 

En este punto se puede conectar a cualquier pantalla utilizando screen -rS "P$i" y separar usando Ctrl+A+D. Los comandos se pueden enviar a todas las sesiones de gdb en analogía con la sección de código anterior.

0

Otra solución es ejecutar su código dentro de SMPI, el MPI simulado. Ese es un proyecto de código abierto en el que estoy involucrado. Cada rango de MPI se convertirá en hilos del mismo proceso de UNIX. A continuación, puede usar gdb fácilmente para avanzar en los rangos de MPI.

SMPI propone otras ventajas para el estudio de aplicaciones MPI: clairevoyance (puede observar todas las partes del sistema), reproducibilidad (varias ejecuciones conducen a exactamente el mismo comportamiento a menos que usted lo especifique), ausencia de heisenbugs (como el simulado la plataforma se mantiene diferente de la del host), etc.

Para obtener más información, vea this presentation o related answer.

0

Si usted es un usuario tmux se sentirá muy cómodo con el script de Benedikt Morbach: tmpi

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

Con él se tienen múltiples paneles (número de procesos) todo ello sincronizado (todos los comandos se copia en todos los paneles o procesos al mismo tiempo, por lo que ahorrará mucho tiempo comparando con el enfoque xterm -e). Además puede conocer los valores de las variables en el proceso que desea simplemente haciendo un print sin tener que moverse a otro panel, esto imprimirá en cada panel los valores de la variable para cada proceso.

Si no eres un usuario de tmux, recomiendo encarecidamente probarlo y ver.

Cuestiones relacionadas