1 NVSHMEM简介
1.1 基本介绍
NVSHMEM 是 NVIDIA 提供的一个并行编程库,专门用于在 GPU 集群或多 GPU 系统中实现高效的共享内存访问。它通过使用共享内存来实现 GPU 间的数据通信,适合大规模并行计算应用,尤其是那些需要在多个 GPU 之间快速交换数据的场景。
1.2 关键特点
1. 一对多通信模型:NVSHMEM 提供了一种 “一对多” 的编程模型,使得一个线程可以直接访问和操作其他线程的数据。这种模型基于 SHMEM(共享内存)标准,并扩展到了多 GPU 环境。
2. 全局地址空间:NVSHMEM 允许多个 GPU 共享一个全局的地址空间,用户可以在多个 GPU 之间读写数据,而不需要显式的消息传递操作。
3. 高效的 GPU 间通信:NVSHMEM 使用 GPU 之间的高带宽互联(如 NVLink、InfiniBand)来实现数据的快速传输。相比传统的 CPU 主导的通信方式,它消除了 CPU 的干预,使得 GPU 间通信更加高效。
4. 同步原语:NVSHMEM 提供了多种同步原语,包括屏障(barriers)和锁(locks),方便开发者在并行计算中协调 GPU 之间的操作。
5. 易于集成:NVSHMEM 可以与其他 NVIDIA 的并行计算库(如 CUDA、NCCL 等)结合使用,提升多 GPU 应用程序的性能。
1.3 NVSHMEM 和 NCCL
总体来说,NVSHMEM较轻量级,适合小规模的不规则复杂通信;NCCL较重量级,适合大规模的规则通信。
2 NVSHMEM安装
实验环境
操作系统:CentOS7
CPU:Gold5218 32核 v5@2.3GHz CPU内存:192GB
GPU:4 * NVIDIA®Tesla®V100 GPU显存:4 * 32G (897 GB/s)
节点内互连:NVLink 双向通信300 GB/s
节点间互连:100G InfiniBand
- 由于是在服务器环境中且无管理员权限,只能安装并添加路径到用户目录下。
- 若有其他问题,所有步骤参考官方文档!!!
1 下载nvshmem v3.0.6和nccl的压缩包,放在 ~/dat01/soft/
文件夹中。
2 首先安装NCCL:(若有管理员权限,直接 sudo yum install nccl
即可)
# 解压文件
[soft]$ unzip nccl-master.zip
[soft]$ rm nccl-master.zip
[soft]$ cd nccl-master
# 安装nccl前必须安装/加载cuda
[soft]$ module load nvidia/cuda/12.2
# 编译并安装至 ~/dat01/soft/nccl
[nccl-master]$ make -j src.build CUDA_HOME=/software/nvidia/cuda/12.2 BUILDDIR=~/dat01/soft/nccl
# 安装完成,删除安装包
[nvshmem]$ cd ..
[soft]$ rm -rf nccl-master
# 配置环境变量
[nccl-master]$ export NCCL_HOME=~/dat01/soft/nccl
[nccl-master]$ export LD_LIBRARY_PATH=$NCCL_HOME/lib:$LD_LIBRARY_PATH
3 然后安装NVSHMEM:
# 解压到当前文件夹并移除压缩包
[soft]$ tar -xvf nvshmem_src_3.0.6-4.txz
[soft]$ rm nvshmem_src_3.0.6-4.txz
# 进入安装包并配置环境
[soft]$ cd nvshmem_src_3.0.6-4/
# 必选,必须加载cuda并设置CUDA_HOME
[nvshmem_src_3.0.6-4]$ module load nvidia/cuda/12.2
[nvshmem_src_3.0.6-4]$ export CUDA_HOME=/software/nvidia/cuda/12.2
# 可选,加载mpi并设置MPI_HOME
[nvshmem_src_3.0.6-4]$ module load openmpi/4.1.0_IB_gcc9.3
[nvshmem_src_3.0.6-4]$ export MPI_HOME=/software/openmpi/4.1.0_IB_gcc9.3
# 可选,安装nccl并设置NCCL_HOME
[nvshmem_src_3.0.6-4]$ export NCCL_HOME=~/dat01/soft/nccl
# 编译及安装,安装路径为 '~/dat01/soft/nvshmem'
[nvshmem_src_3.0.6-4]$ cmake -D NVSHMEM_USE_GDRCOPY=0 -D NVSHMEM_MPI_SUPPORT=1 -D NVSHMEM_USE_NCCL=1 -D NVSHMEM_DEFAULT_PMIX=1 -D NVSHMEM_PREFIX=~/dat01/soft/nvshmem -S . -B ./build
[nvshmem_src_3.0.6-4]$ cd ./build
[nvshmem]$ make -j install
# 安装完成,删除安装包
[nvshmem]$ cd ../..
[soft]$ rm -rf nvshmem_src_3.0.6-4
配置说明:
- NVSHMEM_USE_GDRCOPY=0 仅支持节点内通信。若要支持跨节点通信,需设置GDRCOPY_HOME,并让NVSHMEM_USE_GDRCOPY=1即可。
- NVSHMEM_MPI_SUPPORT=1 支持了NVSHMEM与MPI的集成。也可以选择SHMEM集成。
- NVSHMEM_USE_NCCL=1 支持了NVSHMEM与NCCL的集成。
- NVSHMEM_DEFAULT_PMIX=1 使用PMIX作为默认的bootstrap,同时支持mpirun和slurm两种方式启动nvshmem程序。
现在NVSHMEM已经成功安装到 ~/dat01/soft/nvshmem
文件夹中。
4 准备测试代码 test.cu
:
#include <stdio.h>
#include <cuda.h>
#include "nvshmem.h"
#include "nvshmemx.h"
#include "mpi.h"
__global__ void simple_shift(int *destination) {
int mype = nvshmem_my_pe();
int npes = nvshmem_n_pes();
int peer = (mype + 1) % npes;
nvshmem_int_p(destination, mype, peer);
}
int main(void) {
int mype_node, msg;
cudaStream_t stream;
nvshmem_init();
mype_node = nvshmem_team_my_pe(NVSHMEMX_TEAM_NODE);
cudaSetDevice(mype_node);
cudaStreamCreate(&stream);
int *destination = (int *) nvshmem_malloc(sizeof(int));
simple_shift<<<1, 1, 0, stream>>>(destination);
nvshmemx_barrier_all_on_stream(stream);
cudaMemcpyAsync(&msg, destination, sizeof(int), cudaMemcpyDeviceToHost, stream);
cudaStreamSynchronize(stream);
printf("Total %d PEs.\n", nvshmem_n_pes());
printf("%d: received message %d\n", nvshmem_my_pe(), msg);
nvshmem_free(destination);
nvshmem_finalize();
return 0;
}
由于安装在用户空间,在运行nvshmem程序前需手动添加路径,这里我采用slurm脚本运行程序:
#!/bin/bash
#SBATCH -N 1
#SBATCH --ntasks-per-node=4
#SBATCH --gres=gpu:4
# 加载cuda和mpi
module load nvidia/cuda/12.2
module load openmpi/4.1.0_IB_gcc9.3
# 分别配置nvshmem, mpi, cuda, nccl的路径
export NVSHMEM_HOME=$HOME/dat01/soft/nvshmem
export MPI_HOME=/software/openmpi/4.1.0_IB_gcc9.3
export CUDA_HOME=/software/nvidia/cuda/12.2
export NCCL_HOME=$HOME/dat01/soft/nccl
# 将nvshmem, mpi, nccl的头文件和库文件都添加到路径中
export CPATH=$CPATH:$NVSHMEM_HOME/include:$MPI_HOME/include:$NCCL_HOME/include
export LIBRARY_PATH=$LIBRARY_PATH:$NVSHMEM_HOME/lib:$MPI_HOME/lib:$NCCL_HOME/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$NVSHMEM_HOME/lib:$MPI_HOME/lib:$NCCL_HOME/lib
# 配置编译的其他参数
export NVCC_GENCODE="arch=compute_70,code=sm_70"
export NVSHMEM_MPI_SUPPORT=1
export NVSHMEM_USE_NCCL=1
# 编译执行
nvcc -rdc=true -ccbin g++ -gencode=$NVCC_GENCODE test.cu -o test.out -lnvshmem_host -lnvshmem_device -lmpi
srun ./test.out
rm ./test.out
5 slurm提交脚本程序作业:
$ sbatch -p gpu -n 4 -N 1 --gres=gpu:4 run.sh
若运行成功,则NVSHMEM安装成功。默认只能在节点内通信。
3 NVSHMEM代码结构及常用API解析
NVSHMEM所使用的API都可以在官网上查到。
3.1 API
nvshmem_init()
:初始化 NVSHMEM 环境。
nvshmem_malloc()
:分配对称共享内存。
nvshmem_free()
:释放共享内存。
nvshmem_put()
:远程写入数据到其他 GPU。
nvshmem_get()
:从其他 GPU 读取数据。
nvshmem_barrier_all()
:全局同步,确保所有处理单元都到达同步点。