gdb xterm 调试 openmpi 程序
1,编写编译一个openmpi程序
迭代计算 PI 的源程序:
pi_reduce.c
#include <stdio.h>#include <math.h>
#include <mpi.h>double f(double);
double f(double x)
{return (4.0/(1.0+x*x));
}int main(int argc, char* argv[])
{int done =0, n, myid, numprocs, i;double PI25DT = 3.141592653589793238462643;// a more accurate PIdouble mypi, pi, h, sum, x;double startwtime = 0.0, endwtime;int namelen;char processor_name[MPI_MAX_PROCESSOR_NAME];//[256] openmpi-4.xMPI_Init(&argc, &argv);//& & mutiple processes below:MPI_Comm_size(MPI_COMM_WORLD, &numprocs);// total number of processesMPI_Comm_rank(MPI_COMM_WORLD, &myid);// which process I amMPI_Get_processor_name(processor_name, &namelen);// host name and its lenthfprintf(stdout, "Process %d of %d on %s\n", myid, numprocs, processor_name);n = 0;if(myid == 0){fprintf(stdout, "Please give N=\n");fflush(stdout);scanf("%d",&n);fprintf(stdout, "n = %d\n", n);//n= 1000000;startwtime = MPI_Wtime();}//MPI_Barrier(MPI_COMM_WORLD);//MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);// broadcast n to others//MPI_Bcast在默认情况下是阻塞调用,它会等待所有进程完成归约操作后才会继续执行。你可以使用非阻塞版本的MPI_Ireduce来进行非阻塞调用h = 1.0/(double)n;sum = 0.0;for(i=myid+1; i<=n; i+=numprocs)// each process would calculate several area of rectangles{// n proces, N rectangle// proc 1-st: 1, n+1, 2n+1, ..., N1; N1 is as big as possible, and N1<=N;// proc 2-nd: 2, n+2, 2n+2, ..., N2; N2 is as big as possible, and N2<=N;// ...// proc n-th: n, n+n, 2n+n, ..., Nn; Nn is as big as possible, and Nn<=N;x = h *((double)i - 0.5);// x of this timesum += f(x);
// fprintf(stdout, "Process %d of %d on %s, n=%d, mypi=%.6f, x=%7.3f, h=%7.3f, sum=%7.3f\n", myid, numprocs, processor_name, n, mypi, x, h, sum);}
// fflush(stdout);mypi = h * sum;//fprintf(stdout, "Process %d of %d on %s, n=%d, mypi=%.16f\n", myid, numprocs, processor_name, n, mypi);//fflush(stdout);//int MPI_Reduce(void* sendbuf, void* recvbuf, int count, PI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);//MPI_Reduce在默认情况下是阻塞调用,它会等待所有进程完成归约操作后才会继续执行。你可以使用非阻塞版本的MPI_Ireduce来进行非阻塞调用//MPI_Barrier(MPI_COMM_WORLD);if(myid == 0){endwtime = MPI_Wtime();printf("wall clock time = %f\n", endwtime -startwtime);printf("pi is approximately %.16f, Error is %.16f\n", pi, fabs(pi - PI25DT));fflush(stdout);}MPI_Finalize();return 0;
}
release 构建的 Makefile:
#FORT := ../local/bin/mpif77
FORT := gfortran
LD_F_FLAGS := -lgfortran -L../local/lib/ -lmpi_mpifhEXE := pi_reduceCC := ../../local/bin/mpicxxall: $(EXE)%: %.c$(CC) $< -o $@.PHONY: clean
clean:-rm -rf $(EXE)
注意命令起头的 tab 键;
运行:
$ mpiexec -np 1 ./pi_reduce
输入7,逼近次数
运行效果:
2, 调试 mpi 程序
加个 -g即可 做 debug 构建的Makefile:
#FORT := ../local/bin/mpif77
FORT := gfortran
LD_F_FLAGS := -lgfortran -L../local/lib/ -lmpi_mpifhEXE := pi_reduceCC := ../../local/bin/mpicxxall: $(EXE)%: %.c$(CC) -g $< -o $@.PHONY: clean
clean:-rm -rf $(EXE)
2.1 直接使用gdb 调试
$ mpiexec -np 1 gdb pi_reduce
2.2 使用网上介绍的 xterm 方法
这需要运行在图形用户界面上
安装xterm
sudo apt install xterm
调试时需要图形用户界面的参与,
$ mpiexec -np 1 xterm -e gdb ./pi_reduce
使用mpirun替代 mpiexec 也可以;
效果图:
进入 xterm 窗口,即可使用 gdb 命令进行调试
3, openmpi with-ucx 参数解析
运行 hpc 程序 app_mpi_hpc 时,使用如下参数“,其中 编译 openmpi 时,使用了 with-ucx :
mpiexec -np 1 --mca pml ucx --mca btl ^vader,tcp,openib,uct --map-by node --rank-by node --bind-to none ./app_mpi_hpc
mpiexec -np 1 --mca pml ucx --mca btl ^vader,tcp,openib,uct --map-by node --rank-by node --bind-to none ./app_mpi_hpc
其中命令行参数的作用是什么
这个命令行包含了多个 OpenMPI 和 UCX(Unified Communication X)相关的参数。这里稍微逐一解析这些参数的作用:
1. mpiexec -np 1:
启动一个 MPI 进程。
--mca pml ucx:
使用 UCX 作为点对点管理层(PML, Point-to-Point Management Layer)。
UCX 是一个高性能网络通信框架。
--mca btl ^vader,tcp,openib,uct:
排除 vader(共享内存)、tcp、openib 和 uct 作为字节传输层(BTL, Byte Transfer Layer)。
^ 符号表示排除列出的 BTL 组件。
留下了IB网络,rdma,PCIe,cuda-nvlink 等传输形式
--map-by node:
将进程映射到节点级别,而不是核心或插槽级别。
--rank-by node:
按节点对进程进行排序。
--bind-to none:
不将进程绑定到特定的 CPU 核心或套接字。
./app_mpi_hpc:
要执行的应用程序。
这个命令的整体目的是:
使用 UCX 作为通信框架。
排除某些特定的传输层。
在节点级别管理进程分布。
不限制进程到特定的 CPU 资源。
这种配置通常用于:
在高性能计算环境中优化通信。
测试特定的网络配置或通信库(在这里是 UCX)。
允许进程在节点内自由移动,可能是为了性能测试或特定的负载均衡需求。
需要注意的是,使用 --bind-to none 可能会影响性能,因为它允许操作系统自由地在 CPU 核心之间移动进程,这可能会导致缓存失效。在生产环境中,通常会选择更具体的绑定策略来优化性能。