示例1:MPI应用并行调试
本示例主要是演示如何使用鲲鹏编译调试工具的HPC并行应用调试功能,调试MPI应用,帮助用户基于该工具快速实现并行调试。
- 请从Github获取待使用的MPI程序源文件bcast_demo.c。
下载的源码包为devkitdemo-devkitdemo-23.0.1.zip,解压后“Compiler_and_Debugger/mpi_demo/”路径下的bcast_demo.c作为MPI程序源文件,编译时mpicc编译命令后面加-g,生成带调试信息的可执行文件。
mpicc -g bcast_demo.c -o bcast_demo
- 进入到鲲鹏DevKit插件,单击“开发”按钮,在编译调试区域单击“调试”,打开调试页面。图1 选择调试
- 选择“HPC并行应用”,配置MPI应用调试参数,参数说明如表1所示。图2 配置MPI应用调试参数
表1 HPC并行应用调试参数说明 参数
说明
远程服务器配置
进行HPC并行应用调试的目标服务器。
Linux用户名
输入启动MPI应用的Linux用户名称。
说明:root用户拥有最高权限,为了避免给系统带来不必要的风险,建议使用非root用户进行调试。
Linux用户密码
使用的Linux用户密码。
SSH端口
输入启动MPI应用的服务器SSH端口号。
应用程序
输入的MPI应用,支持动态检索并显示应用程序路径。
请给Linux用户添加当前MPI应用的可读权限以及应用所在目录的可读、可写和可执行权限。说明:- MPI应用要为可执行文件。
- 若MPI应用中无源码信息,则调试器默认以汇编形式进行调试。
应用程序参数(可选)
传递给应用程序运行的参数。
请给Linux用户添加应用程序所在目录的可读、可写、可执行权限及应用程序所在目录父目录的可执行权限。
应用程序源码路径
源码和MPI应用存放的共享路径,支持动态检索并显示应用程序源码路径。
- 若MPI应用已配置共享路径,源码与MPI应用都应存放在共享路径下。
- 请给Linux用户添加当前MPI应用源码路径的可读、可执行权限及源码文件所在目录父目录的可执行权限。
环境变量设置(可选)
输入运行HPC并行应用所需要的环境变量,有以下3种方式可选择,可根据实际情况进行修改。
- export PATH=$PATH:/path/to/mpi
- source /configure/mpi/path/file
- module load/mpi/modulefiles
调试启动方式
调试启动方式可选:
- mpirun命令运行方式
- 多瑙调度器运行方式
- Slurm调度器运行方式
说明:mpirun命令运行方式使用mpirun运行命令,mpirun是一个重要的工具,用作启动MPI并行应用程序,并提供进程之间的通信和清理工作等功能。
多瑙调度器是华为全自研的HPC集群调度器,提供大规模集群下的高资源利用率、高吞吐量的作业调度能力。
Slurm是一个开源的、高度可定制的、可扩展的、高性能的作业调度系统,它能够很好地提供资源管理和任务调度功能,广泛用于高性能计算、集群计算领域,如物理、化学、生物学、天文学等领域。
MPI运行命令行
输入的mpirun命令以及对应的命令参数,rank数目为1~2048。
多瑙调度器运行命令行
输入的多瑙调度器命令以及对应的命令参数。
Slurm调度器运行命令行
输入的Slurm调度器命令以及对应的命令参数
OpenMP应用(可选)
勾选后,需要输入OpenMP线程数。
OpenMP线程数(可选)
输入的OpenMP应用thread数量。
死锁检测(可选)
勾选后,需要输入死锁超时时间。
死锁超时时间(s)(可选)
死锁超时时间,默认为10秒,取值范围10~60。
- 参数填写完成后,单击“开始调试”,若右下角提示权限问题,如图3所示,请执行以下命令解决。
chmod 700 -R 目录名称/
- 再次单击“开始调试”,启动HPC并行应用调试并读取rank状态。图4 启动HPC并行应用调试
图5 读取rank状态
- 在rank状态读取过程中,若rank状态读取全部成功,会自动跳转到MPI应用调试页面。页面上获取到运行和调试区、源码区和调试功能区,运行和调试区域包括调试信息区和rank信息区,如图6所示。
- HPC并行应用调试支持三种调试粒度,分别为“全部”调试、“rank”调试或“通信组”调试。图7 选择调试方式
表2 调试粒度说明 调试方式
效果
全部
在RANK信息区域选择“全部”方式进行调试,选择某一个rank,对其进行调试会应用到全部rank。
rank
在RANK信息区域选择“rank”方式进行调试,对单一rank进行调试。
通信组
在RANK信息区域选择“通信组”方式进行调试,选择通信组中的某一个rank,对其进行调试会应用到整个通信组。
- 可以单击调试功能区的操作按钮来调试MPI应用。
表3 调试按钮操作描述 操作
操作描述
继续
点击执行到下一个断点
暂停
点击中断正在执行的程序
单步跳过
点击执行到下一行
单步调试
点击步入函数
单步跳出
点击步出函数
重启
点击后重新启动调试
停止
点击后停止调试
- RANK信息区域选择“全部”调试方式,在89行代码处、47行代码处和93行代码处打上断点,再继续执行后续操作。
- 选择“全部”调试方式,单击“继续”按钮,代码执行到89行,再单击“下一步”执行MPI_Comm_split(MPI_COMM_WORLD, color, rankNum, &row_comm)函数,该函数可将所有的rank进行通信分组。这里将4个rank生成2个通信子组,rank0、rank1在通信子组1,rank2、rank3在通信子组2。图8 生成2个通信子组
MPI_Comm_split(MPI_COMM_WORLD, color, rankNum, &row_comm)是一个用于创建新的通信子组的函数。
- 第一个参数MPI_COMM_WORLD是通信组,在这个函数中,原始的通信组并没有消失,但是在每个进程中都会创建一个新的通信组;
- 第二个参数color确定每个rank将属于哪个新的通信子组;
- 第三个参数rankNum确定每个新通信组中的顺序(秩),传递rankNum最小值的进程将为0,下一个最小值将为1,以此类推;
- 第四个参数row_comm是MPI如何将新的通信子组返回给用户。
- 生成2个通信子组后,所有rank的源码执行到90行代码处,选择“通信组”调试方式,选择通信子组1中的rank0,单击“下一步”按钮,通信子组1中的所有rank代码执行到92行,通信子组2中的rank代码无变化,停留在90行。图9 调试通信子组1
图10 未调试通信子组2
- 选择“通信组”调试方式,在左侧通信子组1中选择rank0,单击“继续”按钮,代码执行到47行,单击“下一步”按钮,执行MPI_Barrier(MPI_COMM_WORLD)函数,函数执行完成后,通信子组1会一直处于等待状态,此时,在左侧通信子组2中选择rank2,单击“继续”按钮,代码执行到47行,单击“下一步”按钮,执行MPI_Barrier(MPI_COMM_WORLD)函数,函数执行完成后,通信子组1不再等待,同步执行到49行代码处。图11 执行屏障函数
- MPI_Barrier(MPI_COMM_WORLD)函数,该函数是一个屏障函数,屏障域为MPI_COMM_WORLD,用于一个通信组中所有rank的同步,调用函数时rank将处于等待状态,直到通信子组中的所有rank都调用了该函数后才能继续执行。
- 当通信子组1执行到MPI_Barrier函数时,由于采用的是“通信组”方式调试,通信子组2不会同步执行MPI_Barrier函数,通信子组1执行完函数后会一直处于等待状态,只有当通信子组2也执行MPI_Barrier函数后,通信子组1等待才会结束。
- 单击“”按钮,在VS Code面板中能看到通信子组的变化概览,每100ms显示通信子组的变化。通信子组的变化用不同颜色的菱形来区分,蓝色表示通信子组创建,紫色表示通信子组清除,黄色表示100ms内存在通信子组创建和通信子组清除。图12 查看通信子组变化概览
若调试过程中若检测到死锁,会在通信子组变化面板页面提示通信组发生死锁,单击“查看详情”或“死锁”,显示死锁详细信息,如死锁状态图以及表格信息。表格展示rank、源进程(rank)、目标进程(rank)、标记、数据大小(byte)和调用栈信息。
- 选择“全部”调试方式,单击“继续”按钮,代码执行到93行,在单击“下一步”按钮,执行MPI_Comm_free(&row_comm)函数,当用户不再调试某一通信子组时,可以释放创建的通信子组,该函数能实现释放创建的通信子组。图13 释放通信子组
- 在左侧调试区域查看调试信息。图14 查看调试信息