Debugging 如何调试MPI程序?

Debugging 如何调试MPI程序?,debugging,mpi,Debugging,Mpi,我有一个可以编译和运行的MPI程序,但我想一步一步地完成它,以确保没有什么奇怪的事情发生。理想情况下,我希望有一种简单的方法将GDB附加到任何特定的进程,但我不确定这是否可行或如何实现。另一种方法是让每个进程将调试输出写入一个单独的日志文件,但这并没有真正提供与调试器相同的自由度 有更好的方法吗?如何调试MPI程序?调试MPI程序的“标准”方法是使用支持该执行模型的调试器 在UNIX上,据说对MPI有很好的支持。正如其他人所说,是这方面的标准。但这要花你一大笔钱 OpenMPI站点有一个很好的应

我有一个可以编译和运行的MPI程序,但我想一步一步地完成它,以确保没有什么奇怪的事情发生。理想情况下,我希望有一种简单的方法将GDB附加到任何特定的进程,但我不确定这是否可行或如何实现。另一种方法是让每个进程将调试输出写入一个单独的日志文件,但这并没有真正提供与调试器相同的自由度

有更好的方法吗?如何调试MPI程序?

调试MPI程序的“标准”方法是使用支持该执行模型的调试器

在UNIX上,据说对MPI有很好的支持。

正如其他人所说,是这方面的标准。但这要花你一大笔钱

OpenMPI站点有一个很好的应用程序。FAQ中的第6项描述了如何将GDB附加到MPI进程。阅读全文,这里有一些很棒的提示

但是,如果您发现要跟踪的流程太多,请查看。我们在利弗莫尔使用它来收集可能数十万个正在运行的进程的堆栈跟踪,并智能地向用户表示它们。它不是一个功能齐全的调试器(功能齐全的调试器永远不会扩展到208k内核),但它会告诉您哪些进程组正在做相同的事情。然后,您可以在标准调试器中单步遍历每个组中的一个代表。

是我编写的一个实用程序,用于执行此操作。有一些文件,请随时pm我的问题


基本上,您可以调用一个perl程序来包装GDB,并将其IO导入中央服务器。这允许GDB在每个主机上运行,并允许您在终端的每个主机上访问它。

我使用这个小小的homebrewn方法将调试器附加到MPI进程-在代码中的MPI_Init()之后调用以下函数DebugWait()。现在,当进程等待键盘输入时,您可以随时将调试器附加到它们并添加断点。完成后,只需输入一个字符即可开始

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

当然,您只希望为调试版本编译此函数

我使用日志跟踪进行了一些与MPI相关的调试,但是如果您使用的是mpich2:,也可以运行gdb。在处理从调试器启动的过程时,这种技术通常是一种很好的做法。

还有我的开源工具padb,它旨在帮助进行并行编程。我称之为“作业检查工具”,因为它不仅可以用作调试器,还可以用作类似于并行top的程序。在“完整报告”模式下运行,它将显示应用程序中每个进程的堆栈跟踪,以及每个列组上每个函数的局部变量(假设使用-g编译)。它还将向您显示“MPI消息队列”,即作业中每个列组的未完成发送和接收的列表

除了显示完整的报告,还可以告诉padb放大作业中的单个信息位,有无数的选项和配置项来控制显示的信息,有关详细信息,请参阅网页


我发现gdb非常有用。我把它当作

mpirun -np <NP> xterm -e gdb ./program 
mpirun-npxterm-egdb./program
这将启动xterm窗口,我可以在其中执行以下操作

run <arg1> <arg2> ... <argN>
运行。。。
通常效果很好

还可以使用以下方法将这些命令打包在一起:

mpirun -n <NP> xterm -hold -e gdb -ex run --args ./program [arg1] [arg2] [...]
mpirun-nxterm-hold-egdb-exrun--args./program[arg1][arg2][…]
努夫说



更具体的链接:

将gdb附加到mpi进程的命令不完整,应该是

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

可以找到mpi和gdb的简要讨论,如其他人所述,如果您只使用少数mpi进程,您可以尝试使用双倍或滚动您自己的printf/日志解决方案

如果您使用的进程比这多,那么您就真的开始需要一个合适的调试器了。建议同时使用和

我在工作。它是一个功能齐全的图形化源代码调试器,因此您可以:

  • 调试或附加到(超过200k个)MPI进程
  • 分组或单独进行步骤和暂停
  • 添加断点、监视和跟踪点
  • 捕获内存错误和泄漏
……等等。如果您使用过Eclipse或Visual Studio,那么您就可以在家了

我们专门为调试并行代码添加了一些有趣的功能(可以是MPI、多线程或CUDA):

  • 标量变量会在所有进程中自动进行比较:
    (来源:)

  • 您还可以跟踪和过滤变量和表达式随进程和时间变化的值:

它广泛应用于高性能混凝土现场,如、、等

界面非常简洁;作为橡树岭捷豹集群验收测试的一部分,我们以0.1秒的速度对220000个流程的堆栈和变量进行了定时步进和合并


@tgamblin提到了优秀的,它与其他几个流行的开源项目集成在一起。

mpirun-gdb


多亏了()

这里的许多帖子都是关于GDB的,但是没有提到如何从启动时就附加到进程。显然,您可以附加到所有进程:

mpiexec -n X gdb ./a.out
但是,这是非常无效的,因为你必须跳转来启动你的所有流程。如果只想调试一个(或少量)MPI进程,可以使用
操作符在命令行上将其作为单独的可执行文件添加:

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

现在,只有一个进程将获得GDB。

使用
屏幕
GDB
来调试MPI应用程序,特别是当
xterm
不可用或者您处理的处理器不止几个时。在与斯塔科夫同行的过程中,有许多陷阱
}
    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);
}
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`)
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
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
$ mpirun -np <num_of_proc> <prog> <prog_args>