1. 环境搭建与验证

任务目标

本案例完成RDMA与GPU通信开发的最小环境搭建,并验证两点:网卡支持RDMA(InfiniBand或RoCE)且GPU可被系统识别。验证通过后,后续案例可直接在此环境上运行。

环境需求

  • 操作系统:Linux(内核≥3.10,推荐Ubuntu 20.04+ / CentOS 7.6+)
  • 硬件:支持RDMA的网卡(Mellanox ConnectX系列、Broadcom RoCE网卡等)+ NVIDIA GPU
  • 驱动:NVIDIA驱动(≥450.80.02)、MLNX_OFED驱动(Mellanox网卡必需)或系统自带rdma-core(RoCE网卡)
  • 软件包:ibverbs-utils、rdma-core、cuda-toolkit、pciutils

环境检查与配置

以下命令在终端逐条执行,确认输出符合预期。

# 1. 检查GPU是否被系统识别
lspci | grep -i nvidia
# 预期输出:包含 NVIDIA 设备行,如 "NVIDIA Corporation GA102 [GeForce RTX 3080]"

# 2. 检查NVIDIA驱动是否加载
nvidia-smi
# 预期输出:显示GPU名称、驱动版本、显存等信息

# 3. 检查RDMA网卡是否存在
ibv_devinfo
# 预期输出:显示端口状态为 PORT_ACTIVE,链路层为 InfiniBand 或 Ethernet(RoCE)

# 4. 检查内核是否加载RDMA模块
lsmod | grep rdma
# 预期输出:包含 rdma_cm、ib_core、mlx5_core(Mellanox)等模块

# 5. 确认CUDA可用(若需GPU计算)
nvcc --version
# 预期输出:显示CUDA版本号

最小验证代码

以下C程序同时查询RDMA设备与GPU设备,验证两者在当前环境中均可用。编译运行后,输出设备名称与状态。

// rdma_gpu_check.c
#include <stdio.h>
#include <infiniband/verbs.h>
#include <cuda_runtime.h>

int main() {
    // ---- RDMA 设备检查 ----
    struct ibv_device **dev_list;
    int num_devices, i;

    dev_list = ibv_get_device_list(&num_devices, NULL);
    if (!dev_list || num_devices == 0) {
        printf("[FAIL] 未找到RDMA设备,请检查网卡驱动与固件。\n");
        return 1;
    }

    printf("[OK] 发现 %d 个RDMA设备:\n", num_devices);
    for (i = 0; i < num_devices; i++) {
        struct ibv_context *ctx = ibv_open_device(dev_list[i]);
        if (!ctx) {
            printf("  - %s (打开失败)\n", ibv_get_device_name(dev_list[i]));
            continue;
        }
        struct ibv_port_attr port_attr;
        if (ibv_query_port(ctx, 1, &port_attr) == 0) {
            const char *link = (port_attr.link_layer == IBV_LINK_LAYER_INFINIBAND) ?
                               "InfiniBand" : "RoCE/Ethernet";
            printf("  - %s | 端口状态: %s | 链路层: %s\n",
                   ibv_get_device_name(dev_list[i]),
                   (port_attr.state == IBV_PORT_ACTIVE) ? "ACTIVE" : "DOWN",
                   link);
        }
        ibv_close_device(ctx);
    }
    ibv_free_device_list(dev_list);

    // ---- GPU 设备检查 ----
    int gpu_count = 0;
    cudaError_t err = cudaGetDeviceCount(&gpu_count);
    if (err != cudaSuccess || gpu_count == 0) {
        printf("[FAIL] CUDA运行时无法访问GPU: %s\n", cudaGetErrorString(err));
        return 1;
    }

    printf("[OK] 发现 %d 个GPU设备:\n", gpu_count);
    for (i = 0; i < gpu_count; i++) {
        cudaDeviceProp prop;
        cudaGetDeviceProperties(&prop, i);
        printf("  - %s | 显存: %.1f GB | SM版本: %d.%d\n",
               prop.name, prop.totalGlobalMem / (1024.0*1024*1024),
               prop.major, prop.minor);
    }

    printf("\n环境验证通过:RDMA与GPU均可用。\n");
    return 0;
}

编译与运行

# 编译(需安装libibverbs-dev与cuda-toolkit)
gcc rdma_gpu_check.c -o rdma_gpu_check -libverbs -lcudart -L/usr/local/cuda/lib64

# 运行
./rdma_gpu_check

验证判定标准

  • 程序退出码为0,且输出包含[OK]行
  • RDMA设备端口状态为ACTIVE,链路层为InfiniBand或RoCE/Ethernet
  • GPU设备列表非空,且显示正确的设备名称与显存大小
  • 若任一检查输出[FAIL],按提示检查对应驱动或硬件连接

常见问题

  • ibv_devinfo 无输出:确认网卡驱动已安装(Mellanox网卡需MLNX_OFED),或尝试modprobe mlx5_core加载模块
  • nvidia-smi 报错:NVIDIA驱动未安装或与内核版本不匹配,重新安装驱动
  • 编译时找不到libibverbs:安装libibverbs-dev(Ubuntu)或rdma-core-devel(CentOS)
  • cudaGetDeviceCount返回0:确认CUDA toolkit与驱动版本兼容,运行nvcc --version检查