第1章:环境搭建——NVSHMEM的安装与配置
说实话,NVSHMEM的环境搭建,是我见过最容易被低估的环节。很多人觉得不就是装个库嘛,结果一搞就是半天。我当年第一次配的时候,光编译器版本就折腾了两个小时。嗯,今天咱们就把这事彻底捋清楚。
1.1 硬件与软件的前置条件
先看看你的机器够不够格。NVSHMEM说白了是跑在NVIDIA GPU上的,所以硬件上有硬门槛。
| 组件 | 最低要求 | 我推荐 |
|---|---|---|
| GPU | Kepler架构及以上 | Volta或Ampere(V100/A100) |
| CUDA Toolkit | 10.2 | 11.4+ |
| GPU数量 | 至少2块 | 4块以上(单边通信才有效果) |
| 操作系统 | Linux x86_64 | Ubuntu 20.04 / CentOS 7 |
| 网络 | InfiniBand或RoCE | Mellanox ConnectX-5以上 |
你想想看,如果只有一块GPU,那NVSHMEM的单边通信就没什么意义了——数据都没地方传。我在项目中遇到过有人拿单卡跑测试,结果报错说找不到远端PE,其实就是GPU数量不够。
1.2 编译器选择:nvcc vs gcc
这是个经典问题。NVSHMEM的代码最终要跑在GPU上,所以CUDA编译器nvcc是必须的。但主机端的代码呢?
- nvcc:编译包含
__global__或__device__函数的源文件。它会把GPU代码编译成ptx或cubin,主机代码则交给gcc/g++处理。 - gcc/g++:编译纯主机端代码,比如main函数、数据结构定义等。NVSHMEM的API调用其实是在主机端发起的。
我个人习惯的做法是:所有源文件都用nvcc编译。为什么?因为省事。nvcc会自动识别哪些是GPU代码,哪些是主机代码,然后调用后端的gcc去处理主机部分。你不需要手动切来切去。
gcc -L/usr/local/cuda/lib64 -lcudart。但我还是建议你直接用nvcc,少给自己找麻烦。
1.3 安装NVSHMEM
NVSHMEM的安装方式有两种:从源码编译,或者用预编译包。我推荐后者,除非你有特殊需求。
方式一:预编译包(推荐)
# 下载NVSHMEM包
wget https://developer.download.nvidia.com/compute/nvshmem/2.8.0/nvshmem_2.8.0-1_amd64.deb
# 安装
sudo dpkg -i nvshmem_2.8.0-1_amd64.deb
# 或者用rpm
sudo rpm -ivh nvshmem_2.8.0-1.x86_64.rpm
装完之后,默认路径在/opt/nvshmem/。里面会有include、lib、examples等目录。
方式二:从源码编译
如果你需要定制化,比如修改通信后端,那就得自己编译了。
git clone https://github.com/NVIDIA/nvshmem.git
cd nvshmem
mkdir build && cd build
cmake .. \
-DCMAKE_INSTALL_PREFIX=/opt/nvshmem \
-DNVSHMEM_USE_GDRCOPY=ON \
-DCMAKE_CUDA_ARCHITECTURES="70;80"
make -j$(nproc)
sudo make install
这里有个坑:CMAKE_CUDA_ARCHITECTURES一定要填对。我见过有人写"70;80"但机器是T4(架构75),结果编译出来的库根本跑不了。嗯,检查一下你的GPU架构:nvidia-smi --query-gpu=name --format=csv,然后去NVIDIA官网查对应的算力。
NVSHMEM_USE_GDRCOPY设为OFF。否则编译会报错。
1.4 环境变量设置
装完库之后,环境变量得配好。不然编译器找不到头文件和库文件。
# 在~/.bashrc或~/.bash_profile中添加
export NVSHMEM_HOME=/opt/nvshmem
export CUDA_HOME=/usr/local/cuda
export PATH=$NVSHMEM_HOME/bin:$CUDA_HOME/bin:$PATH
export LD_LIBRARY_PATH=$NVSHMEM_HOME/lib:$CUDA_HOME/lib64:$LD_LIBRARY_PATH
export CPATH=$NVSHMEM_HOME/include:$CPATH
然后执行source ~/.bashrc让它生效。
我个人习惯再加一个变量:
export NVSHMEM_MPI_SUPPORT=1
这个变量告诉NVSHMEM使用MPI作为进程启动器。如果你用SLURM或者别的调度器,可能需要调整。我在项目中遇到过因为没设这个变量,导致多进程通信失败的情况——其实就是NVSHMEM不知道该怎么拉起多个PE。
1.5 验证安装是否成功
环境配好了,怎么知道能不能用?跑个简单的测试。
NVSHMEM自带了一些示例程序,在$NVSHMEM_HOME/examples目录下。咱们用最简单的hello_world来验证。
cd $NVSHMEM_HOME/examples
make hello_world
# 用mpirun启动,4个进程
mpirun -np 4 ./hello_world
如果看到类似下面的输出,说明安装成功了:
Hello from PE 0
Hello from PE 1
Hello from PE 2
Hello from PE 3
你也可以自己写一个极简的测试程序:
#include <stdio.h>
#include <nvshmem.h>
int main(void) {
nvshmem_init();
int my_pe = nvshmem_my_pe();
int n_pes = nvshmem_n_pes();
printf("PE %d of %d is alive\n", my_pe, n_pes);
nvshmem_finalize();
return 0;
}
编译命令:
nvcc -o test_nvshmem test_nvshmem.cu -lnvshmem
mpirun -np 4 ./test_nvshmem
- 所有PE都能打印信息,说明初始化成功
- PE编号从0到N-1连续,说明进程分配正常
- 没有segmentation fault或CUDA error,说明库链接正确
我曾经遇到过一次,程序能编译通过,但一运行就报CUDA driver version is insufficient。查了半天,发现是CUDA Toolkit版本和驱动版本不匹配。记住:驱动版本 >= 运行时版本,这是铁律。
1.6 知识体系总览
下面这张图,把环境搭建的核心逻辑串起来了。你照着这个流程走,基本不会出大问题。
这张图从左到右、从上到下,就是完整的搭建路径。你不需要记住所有细节,但流程要清楚:硬件→CUDA→NVSHMEM→环境变量→编译器→验证。每一步都踩实了,后面写代码才不慌。
好了,环境搭建就聊到这儿。记住:配环境这件事,慢就是快。花半小时把环境搞利索,比后面花两天找bug强得多。